Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f454cf1 authored by Alex Deucher's avatar Alex Deucher
Browse files

drm/radeon: allow PPLL sharing on non-DP displays



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: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 9dbbcfc6
Loading
Loading
Loading
Loading
+65 −6
Original line number Diff line number Diff line
@@ -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)