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

Commit 09b4ddf9 authored by Paulo Zanoni's avatar Paulo Zanoni Committed by Daniel Vetter
Browse files

drm/i915: add haswell_crtc_mode_set



It's just a copy of ironlake_crtc_mode_set.

Signed-off-by: default avatarPaulo Zanoni <paulo.r.zanoni@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent fc914639
Loading
Loading
Loading
Loading
+186 −1
Original line number Diff line number Diff line
@@ -5142,6 +5142,185 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
	return ret;
}

static int haswell_crtc_mode_set(struct drm_crtc *crtc,
				 struct drm_display_mode *mode,
				 struct drm_display_mode *adjusted_mode,
				 int x, int y,
				 struct drm_framebuffer *fb)
{
	struct drm_device *dev = crtc->dev;
	struct drm_i915_private *dev_priv = dev->dev_private;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
	int pipe = intel_crtc->pipe;
	int plane = intel_crtc->plane;
	int num_connectors = 0;
	intel_clock_t clock, reduced_clock;
	u32 dpll, fp = 0, fp2 = 0;
	bool ok, has_reduced_clock = false;
	bool is_lvds = false, is_dp = false, is_cpu_edp = false;
	struct intel_encoder *encoder;
	u32 temp;
	int ret;
	bool dither;

	for_each_encoder_on_crtc(dev, crtc, encoder) {
		switch (encoder->type) {
		case INTEL_OUTPUT_LVDS:
			is_lvds = true;
			break;
		case INTEL_OUTPUT_DISPLAYPORT:
			is_dp = true;
			break;
		case INTEL_OUTPUT_EDP:
			is_dp = true;
			if (!intel_encoder_is_pch_edp(&encoder->base))
				is_cpu_edp = true;
			break;
		}

		num_connectors++;
	}

	ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock,
				     &has_reduced_clock, &reduced_clock);
	if (!ok) {
		DRM_ERROR("Couldn't find PLL settings for mode!\n");
		return -EINVAL;
	}

	/* Ensure that the cursor is valid for the new mode before changing... */
	intel_crtc_update_cursor(crtc, true);

	/* determine panel color depth */
	dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, mode);
	if (is_lvds && dev_priv->lvds_dither)
		dither = true;

	fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
	if (has_reduced_clock)
		fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
			reduced_clock.m2;

	dpll = ironlake_compute_dpll(intel_crtc, adjusted_mode, &clock, fp);

	DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
	drm_mode_debug_printmodeline(mode);

	/* CPU eDP is the only output that doesn't need a PCH PLL of its own on
	 * pre-Haswell/LPT generation */
	if (HAS_PCH_LPT(dev)) {
		DRM_DEBUG_KMS("LPT detected: no PLL for pipe %d necessary\n",
				pipe);
	} else if (!is_cpu_edp) {
		struct intel_pch_pll *pll;

		pll = intel_get_pch_pll(intel_crtc, dpll, fp);
		if (pll == NULL) {
			DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n",
					 pipe);
			return -EINVAL;
		}
	} else
		intel_put_pch_pll(intel_crtc);

	/* The LVDS pin pair needs to be on before the DPLLs are enabled.
	 * This is an exception to the general rule that mode_set doesn't turn
	 * things on.
	 */
	if (is_lvds) {
		temp = I915_READ(PCH_LVDS);
		temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
		if (HAS_PCH_CPT(dev)) {
			temp &= ~PORT_TRANS_SEL_MASK;
			temp |= PORT_TRANS_SEL_CPT(pipe);
		} else {
			if (pipe == 1)
				temp |= LVDS_PIPEB_SELECT;
			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
		 * set the DPLLs for dual-channel mode or not.
		 */
		if (clock.p2 == 7)
			temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
		else
			temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);

		/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
		 * appropriately here, but we need to look more thoroughly into how
		 * panels behave in the two modes.
		 */
		temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
		if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
			temp |= LVDS_HSYNC_POLARITY;
		if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
			temp |= LVDS_VSYNC_POLARITY;
		I915_WRITE(PCH_LVDS, temp);
	}

	if (is_dp && !is_cpu_edp) {
		intel_dp_set_m_n(crtc, mode, adjusted_mode);
	} else {
		/* For non-DP output, clear any trans DP clock recovery setting.*/
		I915_WRITE(TRANSDATA_M1(pipe), 0);
		I915_WRITE(TRANSDATA_N1(pipe), 0);
		I915_WRITE(TRANSDPLINK_M1(pipe), 0);
		I915_WRITE(TRANSDPLINK_N1(pipe), 0);
	}

	if (intel_crtc->pch_pll) {
		I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll);

		/* Wait for the clocks to stabilize. */
		POSTING_READ(intel_crtc->pch_pll->pll_reg);
		udelay(150);

		/* The pixel multiplier can only be updated once the
		 * DPLL is enabled and the clocks are stable.
		 *
		 * So write it again.
		 */
		I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll);
	}

	intel_crtc->lowfreq_avail = false;
	if (intel_crtc->pch_pll) {
		if (is_lvds && has_reduced_clock && i915_powersave) {
			I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2);
			intel_crtc->lowfreq_avail = true;
		} else {
			I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp);
		}
	}

	intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);

	ironlake_set_m_n(crtc, mode, adjusted_mode);

	if (is_cpu_edp)
		ironlake_set_pll_edp(crtc, adjusted_mode->clock);

	ironlake_set_pipeconf(crtc, adjusted_mode, dither);

	intel_wait_for_vblank(dev, pipe);

	/* Set up the display plane register */
	I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE);
	POSTING_READ(DSPCNTR(plane));

	ret = intel_pipe_set_base(crtc, x, y, fb);

	intel_update_watermarks(dev);

	intel_update_linetime_watermarks(dev, pipe, adjusted_mode);

	return ret;
}

static int intel_crtc_mode_set(struct drm_crtc *crtc,
			       struct drm_display_mode *mode,
			       struct drm_display_mode *adjusted_mode,
@@ -7852,7 +8031,13 @@ static void intel_init_display(struct drm_device *dev)
	struct drm_i915_private *dev_priv = dev->dev_private;

	/* We always want a DPMS function */
	if (HAS_PCH_SPLIT(dev)) {
	if (IS_HASWELL(dev)) {
		dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
		dev_priv->display.crtc_enable = ironlake_crtc_enable;
		dev_priv->display.crtc_disable = ironlake_crtc_disable;
		dev_priv->display.off = ironlake_crtc_off;
		dev_priv->display.update_plane = ironlake_update_plane;
	} else if (HAS_PCH_SPLIT(dev)) {
		dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
		dev_priv->display.crtc_enable = ironlake_crtc_enable;
		dev_priv->display.crtc_disable = ironlake_crtc_disable;