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

Commit 4b645f14 authored by Jesse Barnes's avatar Jesse Barnes Committed by Keith Packard
Browse files

drm/i915: add PLL sharing support to handle 3 pipes



Add two new fields to the intel_crtc struct for 3 pipe support: no_pll
and use_pll_a.  The no_pll field is only set on the 3rd pipe to indicate
that it doesn't have a PLL of its own and so shouldn't try to write the
main PLL regs.  The use_pll_a field controls which PLL pipe 3 will
share, A or B.  The core code will try to share PLLs with whichever pipe
has the same timings, rejecting the mode set if none is found.  This
means that pipe 3 must always be set after one of the other pipes has
been configured with real PLL settings.

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Tested-By: default avatarEugeni Dodonov <eugeni.dodonov@intel.com>
Reviewed-By: default avatarEugeni Dodonov <eugeni.dodonov@intel.com>
Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
parent d3ccbe86
Loading
Loading
Loading
Loading
+60 −38
Original line number Diff line number Diff line
@@ -2893,7 +2893,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	int pipe = intel_crtc->pipe;
	u32 reg, temp;
	u32 reg, temp, transc_sel;

	/* For PCH output, training FDI link */
	dev_priv->display.fdi_link_train(crtc);
@@ -2901,6 +2901,9 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
	intel_enable_pch_pll(dev_priv, pipe);

	if (HAS_PCH_CPT(dev)) {
		transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL :
			TRANSC_DPLLB_SEL;

		/* Be sure PCH DPLL SEL is set */
		temp = I915_READ(PCH_DPLL_SEL);
		if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
@@ -2908,7 +2911,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
		else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
			temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
		else if (pipe == 2 && (temp & TRANSC_DPLL_ENABLE) == 0)
			temp |= (TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL);
			temp |= (TRANSC_DPLL_ENABLE | transc_sel);
		I915_WRITE(PCH_DPLL_SEL, temp);
	}

@@ -3080,8 +3083,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
			temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
			break;
		case 2:
			/* FIXME: manage transcoder PLLs? */
			temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL);
			/* C shares PLL A or B */
			temp &= ~(TRANSC_DPLL_ENABLE | TRANSB_DPLLB_SEL);
			break;
		default:
			BUG(); /* wtf */
@@ -3090,6 +3093,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
	}

	/* disable PCH DPLL */
	if (!intel_crtc->no_pll)
		intel_disable_pch_pll(dev_priv, pipe);

	/* Switch from PCDclk to Rawclk */
@@ -5549,16 +5553,34 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
	drm_mode_debug_printmodeline(mode);

	/* PCH eDP needs FDI, but CPU eDP does not */
	if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
	if (!intel_crtc->no_pll) {
		if (!has_edp_encoder ||
		    intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
			I915_WRITE(PCH_FP0(pipe), fp);
			I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);

			POSTING_READ(PCH_DPLL(pipe));
			udelay(150);
		}
	} else {
		if (dpll == (I915_READ(PCH_DPLL(0)) & 0x7fffffff) &&
		    fp == I915_READ(PCH_FP0(0))) {
			intel_crtc->use_pll_a = true;
			DRM_DEBUG_KMS("using pipe a dpll\n");
		} else if (dpll == (I915_READ(PCH_DPLL(1)) & 0x7fffffff) &&
			   fp == I915_READ(PCH_FP0(1))) {
			intel_crtc->use_pll_a = false;
			DRM_DEBUG_KMS("using pipe b dpll\n");
		} else {
			DRM_DEBUG_KMS("no matching PLL configuration for pipe 2\n");
			return -EINVAL;
		}
	}

	/* enable transcoder DPLL */
	if (HAS_PCH_CPT(dev)) {
		u32 transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL :
			TRANSC_DPLLB_SEL;
		temp = I915_READ(PCH_DPLL_SEL);
		switch (pipe) {
		case 0:
@@ -5568,8 +5590,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
			temp |=	TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
			break;
		case 2:
			/* FIXME: manage transcoder PLLs? */
			temp |= TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL;
			temp |= TRANSC_DPLL_ENABLE | transc_sel;
			break;
		default:
			BUG();
@@ -5587,17 +5608,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
	if (is_lvds) {
		temp = I915_READ(PCH_LVDS);
		temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
		if (pipe == 1) {
		if (HAS_PCH_CPT(dev))
				temp |= PORT_TRANS_B_SEL_CPT;
			else
			temp |= PORT_TRANS_SEL_CPT(pipe);
		else if (pipe == 1)
			temp |= LVDS_PIPEB_SELECT;
		} else {
			if (HAS_PCH_CPT(dev))
				temp &= ~PORT_TRANS_SEL_MASK;
		else
			temp &= ~LVDS_PIPEB_SELECT;
		}

		/* set the corresponsding LVDS_BORDER bit */
		temp |= dev_priv->lvds_border_bits;
		/* Set the B0-B3 data pairs corresponding to whether we're going to
@@ -5647,8 +5664,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
		I915_WRITE(TRANSDPLINK_N1(pipe), 0);
	}

	if (!has_edp_encoder ||
	    intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
	if (!intel_crtc->no_pll &&
	    (!has_edp_encoder ||
	     intel_encoder_is_pch_edp(&has_edp_encoder->base))) {
		I915_WRITE(PCH_DPLL(pipe), dpll);

		/* Wait for the clocks to stabilize. */
@@ -5664,6 +5682,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
	}

	intel_crtc->lowfreq_avail = false;
	if (!intel_crtc->no_pll) {
		if (is_lvds && has_reduced_clock && i915_powersave) {
			I915_WRITE(PCH_FP1(pipe), fp2);
			intel_crtc->lowfreq_avail = true;
@@ -5678,6 +5697,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
				pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
			}
		}
	}

	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
		pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
@@ -7291,6 +7311,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
	intel_crtc->bpp = 24; /* default for pre-Ironlake */

	if (HAS_PCH_SPLIT(dev)) {
		if (pipe == 2 && IS_IVYBRIDGE(dev))
			intel_crtc->no_pll = true;
		intel_helper_funcs.prepare = ironlake_crtc_prepare;
		intel_helper_funcs.commit = ironlake_crtc_commit;
	} else {
+3 −0
Original line number Diff line number Diff line
@@ -171,6 +171,9 @@ struct intel_crtc {
	int16_t cursor_width, cursor_height;
	bool cursor_visible;
	unsigned int bpp;

	bool no_pll; /* tertiary pipe for IVB */
	bool use_pll_a;
};

#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)