diff mbox

drm/radeon: rework pll selection (v2)

Message ID 1346457632-2186-1-git-send-email-alexdeucher@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Alex Deucher Sept. 1, 2012, midnight UTC
From: Alex Deucher <alexander.deucher@amd.com>

For DP we can use the same PPLL for all active DP
encoders.  Take advantage of that to prevent cases
where we may end up sharing a PPLL between DP and
non-DP which won't work.  Also clean up the code
a bit.

v2: fix missing pll_id assignment in crtc init

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
---
 drivers/gpu/drm/radeon/atombios_crtc.c |  102 +++++++++++++++++++++----------
 1 files changed, 69 insertions(+), 33 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 2817101..3b42ea2 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1479,6 +1479,24 @@  static void radeon_legacy_atom_fixup(struct drm_crtc *crtc)
 	}
 }
 
+static u32 radeon_get_pll_use_mask(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_crtc *test_crtc;
+	struct radeon_crtc *radeon_test_crtc;
+	u32 pll_in_use = 0;
+
+	list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+		if (crtc == test_crtc)
+			continue;
+
+		radeon_test_crtc = to_radeon_crtc(test_crtc);
+		if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)
+			pll_in_use |= (1 << radeon_test_crtc->pll_id);
+	}
+	return pll_in_use;
+}
+
 static int radeon_atom_pick_pll(struct drm_crtc *crtc)
 {
 	struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -1486,7 +1504,7 @@  static int radeon_atom_pick_pll(struct drm_crtc *crtc)
 	struct radeon_device *rdev = dev->dev_private;
 	struct drm_encoder *test_encoder;
 	struct drm_crtc *test_crtc;
-	uint32_t pll_in_use = 0;
+	u32 pll_in_use;
 
 	if (ASIC_IS_DCE61(rdev)) {
 		list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
@@ -1498,32 +1516,45 @@  static int radeon_atom_pick_pll(struct drm_crtc *crtc)
 
 				if ((test_radeon_encoder->encoder_id ==
 				     ENCODER_OBJECT_ID_INTERNAL_UNIPHY) &&
-				    (dig->linkb == false)) /* UNIPHY A uses PPLL2 */
+				    (dig->linkb == false))
+					/* UNIPHY A uses PPLL2 */
 					return ATOM_PPLL2;
+				else if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
+					/* UNIPHY B/C/D/E/F */
+					if (rdev->clock.dp_extclk)
+						return ATOM_PPLL_INVALID;
+					else {
+						list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+							struct radeon_crtc *radeon_test_crtc;
+
+							if (crtc == test_crtc)
+								continue;
+
+							/* for DP use the same PLL for all */
+							radeon_test_crtc = to_radeon_crtc(test_crtc);
+							if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)
+								return radeon_test_crtc->pll_id;
+						}
+					}
+				}
 			}
 		}
 		/* UNIPHY B/C/D/E/F */
-		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
-			struct radeon_crtc *radeon_test_crtc;
-
-			if (crtc == test_crtc)
-				continue;
-
-			radeon_test_crtc = to_radeon_crtc(test_crtc);
-			if ((radeon_test_crtc->pll_id == ATOM_PPLL0) ||
-			    (radeon_test_crtc->pll_id == ATOM_PPLL1))
-				pll_in_use |= (1 << radeon_test_crtc->pll_id);
-		}
-		if (!(pll_in_use & 4))
+		pll_in_use = radeon_get_pll_use_mask(crtc);
+		if (!(pll_in_use & (1 << ATOM_PPLL0)))
 			return ATOM_PPLL0;
-		return ATOM_PPLL1;
+		if (!(pll_in_use & (1 << ATOM_PPLL1)))
+			return ATOM_PPLL1;
+		DRM_ERROR("unable to allocate a PPLL\n");
+		return ATOM_PPLL_INVALID;
 	} else if (ASIC_IS_DCE4(rdev)) {
 		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 PPLL, DCPLL, or ext clock,
 				 * depending on the asic:
 				 * DCE4: PPLL or ext clock
-				 * DCE5: DCPLL or ext clock
+				 * DCE5: PPLL, DCPLL, or ext clock
+				 * DCE6: PPLL, PPLL0, or ext clock
 				 *
 				 * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip
 				 * PPLL/DCPLL programming and only program the DP DTO for the
@@ -1536,25 +1567,30 @@  static int radeon_atom_pick_pll(struct drm_crtc *crtc)
 						return ATOM_PPLL0;
 					else if (ASIC_IS_DCE5(rdev))
 						return ATOM_DCPLL;
+					else {
+						list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
+							struct radeon_crtc *radeon_test_crtc;
+
+							if (crtc == test_crtc)
+								continue;
+
+							/* for DP use the same PLL for all */
+							radeon_test_crtc = to_radeon_crtc(test_crtc);
+							if (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID)
+								return radeon_test_crtc->pll_id;
+						}
+					}
 				}
 			}
 		}
-
-		/* otherwise, pick one of the plls */
-		list_for_each_entry(test_crtc, &dev->mode_config.crtc_list, head) {
-			struct radeon_crtc *radeon_test_crtc;
-
-			if (crtc == test_crtc)
-				continue;
-
-			radeon_test_crtc = to_radeon_crtc(test_crtc);
-			if ((radeon_test_crtc->pll_id >= ATOM_PPLL1) &&
-			    (radeon_test_crtc->pll_id <= ATOM_PPLL2))
-				pll_in_use |= (1 << radeon_test_crtc->pll_id);
-		}
-		if (!(pll_in_use & 1))
+		/* non DP */
+		pll_in_use = radeon_get_pll_use_mask(crtc);
+		if (!(pll_in_use & (1 << ATOM_PPLL2)))
+			return ATOM_PPLL2;
+		if (!(pll_in_use & (1 << ATOM_PPLL1)))
 			return ATOM_PPLL1;
-		return ATOM_PPLL2;
+		DRM_ERROR("unable to allocate a PPLL\n");
+		return ATOM_PPLL_INVALID;
 	} else
 		return radeon_crtc->crtc_id;
 
@@ -1697,7 +1733,7 @@  static void atombios_crtc_disable(struct drm_crtc *crtc)
 		break;
 	}
 done:
-	radeon_crtc->pll_id = -1;
+	radeon_crtc->pll_id = ATOM_PPLL_INVALID;
 }
 
 static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
@@ -1746,6 +1782,6 @@  void radeon_atombios_init_crtc(struct drm_device *dev,
 		else
 			radeon_crtc->crtc_offset = 0;
 	}
-	radeon_crtc->pll_id = -1;
+	radeon_crtc->pll_id = ATOM_PPLL_INVALID;
 	drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
 }