All of lore.kernel.org
 help / color / mirror / Atom feed
* [Intel-gfx] [rfc] start slimming down intel_display.c
@ 2020-12-09  4:21 Dave Airlie
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 1/4] drm/i915: refactor cursor code out of i915_display.c Dave Airlie
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Dave Airlie @ 2020-12-09  4:21 UTC (permalink / raw)
  To: intel-gfx

Recent events led me to notice a 20k loc file that seems excessive.

If a new driver came along and asked to merge this monster I'd say no,
so why has the in tree code gotten this bad. Standards are clearly
not being kept once code is merged, which doesn't bode well for the
future.

Anyways, as an effort to kick start some cleaning, I've refactored
a few thousand lines of code out of this into separate files, I've
been pretty arbitary and I'm sure there are many nicers ways to slice
this, but this is my effort.

Dave.


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Intel-gfx] [PATCH 1/4] drm/i915: refactor cursor code out of i915_display.c
  2020-12-09  4:21 [Intel-gfx] [rfc] start slimming down intel_display.c Dave Airlie
@ 2020-12-09  4:21 ` Dave Airlie
  2020-12-09 11:07   ` Daniel Vetter
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 2/4] drm/i915: refactor some crtc code out of intel display Dave Airlie
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Dave Airlie @ 2020-12-09  4:21 UTC (permalink / raw)
  To: intel-gfx

From: Dave Airlie <airlied@redhat.com>

This file is a monster, let's start simple, the cursor plane code
seems pretty standalone, and splits out easily enough.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/i915/Makefile                |   1 +
 drivers/gpu/drm/i915/display/intel_cursor.c  | 817 +++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_display.c | 796 +-----------------
 drivers/gpu/drm/i915/display/intel_display.h |  12 +
 4 files changed, 836 insertions(+), 790 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/display/intel_cursor.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index e5574e506a5c..98a35b939052 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -197,6 +197,7 @@ i915-y += \
 	display/intel_combo_phy.o \
 	display/intel_connector.o \
 	display/intel_csr.o \
+	display/intel_cursor.o \
 	display/intel_display.o \
 	display/intel_display_power.o \
 	display/intel_dpio_phy.o \
diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
new file mode 100644
index 000000000000..d69eac067255
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -0,0 +1,817 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+#include <linux/kernel.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_damage_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_fourcc.h>
+
+#include "intel_atomic.h"
+#include "intel_atomic_plane.h"
+#include "intel_display_types.h"
+#include "intel_display.h"
+
+#include "intel_frontbuffer.h"
+#include "intel_pm.h"
+#include "intel_psr.h"
+#include "intel_sprite.h"
+
+/* Cursor formats */
+static const u32 intel_cursor_formats[] = {
+	DRM_FORMAT_ARGB8888,
+};
+
+static const u64 cursor_format_modifiers[] = {
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+static bool
+needs_modeset(const struct intel_crtc_state *state)
+{
+	return drm_atomic_crtc_needs_modeset(&state->uapi);
+}
+
+static struct intel_frontbuffer *
+to_intel_frontbuffer(struct drm_framebuffer *fb)
+{
+	return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL;
+}
+
+static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
+{
+	struct drm_i915_private *dev_priv =
+		to_i915(plane_state->uapi.plane->dev);
+	const struct drm_framebuffer *fb = plane_state->hw.fb;
+	const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+	u32 base;
+
+	if (INTEL_INFO(dev_priv)->display.cursor_needs_physical)
+		base = sg_dma_address(obj->mm.pages->sgl);
+	else
+		base = intel_plane_ggtt_offset(plane_state);
+
+	return base + plane_state->color_plane[0].offset;
+}
+
+static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
+{
+	int x = plane_state->uapi.dst.x1;
+	int y = plane_state->uapi.dst.y1;
+	u32 pos = 0;
+
+	if (x < 0) {
+		pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
+		x = -x;
+	}
+	pos |= x << CURSOR_X_SHIFT;
+
+	if (y < 0) {
+		pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
+		y = -y;
+	}
+	pos |= y << CURSOR_Y_SHIFT;
+
+	return pos;
+}
+
+static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
+{
+	const struct drm_mode_config *config =
+		&plane_state->uapi.plane->dev->mode_config;
+	int width = drm_rect_width(&plane_state->uapi.dst);
+	int height = drm_rect_height(&plane_state->uapi.dst);
+
+	return width > 0 && width <= config->cursor_width &&
+		height > 0 && height <= config->cursor_height;
+}
+
+static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
+{
+	struct drm_i915_private *dev_priv =
+		to_i915(plane_state->uapi.plane->dev);
+	unsigned int rotation = plane_state->hw.rotation;
+	int src_x, src_y;
+	u32 offset;
+	int ret;
+
+	ret = intel_plane_compute_gtt(plane_state);
+	if (ret)
+		return ret;
+
+	if (!plane_state->uapi.visible)
+		return 0;
+
+	src_x = plane_state->uapi.src.x1 >> 16;
+	src_y = plane_state->uapi.src.y1 >> 16;
+
+	intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
+	offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
+						    plane_state, 0);
+
+	if (src_x != 0 || src_y != 0) {
+		drm_dbg_kms(&dev_priv->drm,
+			    "Arbitrary cursor panning not supported\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Put the final coordinates back so that the src
+	 * coordinate checks will see the right values.
+	 */
+	drm_rect_translate_to(&plane_state->uapi.src,
+			      src_x << 16, src_y << 16);
+
+	/* ILK+ do this automagically in hardware */
+	if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) {
+		const struct drm_framebuffer *fb = plane_state->hw.fb;
+		int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
+		int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
+
+		offset += (src_h * src_w - 1) * fb->format->cpp[0];
+	}
+
+	plane_state->color_plane[0].offset = offset;
+	plane_state->color_plane[0].x = src_x;
+	plane_state->color_plane[0].y = src_y;
+
+	return 0;
+}
+
+static int intel_check_cursor(struct intel_crtc_state *crtc_state,
+			      struct intel_plane_state *plane_state)
+{
+	const struct drm_framebuffer *fb = plane_state->hw.fb;
+	struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
+	const struct drm_rect src = plane_state->uapi.src;
+	const struct drm_rect dst = plane_state->uapi.dst;
+	int ret;
+
+	if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
+		drm_dbg_kms(&i915->drm, "cursor cannot be tiled\n");
+		return -EINVAL;
+	}
+
+	ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+						DRM_PLANE_HELPER_NO_SCALING,
+						DRM_PLANE_HELPER_NO_SCALING,
+						true);
+	if (ret)
+		return ret;
+
+	/* Use the unclipped src/dst rectangles, which we program to hw */
+	plane_state->uapi.src = src;
+	plane_state->uapi.dst = dst;
+
+	ret = intel_cursor_check_surface(plane_state);
+	if (ret)
+		return ret;
+
+	if (!plane_state->uapi.visible)
+		return 0;
+
+	ret = intel_plane_check_src_coordinates(plane_state);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static unsigned int
+i845_cursor_max_stride(struct intel_plane *plane,
+		       u32 pixel_format, u64 modifier,
+		       unsigned int rotation)
+{
+	return 2048;
+}
+
+static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
+{
+	u32 cntl = 0;
+
+	if (crtc_state->gamma_enable)
+		cntl |= CURSOR_GAMMA_ENABLE;
+
+	return cntl;
+}
+
+static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
+			   const struct intel_plane_state *plane_state)
+{
+	return CURSOR_ENABLE |
+		CURSOR_FORMAT_ARGB |
+		CURSOR_STRIDE(plane_state->color_plane[0].stride);
+}
+
+static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
+{
+	int width = drm_rect_width(&plane_state->uapi.dst);
+
+	/*
+	 * 845g/865g are only limited by the width of their cursors,
+	 * the height is arbitrary up to the precision of the register.
+	 */
+	return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64);
+}
+
+static int i845_check_cursor(struct intel_crtc_state *crtc_state,
+			     struct intel_plane_state *plane_state)
+{
+	const struct drm_framebuffer *fb = plane_state->hw.fb;
+	struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
+	int ret;
+
+	ret = intel_check_cursor(crtc_state, plane_state);
+	if (ret)
+		return ret;
+
+	/* if we want to turn off the cursor ignore width and height */
+	if (!fb)
+		return 0;
+
+	/* Check for which cursor types we support */
+	if (!i845_cursor_size_ok(plane_state)) {
+		drm_dbg_kms(&i915->drm,
+			    "Cursor dimension %dx%d not supported\n",
+			    drm_rect_width(&plane_state->uapi.dst),
+			    drm_rect_height(&plane_state->uapi.dst));
+		return -EINVAL;
+	}
+
+	drm_WARN_ON(&i915->drm, plane_state->uapi.visible &&
+		    plane_state->color_plane[0].stride != fb->pitches[0]);
+
+	switch (fb->pitches[0]) {
+	case 256:
+	case 512:
+	case 1024:
+	case 2048:
+		break;
+	default:
+		 drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n",
+			     fb->pitches[0]);
+		return -EINVAL;
+	}
+
+	plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
+
+	return 0;
+}
+
+static void i845_update_cursor(struct intel_plane *plane,
+			       const struct intel_crtc_state *crtc_state,
+			       const struct intel_plane_state *plane_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	u32 cntl = 0, base = 0, pos = 0, size = 0;
+	unsigned long irqflags;
+
+	if (plane_state && plane_state->uapi.visible) {
+		unsigned int width = drm_rect_width(&plane_state->uapi.dst);
+		unsigned int height = drm_rect_height(&plane_state->uapi.dst);
+
+		cntl = plane_state->ctl |
+			i845_cursor_ctl_crtc(crtc_state);
+
+		size = (height << 12) | width;
+
+		base = intel_cursor_base(plane_state);
+		pos = intel_cursor_position(plane_state);
+	}
+
+	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+	/* On these chipsets we can only modify the base/size/stride
+	 * whilst the cursor is disabled.
+	 */
+	if (plane->cursor.base != base ||
+	    plane->cursor.size != size ||
+	    plane->cursor.cntl != cntl) {
+		intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), 0);
+		intel_de_write_fw(dev_priv, CURBASE(PIPE_A), base);
+		intel_de_write_fw(dev_priv, CURSIZE, size);
+		intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
+		intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), cntl);
+
+		plane->cursor.base = base;
+		plane->cursor.size = size;
+		plane->cursor.cntl = cntl;
+	} else {
+		intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
+	}
+
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void i845_disable_cursor(struct intel_plane *plane,
+				const struct intel_crtc_state *crtc_state)
+{
+	i845_update_cursor(plane, crtc_state, NULL);
+}
+
+static bool i845_cursor_get_hw_state(struct intel_plane *plane,
+				     enum pipe *pipe)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
+	bool ret;
+
+	power_domain = POWER_DOMAIN_PIPE(PIPE_A);
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
+		return false;
+
+	ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE;
+
+	*pipe = PIPE_A;
+
+	intel_display_power_put(dev_priv, power_domain, wakeref);
+
+	return ret;
+}
+
+static unsigned int
+i9xx_cursor_max_stride(struct intel_plane *plane,
+		       u32 pixel_format, u64 modifier,
+		       unsigned int rotation)
+{
+	return plane->base.dev->mode_config.cursor_width * 4;
+}
+
+static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	u32 cntl = 0;
+
+	if (INTEL_GEN(dev_priv) >= 11)
+		return cntl;
+
+	if (crtc_state->gamma_enable)
+		cntl = MCURSOR_GAMMA_ENABLE;
+
+	if (crtc_state->csc_enable)
+		cntl |= MCURSOR_PIPE_CSC_ENABLE;
+
+	if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
+		cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
+
+	return cntl;
+}
+
+static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
+			   const struct intel_plane_state *plane_state)
+{
+	struct drm_i915_private *dev_priv =
+		to_i915(plane_state->uapi.plane->dev);
+	u32 cntl = 0;
+
+	if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
+		cntl |= MCURSOR_TRICKLE_FEED_DISABLE;
+
+	switch (drm_rect_width(&plane_state->uapi.dst)) {
+	case 64:
+		cntl |= MCURSOR_MODE_64_ARGB_AX;
+		break;
+	case 128:
+		cntl |= MCURSOR_MODE_128_ARGB_AX;
+		break;
+	case 256:
+		cntl |= MCURSOR_MODE_256_ARGB_AX;
+		break;
+	default:
+		MISSING_CASE(drm_rect_width(&plane_state->uapi.dst));
+		return 0;
+	}
+
+	if (plane_state->hw.rotation & DRM_MODE_ROTATE_180)
+		cntl |= MCURSOR_ROTATE_180;
+
+	return cntl;
+}
+
+static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
+{
+	struct drm_i915_private *dev_priv =
+		to_i915(plane_state->uapi.plane->dev);
+	int width = drm_rect_width(&plane_state->uapi.dst);
+	int height = drm_rect_height(&plane_state->uapi.dst);
+
+	if (!intel_cursor_size_ok(plane_state))
+		return false;
+
+	/* Cursor width is limited to a few power-of-two sizes */
+	switch (width) {
+	case 256:
+	case 128:
+	case 64:
+		break;
+	default:
+		return false;
+	}
+
+	/*
+	 * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor
+	 * height from 8 lines up to the cursor width, when the
+	 * cursor is not rotated. Everything else requires square
+	 * cursors.
+	 */
+	if (HAS_CUR_FBC(dev_priv) &&
+	    plane_state->hw.rotation & DRM_MODE_ROTATE_0) {
+		if (height < 8 || height > width)
+			return false;
+	} else {
+		if (height != width)
+			return false;
+	}
+
+	return true;
+}
+
+static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
+			     struct intel_plane_state *plane_state)
+{
+	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	const struct drm_framebuffer *fb = plane_state->hw.fb;
+	enum pipe pipe = plane->pipe;
+	int ret;
+
+	ret = intel_check_cursor(crtc_state, plane_state);
+	if (ret)
+		return ret;
+
+	/* if we want to turn off the cursor ignore width and height */
+	if (!fb)
+		return 0;
+
+	/* Check for which cursor types we support */
+	if (!i9xx_cursor_size_ok(plane_state)) {
+		drm_dbg(&dev_priv->drm,
+			"Cursor dimension %dx%d not supported\n",
+			drm_rect_width(&plane_state->uapi.dst),
+			drm_rect_height(&plane_state->uapi.dst));
+		return -EINVAL;
+	}
+
+	drm_WARN_ON(&dev_priv->drm, plane_state->uapi.visible &&
+		    plane_state->color_plane[0].stride != fb->pitches[0]);
+
+	if (fb->pitches[0] !=
+	    drm_rect_width(&plane_state->uapi.dst) * fb->format->cpp[0]) {
+		drm_dbg_kms(&dev_priv->drm,
+			    "Invalid cursor stride (%u) (cursor width %d)\n",
+			    fb->pitches[0],
+			    drm_rect_width(&plane_state->uapi.dst));
+		return -EINVAL;
+	}
+
+	/*
+	 * There's something wrong with the cursor on CHV pipe C.
+	 * If it straddles the left edge of the screen then
+	 * moving it away from the edge or disabling it often
+	 * results in a pipe underrun, and often that can lead to
+	 * dead pipe (constant underrun reported, and it scans
+	 * out just a solid color). To recover from that, the
+	 * display power well must be turned off and on again.
+	 * Refuse the put the cursor into that compromised position.
+	 */
+	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
+	    plane_state->uapi.visible && plane_state->uapi.dst.x1 < 0) {
+		drm_dbg_kms(&dev_priv->drm,
+			    "CHV cursor C not allowed to straddle the left screen edge\n");
+		return -EINVAL;
+	}
+
+	plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
+
+	return 0;
+}
+
+static void i9xx_update_cursor(struct intel_plane *plane,
+			       const struct intel_crtc_state *crtc_state,
+			       const struct intel_plane_state *plane_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	enum pipe pipe = plane->pipe;
+	u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
+	unsigned long irqflags;
+
+	if (plane_state && plane_state->uapi.visible) {
+		unsigned width = drm_rect_width(&plane_state->uapi.dst);
+		unsigned height = drm_rect_height(&plane_state->uapi.dst);
+
+		cntl = plane_state->ctl |
+			i9xx_cursor_ctl_crtc(crtc_state);
+
+		if (width != height)
+			fbc_ctl = CUR_FBC_CTL_EN | (height - 1);
+
+		base = intel_cursor_base(plane_state);
+		pos = intel_cursor_position(plane_state);
+	}
+
+	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+	/*
+	 * On some platforms writing CURCNTR first will also
+	 * cause CURPOS to be armed by the CURBASE write.
+	 * Without the CURCNTR write the CURPOS write would
+	 * arm itself. Thus we always update CURCNTR before
+	 * CURPOS.
+	 *
+	 * On other platforms CURPOS always requires the
+	 * CURBASE write to arm the update. Additonally
+	 * a write to any of the cursor register will cancel
+	 * an already armed cursor update. Thus leaving out
+	 * the CURBASE write after CURPOS could lead to a
+	 * cursor that doesn't appear to move, or even change
+	 * shape. Thus we always write CURBASE.
+	 *
+	 * The other registers are armed by by the CURBASE write
+	 * except when the plane is getting enabled at which time
+	 * the CURCNTR write arms the update.
+	 */
+
+	if (INTEL_GEN(dev_priv) >= 9)
+		skl_write_cursor_wm(plane, crtc_state);
+
+	if (!needs_modeset(crtc_state))
+		intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0);
+
+	if (plane->cursor.base != base ||
+	    plane->cursor.size != fbc_ctl ||
+	    plane->cursor.cntl != cntl) {
+		if (HAS_CUR_FBC(dev_priv))
+			intel_de_write_fw(dev_priv, CUR_FBC_CTL(pipe),
+					  fbc_ctl);
+		intel_de_write_fw(dev_priv, CURCNTR(pipe), cntl);
+		intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
+		intel_de_write_fw(dev_priv, CURBASE(pipe), base);
+
+		plane->cursor.base = base;
+		plane->cursor.size = fbc_ctl;
+		plane->cursor.cntl = cntl;
+	} else {
+		intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
+		intel_de_write_fw(dev_priv, CURBASE(pipe), base);
+	}
+
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void i9xx_disable_cursor(struct intel_plane *plane,
+				const struct intel_crtc_state *crtc_state)
+{
+	i9xx_update_cursor(plane, crtc_state, NULL);
+}
+
+static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
+				     enum pipe *pipe)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	enum intel_display_power_domain power_domain;
+	intel_wakeref_t wakeref;
+	bool ret;
+	u32 val;
+
+	/*
+	 * Not 100% correct for planes that can move between pipes,
+	 * but that's only the case for gen2-3 which don't have any
+	 * display power wells.
+	 */
+	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
+		return false;
+
+	val = intel_de_read(dev_priv, CURCNTR(plane->pipe));
+
+	ret = val & MCURSOR_MODE;
+
+	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+		*pipe = plane->pipe;
+	else
+		*pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
+			MCURSOR_PIPE_SELECT_SHIFT;
+
+	intel_display_power_put(dev_priv, power_domain, wakeref);
+
+	return ret;
+}
+
+static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
+					      u32 format, u64 modifier)
+{
+	return modifier == DRM_FORMAT_MOD_LINEAR &&
+		format == DRM_FORMAT_ARGB8888;
+}
+
+static int
+intel_legacy_cursor_update(struct drm_plane *_plane,
+			   struct drm_crtc *_crtc,
+			   struct drm_framebuffer *fb,
+			   int crtc_x, int crtc_y,
+			   unsigned int crtc_w, unsigned int crtc_h,
+			   u32 src_x, u32 src_y,
+			   u32 src_w, u32 src_h,
+			   struct drm_modeset_acquire_ctx *ctx)
+{
+	struct intel_plane *plane = to_intel_plane(_plane);
+	struct intel_crtc *crtc = to_intel_crtc(_crtc);
+	struct intel_plane_state *old_plane_state =
+		to_intel_plane_state(plane->base.state);
+	struct intel_plane_state *new_plane_state;
+	struct intel_crtc_state *crtc_state =
+		to_intel_crtc_state(crtc->base.state);
+	struct intel_crtc_state *new_crtc_state;
+	int ret;
+
+	/*
+	 * When crtc is inactive or there is a modeset pending,
+	 * wait for it to complete in the slowpath
+	 *
+	 * FIXME bigjoiner fastpath would be good
+	 */
+	if (!crtc_state->hw.active || needs_modeset(crtc_state) ||
+	    crtc_state->update_pipe || crtc_state->bigjoiner)
+		goto slow;
+
+	/*
+	 * Don't do an async update if there is an outstanding commit modifying
+	 * the plane.  This prevents our async update's changes from getting
+	 * overridden by a previous synchronous update's state.
+	 */
+	if (old_plane_state->uapi.commit &&
+	    !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done))
+		goto slow;
+
+	/*
+	 * If any parameters change that may affect watermarks,
+	 * take the slowpath. Only changing fb or position should be
+	 * in the fastpath.
+	 */
+	if (old_plane_state->uapi.crtc != &crtc->base ||
+	    old_plane_state->uapi.src_w != src_w ||
+	    old_plane_state->uapi.src_h != src_h ||
+	    old_plane_state->uapi.crtc_w != crtc_w ||
+	    old_plane_state->uapi.crtc_h != crtc_h ||
+	    !old_plane_state->uapi.fb != !fb)
+		goto slow;
+
+	new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base));
+	if (!new_plane_state)
+		return -ENOMEM;
+
+	new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base));
+	if (!new_crtc_state) {
+		ret = -ENOMEM;
+		goto out_free;
+	}
+
+	drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb);
+
+	new_plane_state->uapi.src_x = src_x;
+	new_plane_state->uapi.src_y = src_y;
+	new_plane_state->uapi.src_w = src_w;
+	new_plane_state->uapi.src_h = src_h;
+	new_plane_state->uapi.crtc_x = crtc_x;
+	new_plane_state->uapi.crtc_y = crtc_y;
+	new_plane_state->uapi.crtc_w = crtc_w;
+	new_plane_state->uapi.crtc_h = crtc_h;
+
+	intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc);
+
+	ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
+						  old_plane_state, new_plane_state);
+	if (ret)
+		goto out_free;
+
+	ret = intel_plane_pin_fb(new_plane_state);
+	if (ret)
+		goto out_free;
+
+	intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb),
+				ORIGIN_FLIP);
+	intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb),
+				to_intel_frontbuffer(new_plane_state->hw.fb),
+				plane->frontbuffer_bit);
+
+	/* Swap plane state */
+	plane->base.state = &new_plane_state->uapi;
+
+	/*
+	 * We cannot swap crtc_state as it may be in use by an atomic commit or
+	 * page flip that's running simultaneously. If we swap crtc_state and
+	 * destroy the old state, we will cause a use-after-free there.
+	 *
+	 * Only update active_planes, which is needed for our internal
+	 * bookkeeping. Either value will do the right thing when updating
+	 * planes atomically. If the cursor was part of the atomic update then
+	 * we would have taken the slowpath.
+	 */
+	crtc_state->active_planes = new_crtc_state->active_planes;
+
+	if (new_plane_state->uapi.visible)
+		intel_update_plane(plane, crtc_state, new_plane_state);
+	else
+		intel_disable_plane(plane, crtc_state);
+
+	intel_plane_unpin_fb(old_plane_state);
+
+out_free:
+	if (new_crtc_state)
+		intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi);
+	if (ret)
+		intel_plane_destroy_state(&plane->base, &new_plane_state->uapi);
+	else
+		intel_plane_destroy_state(&plane->base, &old_plane_state->uapi);
+	return ret;
+
+slow:
+	return drm_atomic_helper_update_plane(&plane->base, &crtc->base, fb,
+					      crtc_x, crtc_y, crtc_w, crtc_h,
+					      src_x, src_y, src_w, src_h, ctx);
+}
+
+static const struct drm_plane_funcs intel_cursor_plane_funcs = {
+	.update_plane = intel_legacy_cursor_update,
+	.disable_plane = drm_atomic_helper_disable_plane,
+	.destroy = intel_plane_destroy,
+	.atomic_duplicate_state = intel_plane_duplicate_state,
+	.atomic_destroy_state = intel_plane_destroy_state,
+	.format_mod_supported = intel_cursor_format_mod_supported,
+};
+
+struct intel_plane *
+intel_cursor_plane_create(struct drm_i915_private *dev_priv,
+			  enum pipe pipe)
+{
+	struct intel_plane *cursor;
+	int ret, zpos;
+
+	cursor = intel_plane_alloc();
+	if (IS_ERR(cursor))
+		return cursor;
+
+	cursor->pipe = pipe;
+	cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
+	cursor->id = PLANE_CURSOR;
+	cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
+
+	if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
+		cursor->max_stride = i845_cursor_max_stride;
+		cursor->update_plane = i845_update_cursor;
+		cursor->disable_plane = i845_disable_cursor;
+		cursor->get_hw_state = i845_cursor_get_hw_state;
+		cursor->check_plane = i845_check_cursor;
+	} else {
+		cursor->max_stride = i9xx_cursor_max_stride;
+		cursor->update_plane = i9xx_update_cursor;
+		cursor->disable_plane = i9xx_disable_cursor;
+		cursor->get_hw_state = i9xx_cursor_get_hw_state;
+		cursor->check_plane = i9xx_check_cursor;
+	}
+
+	cursor->cursor.base = ~0;
+	cursor->cursor.cntl = ~0;
+
+	if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
+		cursor->cursor.size = ~0;
+
+	ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
+				       0, &intel_cursor_plane_funcs,
+				       intel_cursor_formats,
+				       ARRAY_SIZE(intel_cursor_formats),
+				       cursor_format_modifiers,
+				       DRM_PLANE_TYPE_CURSOR,
+				       "cursor %c", pipe_name(pipe));
+	if (ret)
+		goto fail;
+
+	if (INTEL_GEN(dev_priv) >= 4)
+		drm_plane_create_rotation_property(&cursor->base,
+						   DRM_MODE_ROTATE_0,
+						   DRM_MODE_ROTATE_0 |
+						   DRM_MODE_ROTATE_180);
+
+	zpos = RUNTIME_INFO(dev_priv)->num_sprites[pipe] + 1;
+	drm_plane_create_zpos_immutable_property(&cursor->base, zpos);
+
+	if (INTEL_GEN(dev_priv) >= 12)
+		drm_plane_enable_fb_damage_clips(&cursor->base);
+
+	drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
+
+	return cursor;
+
+fail:
+	intel_plane_free(cursor);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index c567c0cada7e..0a3b97889248 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -137,16 +137,6 @@ static const u64 i9xx_format_modifiers[] = {
 	DRM_FORMAT_MOD_INVALID
 };
 
-/* Cursor formats */
-static const u32 intel_cursor_formats[] = {
-	DRM_FORMAT_ARGB8888,
-};
-
-static const u64 cursor_format_modifiers[] = {
-	DRM_FORMAT_MOD_LINEAR,
-	DRM_FORMAT_MOD_INVALID
-};
-
 static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
 				struct intel_crtc_state *pipe_config);
 static void ilk_pch_clock_get(struct intel_crtc *crtc,
@@ -2533,9 +2523,9 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
 	return offset_aligned;
 }
 
-static u32 intel_plane_compute_aligned_offset(int *x, int *y,
-					      const struct intel_plane_state *state,
-					      int color_plane)
+u32 intel_plane_compute_aligned_offset(int *x, int *y,
+				       const struct intel_plane_state *state,
+				       int color_plane)
 {
 	struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane);
 	struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
@@ -3272,7 +3262,7 @@ intel_plane_remap_gtt(struct intel_plane_state *plane_state)
 	}
 }
 
-static int
+int
 intel_plane_compute_gtt(struct intel_plane_state *plane_state)
 {
 	const struct intel_framebuffer *fb =
@@ -11547,569 +11537,6 @@ static bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state)
 	return true;
 }
 
-static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
-{
-	struct drm_i915_private *dev_priv =
-		to_i915(plane_state->uapi.plane->dev);
-	const struct drm_framebuffer *fb = plane_state->hw.fb;
-	const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-	u32 base;
-
-	if (INTEL_INFO(dev_priv)->display.cursor_needs_physical)
-		base = sg_dma_address(obj->mm.pages->sgl);
-	else
-		base = intel_plane_ggtt_offset(plane_state);
-
-	return base + plane_state->color_plane[0].offset;
-}
-
-static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
-{
-	int x = plane_state->uapi.dst.x1;
-	int y = plane_state->uapi.dst.y1;
-	u32 pos = 0;
-
-	if (x < 0) {
-		pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
-		x = -x;
-	}
-	pos |= x << CURSOR_X_SHIFT;
-
-	if (y < 0) {
-		pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
-		y = -y;
-	}
-	pos |= y << CURSOR_Y_SHIFT;
-
-	return pos;
-}
-
-static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
-{
-	const struct drm_mode_config *config =
-		&plane_state->uapi.plane->dev->mode_config;
-	int width = drm_rect_width(&plane_state->uapi.dst);
-	int height = drm_rect_height(&plane_state->uapi.dst);
-
-	return width > 0 && width <= config->cursor_width &&
-		height > 0 && height <= config->cursor_height;
-}
-
-static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
-{
-	struct drm_i915_private *dev_priv =
-		to_i915(plane_state->uapi.plane->dev);
-	unsigned int rotation = plane_state->hw.rotation;
-	int src_x, src_y;
-	u32 offset;
-	int ret;
-
-	ret = intel_plane_compute_gtt(plane_state);
-	if (ret)
-		return ret;
-
-	if (!plane_state->uapi.visible)
-		return 0;
-
-	src_x = plane_state->uapi.src.x1 >> 16;
-	src_y = plane_state->uapi.src.y1 >> 16;
-
-	intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
-	offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
-						    plane_state, 0);
-
-	if (src_x != 0 || src_y != 0) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "Arbitrary cursor panning not supported\n");
-		return -EINVAL;
-	}
-
-	/*
-	 * Put the final coordinates back so that the src
-	 * coordinate checks will see the right values.
-	 */
-	drm_rect_translate_to(&plane_state->uapi.src,
-			      src_x << 16, src_y << 16);
-
-	/* ILK+ do this automagically in hardware */
-	if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) {
-		const struct drm_framebuffer *fb = plane_state->hw.fb;
-		int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
-		int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
-
-		offset += (src_h * src_w - 1) * fb->format->cpp[0];
-	}
-
-	plane_state->color_plane[0].offset = offset;
-	plane_state->color_plane[0].x = src_x;
-	plane_state->color_plane[0].y = src_y;
-
-	return 0;
-}
-
-static int intel_check_cursor(struct intel_crtc_state *crtc_state,
-			      struct intel_plane_state *plane_state)
-{
-	const struct drm_framebuffer *fb = plane_state->hw.fb;
-	struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
-	const struct drm_rect src = plane_state->uapi.src;
-	const struct drm_rect dst = plane_state->uapi.dst;
-	int ret;
-
-	if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
-		drm_dbg_kms(&i915->drm, "cursor cannot be tiled\n");
-		return -EINVAL;
-	}
-
-	ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
-						DRM_PLANE_HELPER_NO_SCALING,
-						DRM_PLANE_HELPER_NO_SCALING,
-						true);
-	if (ret)
-		return ret;
-
-	/* Use the unclipped src/dst rectangles, which we program to hw */
-	plane_state->uapi.src = src;
-	plane_state->uapi.dst = dst;
-
-	ret = intel_cursor_check_surface(plane_state);
-	if (ret)
-		return ret;
-
-	if (!plane_state->uapi.visible)
-		return 0;
-
-	ret = intel_plane_check_src_coordinates(plane_state);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static unsigned int
-i845_cursor_max_stride(struct intel_plane *plane,
-		       u32 pixel_format, u64 modifier,
-		       unsigned int rotation)
-{
-	return 2048;
-}
-
-static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
-{
-	u32 cntl = 0;
-
-	if (crtc_state->gamma_enable)
-		cntl |= CURSOR_GAMMA_ENABLE;
-
-	return cntl;
-}
-
-static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
-			   const struct intel_plane_state *plane_state)
-{
-	return CURSOR_ENABLE |
-		CURSOR_FORMAT_ARGB |
-		CURSOR_STRIDE(plane_state->color_plane[0].stride);
-}
-
-static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
-{
-	int width = drm_rect_width(&plane_state->uapi.dst);
-
-	/*
-	 * 845g/865g are only limited by the width of their cursors,
-	 * the height is arbitrary up to the precision of the register.
-	 */
-	return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64);
-}
-
-static int i845_check_cursor(struct intel_crtc_state *crtc_state,
-			     struct intel_plane_state *plane_state)
-{
-	const struct drm_framebuffer *fb = plane_state->hw.fb;
-	struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
-	int ret;
-
-	ret = intel_check_cursor(crtc_state, plane_state);
-	if (ret)
-		return ret;
-
-	/* if we want to turn off the cursor ignore width and height */
-	if (!fb)
-		return 0;
-
-	/* Check for which cursor types we support */
-	if (!i845_cursor_size_ok(plane_state)) {
-		drm_dbg_kms(&i915->drm,
-			    "Cursor dimension %dx%d not supported\n",
-			    drm_rect_width(&plane_state->uapi.dst),
-			    drm_rect_height(&plane_state->uapi.dst));
-		return -EINVAL;
-	}
-
-	drm_WARN_ON(&i915->drm, plane_state->uapi.visible &&
-		    plane_state->color_plane[0].stride != fb->pitches[0]);
-
-	switch (fb->pitches[0]) {
-	case 256:
-	case 512:
-	case 1024:
-	case 2048:
-		break;
-	default:
-		 drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n",
-			     fb->pitches[0]);
-		return -EINVAL;
-	}
-
-	plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
-
-	return 0;
-}
-
-static void i845_update_cursor(struct intel_plane *plane,
-			       const struct intel_crtc_state *crtc_state,
-			       const struct intel_plane_state *plane_state)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	u32 cntl = 0, base = 0, pos = 0, size = 0;
-	unsigned long irqflags;
-
-	if (plane_state && plane_state->uapi.visible) {
-		unsigned int width = drm_rect_width(&plane_state->uapi.dst);
-		unsigned int height = drm_rect_height(&plane_state->uapi.dst);
-
-		cntl = plane_state->ctl |
-			i845_cursor_ctl_crtc(crtc_state);
-
-		size = (height << 12) | width;
-
-		base = intel_cursor_base(plane_state);
-		pos = intel_cursor_position(plane_state);
-	}
-
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
-	/* On these chipsets we can only modify the base/size/stride
-	 * whilst the cursor is disabled.
-	 */
-	if (plane->cursor.base != base ||
-	    plane->cursor.size != size ||
-	    plane->cursor.cntl != cntl) {
-		intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), 0);
-		intel_de_write_fw(dev_priv, CURBASE(PIPE_A), base);
-		intel_de_write_fw(dev_priv, CURSIZE, size);
-		intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
-		intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), cntl);
-
-		plane->cursor.base = base;
-		plane->cursor.size = size;
-		plane->cursor.cntl = cntl;
-	} else {
-		intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
-	}
-
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void i845_disable_cursor(struct intel_plane *plane,
-				const struct intel_crtc_state *crtc_state)
-{
-	i845_update_cursor(plane, crtc_state, NULL);
-}
-
-static bool i845_cursor_get_hw_state(struct intel_plane *plane,
-				     enum pipe *pipe)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	enum intel_display_power_domain power_domain;
-	intel_wakeref_t wakeref;
-	bool ret;
-
-	power_domain = POWER_DOMAIN_PIPE(PIPE_A);
-	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
-	if (!wakeref)
-		return false;
-
-	ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE;
-
-	*pipe = PIPE_A;
-
-	intel_display_power_put(dev_priv, power_domain, wakeref);
-
-	return ret;
-}
-
-static unsigned int
-i9xx_cursor_max_stride(struct intel_plane *plane,
-		       u32 pixel_format, u64 modifier,
-		       unsigned int rotation)
-{
-	return plane->base.dev->mode_config.cursor_width * 4;
-}
-
-static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
-{
-	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	u32 cntl = 0;
-
-	if (INTEL_GEN(dev_priv) >= 11)
-		return cntl;
-
-	if (crtc_state->gamma_enable)
-		cntl = MCURSOR_GAMMA_ENABLE;
-
-	if (crtc_state->csc_enable)
-		cntl |= MCURSOR_PIPE_CSC_ENABLE;
-
-	if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
-		cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
-
-	return cntl;
-}
-
-static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
-			   const struct intel_plane_state *plane_state)
-{
-	struct drm_i915_private *dev_priv =
-		to_i915(plane_state->uapi.plane->dev);
-	u32 cntl = 0;
-
-	if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
-		cntl |= MCURSOR_TRICKLE_FEED_DISABLE;
-
-	switch (drm_rect_width(&plane_state->uapi.dst)) {
-	case 64:
-		cntl |= MCURSOR_MODE_64_ARGB_AX;
-		break;
-	case 128:
-		cntl |= MCURSOR_MODE_128_ARGB_AX;
-		break;
-	case 256:
-		cntl |= MCURSOR_MODE_256_ARGB_AX;
-		break;
-	default:
-		MISSING_CASE(drm_rect_width(&plane_state->uapi.dst));
-		return 0;
-	}
-
-	if (plane_state->hw.rotation & DRM_MODE_ROTATE_180)
-		cntl |= MCURSOR_ROTATE_180;
-
-	return cntl;
-}
-
-static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
-{
-	struct drm_i915_private *dev_priv =
-		to_i915(plane_state->uapi.plane->dev);
-	int width = drm_rect_width(&plane_state->uapi.dst);
-	int height = drm_rect_height(&plane_state->uapi.dst);
-
-	if (!intel_cursor_size_ok(plane_state))
-		return false;
-
-	/* Cursor width is limited to a few power-of-two sizes */
-	switch (width) {
-	case 256:
-	case 128:
-	case 64:
-		break;
-	default:
-		return false;
-	}
-
-	/*
-	 * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor
-	 * height from 8 lines up to the cursor width, when the
-	 * cursor is not rotated. Everything else requires square
-	 * cursors.
-	 */
-	if (HAS_CUR_FBC(dev_priv) &&
-	    plane_state->hw.rotation & DRM_MODE_ROTATE_0) {
-		if (height < 8 || height > width)
-			return false;
-	} else {
-		if (height != width)
-			return false;
-	}
-
-	return true;
-}
-
-static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
-			     struct intel_plane_state *plane_state)
-{
-	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	const struct drm_framebuffer *fb = plane_state->hw.fb;
-	enum pipe pipe = plane->pipe;
-	int ret;
-
-	ret = intel_check_cursor(crtc_state, plane_state);
-	if (ret)
-		return ret;
-
-	/* if we want to turn off the cursor ignore width and height */
-	if (!fb)
-		return 0;
-
-	/* Check for which cursor types we support */
-	if (!i9xx_cursor_size_ok(plane_state)) {
-		drm_dbg(&dev_priv->drm,
-			"Cursor dimension %dx%d not supported\n",
-			drm_rect_width(&plane_state->uapi.dst),
-			drm_rect_height(&plane_state->uapi.dst));
-		return -EINVAL;
-	}
-
-	drm_WARN_ON(&dev_priv->drm, plane_state->uapi.visible &&
-		    plane_state->color_plane[0].stride != fb->pitches[0]);
-
-	if (fb->pitches[0] !=
-	    drm_rect_width(&plane_state->uapi.dst) * fb->format->cpp[0]) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "Invalid cursor stride (%u) (cursor width %d)\n",
-			    fb->pitches[0],
-			    drm_rect_width(&plane_state->uapi.dst));
-		return -EINVAL;
-	}
-
-	/*
-	 * There's something wrong with the cursor on CHV pipe C.
-	 * If it straddles the left edge of the screen then
-	 * moving it away from the edge or disabling it often
-	 * results in a pipe underrun, and often that can lead to
-	 * dead pipe (constant underrun reported, and it scans
-	 * out just a solid color). To recover from that, the
-	 * display power well must be turned off and on again.
-	 * Refuse the put the cursor into that compromised position.
-	 */
-	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
-	    plane_state->uapi.visible && plane_state->uapi.dst.x1 < 0) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "CHV cursor C not allowed to straddle the left screen edge\n");
-		return -EINVAL;
-	}
-
-	plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
-
-	return 0;
-}
-
-static void i9xx_update_cursor(struct intel_plane *plane,
-			       const struct intel_crtc_state *crtc_state,
-			       const struct intel_plane_state *plane_state)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	enum pipe pipe = plane->pipe;
-	u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
-	unsigned long irqflags;
-
-	if (plane_state && plane_state->uapi.visible) {
-		unsigned width = drm_rect_width(&plane_state->uapi.dst);
-		unsigned height = drm_rect_height(&plane_state->uapi.dst);
-
-		cntl = plane_state->ctl |
-			i9xx_cursor_ctl_crtc(crtc_state);
-
-		if (width != height)
-			fbc_ctl = CUR_FBC_CTL_EN | (height - 1);
-
-		base = intel_cursor_base(plane_state);
-		pos = intel_cursor_position(plane_state);
-	}
-
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
-	/*
-	 * On some platforms writing CURCNTR first will also
-	 * cause CURPOS to be armed by the CURBASE write.
-	 * Without the CURCNTR write the CURPOS write would
-	 * arm itself. Thus we always update CURCNTR before
-	 * CURPOS.
-	 *
-	 * On other platforms CURPOS always requires the
-	 * CURBASE write to arm the update. Additonally
-	 * a write to any of the cursor register will cancel
-	 * an already armed cursor update. Thus leaving out
-	 * the CURBASE write after CURPOS could lead to a
-	 * cursor that doesn't appear to move, or even change
-	 * shape. Thus we always write CURBASE.
-	 *
-	 * The other registers are armed by by the CURBASE write
-	 * except when the plane is getting enabled at which time
-	 * the CURCNTR write arms the update.
-	 */
-
-	if (INTEL_GEN(dev_priv) >= 9)
-		skl_write_cursor_wm(plane, crtc_state);
-
-	if (!needs_modeset(crtc_state))
-		intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0);
-
-	if (plane->cursor.base != base ||
-	    plane->cursor.size != fbc_ctl ||
-	    plane->cursor.cntl != cntl) {
-		if (HAS_CUR_FBC(dev_priv))
-			intel_de_write_fw(dev_priv, CUR_FBC_CTL(pipe),
-					  fbc_ctl);
-		intel_de_write_fw(dev_priv, CURCNTR(pipe), cntl);
-		intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
-		intel_de_write_fw(dev_priv, CURBASE(pipe), base);
-
-		plane->cursor.base = base;
-		plane->cursor.size = fbc_ctl;
-		plane->cursor.cntl = cntl;
-	} else {
-		intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
-		intel_de_write_fw(dev_priv, CURBASE(pipe), base);
-	}
-
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void i9xx_disable_cursor(struct intel_plane *plane,
-				const struct intel_crtc_state *crtc_state)
-{
-	i9xx_update_cursor(plane, crtc_state, NULL);
-}
-
-static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
-				     enum pipe *pipe)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	enum intel_display_power_domain power_domain;
-	intel_wakeref_t wakeref;
-	bool ret;
-	u32 val;
-
-	/*
-	 * Not 100% correct for planes that can move between pipes,
-	 * but that's only the case for gen2-3 which don't have any
-	 * display power wells.
-	 */
-	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
-	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
-	if (!wakeref)
-		return false;
-
-	val = intel_de_read(dev_priv, CURCNTR(plane->pipe));
-
-	ret = val & MCURSOR_MODE;
-
-	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
-		*pipe = plane->pipe;
-	else
-		*pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
-			MCURSOR_PIPE_SELECT_SHIFT;
-
-	intel_display_power_put(dev_priv, power_domain, wakeref);
-
-	return ret;
-}
-
 /* VESA 640x480x72Hz mode to set on the pipe */
 static const struct drm_display_mode load_detect_mode = {
 	DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
@@ -16620,7 +16047,7 @@ static void add_rps_boost_after_vblank(struct drm_crtc *crtc,
 	add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait);
 }
 
-static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
+int intel_plane_pin_fb(struct intel_plane_state *plane_state)
 {
 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
@@ -16650,7 +16077,7 @@ static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
 	return 0;
 }
 
-static void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
+void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
 {
 	struct i915_vma *vma;
 
@@ -16886,13 +16313,6 @@ static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
 	}
 }
 
-static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
-					      u32 format, u64 modifier)
-{
-	return modifier == DRM_FORMAT_MOD_LINEAR &&
-		format == DRM_FORMAT_ARGB8888;
-}
-
 static const struct drm_plane_funcs i965_plane_funcs = {
 	.update_plane = drm_atomic_helper_update_plane,
 	.disable_plane = drm_atomic_helper_disable_plane,
@@ -16911,142 +16331,6 @@ static const struct drm_plane_funcs i8xx_plane_funcs = {
 	.format_mod_supported = i8xx_plane_format_mod_supported,
 };
 
-static int
-intel_legacy_cursor_update(struct drm_plane *_plane,
-			   struct drm_crtc *_crtc,
-			   struct drm_framebuffer *fb,
-			   int crtc_x, int crtc_y,
-			   unsigned int crtc_w, unsigned int crtc_h,
-			   u32 src_x, u32 src_y,
-			   u32 src_w, u32 src_h,
-			   struct drm_modeset_acquire_ctx *ctx)
-{
-	struct intel_plane *plane = to_intel_plane(_plane);
-	struct intel_crtc *crtc = to_intel_crtc(_crtc);
-	struct intel_plane_state *old_plane_state =
-		to_intel_plane_state(plane->base.state);
-	struct intel_plane_state *new_plane_state;
-	struct intel_crtc_state *crtc_state =
-		to_intel_crtc_state(crtc->base.state);
-	struct intel_crtc_state *new_crtc_state;
-	int ret;
-
-	/*
-	 * When crtc is inactive or there is a modeset pending,
-	 * wait for it to complete in the slowpath
-	 *
-	 * FIXME bigjoiner fastpath would be good
-	 */
-	if (!crtc_state->hw.active || needs_modeset(crtc_state) ||
-	    crtc_state->update_pipe || crtc_state->bigjoiner)
-		goto slow;
-
-	/*
-	 * Don't do an async update if there is an outstanding commit modifying
-	 * the plane.  This prevents our async update's changes from getting
-	 * overridden by a previous synchronous update's state.
-	 */
-	if (old_plane_state->uapi.commit &&
-	    !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done))
-		goto slow;
-
-	/*
-	 * If any parameters change that may affect watermarks,
-	 * take the slowpath. Only changing fb or position should be
-	 * in the fastpath.
-	 */
-	if (old_plane_state->uapi.crtc != &crtc->base ||
-	    old_plane_state->uapi.src_w != src_w ||
-	    old_plane_state->uapi.src_h != src_h ||
-	    old_plane_state->uapi.crtc_w != crtc_w ||
-	    old_plane_state->uapi.crtc_h != crtc_h ||
-	    !old_plane_state->uapi.fb != !fb)
-		goto slow;
-
-	new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base));
-	if (!new_plane_state)
-		return -ENOMEM;
-
-	new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base));
-	if (!new_crtc_state) {
-		ret = -ENOMEM;
-		goto out_free;
-	}
-
-	drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb);
-
-	new_plane_state->uapi.src_x = src_x;
-	new_plane_state->uapi.src_y = src_y;
-	new_plane_state->uapi.src_w = src_w;
-	new_plane_state->uapi.src_h = src_h;
-	new_plane_state->uapi.crtc_x = crtc_x;
-	new_plane_state->uapi.crtc_y = crtc_y;
-	new_plane_state->uapi.crtc_w = crtc_w;
-	new_plane_state->uapi.crtc_h = crtc_h;
-
-	intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc);
-
-	ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
-						  old_plane_state, new_plane_state);
-	if (ret)
-		goto out_free;
-
-	ret = intel_plane_pin_fb(new_plane_state);
-	if (ret)
-		goto out_free;
-
-	intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb),
-				ORIGIN_FLIP);
-	intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb),
-				to_intel_frontbuffer(new_plane_state->hw.fb),
-				plane->frontbuffer_bit);
-
-	/* Swap plane state */
-	plane->base.state = &new_plane_state->uapi;
-
-	/*
-	 * We cannot swap crtc_state as it may be in use by an atomic commit or
-	 * page flip that's running simultaneously. If we swap crtc_state and
-	 * destroy the old state, we will cause a use-after-free there.
-	 *
-	 * Only update active_planes, which is needed for our internal
-	 * bookkeeping. Either value will do the right thing when updating
-	 * planes atomically. If the cursor was part of the atomic update then
-	 * we would have taken the slowpath.
-	 */
-	crtc_state->active_planes = new_crtc_state->active_planes;
-
-	if (new_plane_state->uapi.visible)
-		intel_update_plane(plane, crtc_state, new_plane_state);
-	else
-		intel_disable_plane(plane, crtc_state);
-
-	intel_plane_unpin_fb(old_plane_state);
-
-out_free:
-	if (new_crtc_state)
-		intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi);
-	if (ret)
-		intel_plane_destroy_state(&plane->base, &new_plane_state->uapi);
-	else
-		intel_plane_destroy_state(&plane->base, &old_plane_state->uapi);
-	return ret;
-
-slow:
-	return drm_atomic_helper_update_plane(&plane->base, &crtc->base, fb,
-					      crtc_x, crtc_y, crtc_w, crtc_h,
-					      src_x, src_y, src_w, src_h, ctx);
-}
-
-static const struct drm_plane_funcs intel_cursor_plane_funcs = {
-	.update_plane = intel_legacy_cursor_update,
-	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
-	.atomic_duplicate_state = intel_plane_duplicate_state,
-	.atomic_destroy_state = intel_plane_destroy_state,
-	.format_mod_supported = intel_cursor_format_mod_supported,
-};
-
 static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
 			       enum i9xx_plane_id i9xx_plane)
 {
@@ -17198,74 +16482,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
 	return ERR_PTR(ret);
 }
 
-static struct intel_plane *
-intel_cursor_plane_create(struct drm_i915_private *dev_priv,
-			  enum pipe pipe)
-{
-	struct intel_plane *cursor;
-	int ret, zpos;
-
-	cursor = intel_plane_alloc();
-	if (IS_ERR(cursor))
-		return cursor;
-
-	cursor->pipe = pipe;
-	cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
-	cursor->id = PLANE_CURSOR;
-	cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
-
-	if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
-		cursor->max_stride = i845_cursor_max_stride;
-		cursor->update_plane = i845_update_cursor;
-		cursor->disable_plane = i845_disable_cursor;
-		cursor->get_hw_state = i845_cursor_get_hw_state;
-		cursor->check_plane = i845_check_cursor;
-	} else {
-		cursor->max_stride = i9xx_cursor_max_stride;
-		cursor->update_plane = i9xx_update_cursor;
-		cursor->disable_plane = i9xx_disable_cursor;
-		cursor->get_hw_state = i9xx_cursor_get_hw_state;
-		cursor->check_plane = i9xx_check_cursor;
-	}
-
-	cursor->cursor.base = ~0;
-	cursor->cursor.cntl = ~0;
-
-	if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
-		cursor->cursor.size = ~0;
-
-	ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
-				       0, &intel_cursor_plane_funcs,
-				       intel_cursor_formats,
-				       ARRAY_SIZE(intel_cursor_formats),
-				       cursor_format_modifiers,
-				       DRM_PLANE_TYPE_CURSOR,
-				       "cursor %c", pipe_name(pipe));
-	if (ret)
-		goto fail;
-
-	if (INTEL_GEN(dev_priv) >= 4)
-		drm_plane_create_rotation_property(&cursor->base,
-						   DRM_MODE_ROTATE_0,
-						   DRM_MODE_ROTATE_0 |
-						   DRM_MODE_ROTATE_180);
-
-	zpos = RUNTIME_INFO(dev_priv)->num_sprites[pipe] + 1;
-	drm_plane_create_zpos_immutable_property(&cursor->base, zpos);
-
-	if (INTEL_GEN(dev_priv) >= 12)
-		drm_plane_enable_fb_damage_clips(&cursor->base);
-
-	drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
-
-	return cursor;
-
-fail:
-	intel_plane_free(cursor);
-
-	return ERR_PTR(ret);
-}
-
 static int intel_crtc_late_register(struct drm_crtc *crtc)
 {
 	intel_crtc_debugfs_add(crtc);
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index a5771bfecba6..f0a5bf69656f 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -647,6 +647,18 @@ bool
 intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
 				    uint64_t modifier);
 
+int intel_plane_compute_gtt(struct intel_plane_state *plane_state);
+u32 intel_plane_compute_aligned_offset(int *x, int *y,
+				       const struct intel_plane_state *state,
+				       int color_plane);
+int intel_plane_pin_fb(struct intel_plane_state *plane_state);
+void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state);
+
+/* cursor */
+struct intel_plane *
+intel_cursor_plane_create(struct drm_i915_private *dev_priv,
+			  enum pipe pipe);
+
 /* modesetting */
 void intel_modeset_init_hw(struct drm_i915_private *i915);
 int intel_modeset_init_noirq(struct drm_i915_private *i915);
-- 
2.27.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Intel-gfx] [PATCH 2/4] drm/i915: refactor some crtc code out of intel display.
  2020-12-09  4:21 [Intel-gfx] [rfc] start slimming down intel_display.c Dave Airlie
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 1/4] drm/i915: refactor cursor code out of i915_display.c Dave Airlie
@ 2020-12-09  4:21 ` Dave Airlie
  2020-12-09 11:03   ` Daniel Vetter
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 3/4] drm/i915: refactor pll code out into intel_clock.c Dave Airlie
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Dave Airlie @ 2020-12-09  4:21 UTC (permalink / raw)
  To: intel-gfx

From: Dave Airlie <airlied@redhat.com>

There may be more crtc code that can be pulled out, but this
is a good start.

RFC: maybe call the new file something different

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/i915/Makefile                |   1 +
 drivers/gpu/drm/i915/display/intel_crtc.c    | 951 +++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_display.c | 932 ------------------
 drivers/gpu/drm/i915/display/intel_display.h |   7 +
 4 files changed, 959 insertions(+), 932 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/display/intel_crtc.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 98a35b939052..ffec257702af 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -196,6 +196,7 @@ i915-y += \
 	display/intel_color.o \
 	display/intel_combo_phy.o \
 	display/intel_connector.o \
+	display/intel_crtc.o \
 	display/intel_csr.o \
 	display/intel_cursor.o \
 	display/intel_display.o \
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
new file mode 100644
index 000000000000..75a79f18cee2
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -0,0 +1,951 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_plane.h>
+#include <drm/drm_plane_helper.h>
+
+#include "intel_atomic.h"
+#include "intel_atomic_plane.h"
+#include "intel_color.h"
+#include "intel_display_debugfs.h"
+#include "intel_display_types.h"
+#include "intel_pipe_crc.h"
+#include "intel_sprite.h"
+
+/* Primary plane formats for gen <= 3 */
+static const u32 i8xx_primary_formats[] = {
+	DRM_FORMAT_C8,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_XRGB8888,
+};
+
+/* Primary plane formats for ivb (no fp16 due to hw issue) */
+static const u32 ivb_primary_formats[] = {
+	DRM_FORMAT_C8,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB2101010,
+	DRM_FORMAT_XBGR2101010,
+};
+
+/* Primary plane formats for gen >= 4, except ivb */
+static const u32 i965_primary_formats[] = {
+	DRM_FORMAT_C8,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_XRGB2101010,
+	DRM_FORMAT_XBGR2101010,
+	DRM_FORMAT_XBGR16161616F,
+};
+
+/* Primary plane formats for vlv/chv */
+static const u32 vlv_primary_formats[] = {
+	DRM_FORMAT_C8,
+	DRM_FORMAT_RGB565,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_XRGB2101010,
+	DRM_FORMAT_XBGR2101010,
+	DRM_FORMAT_ARGB2101010,
+	DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_XBGR16161616F,
+};
+
+static const u64 i9xx_format_modifiers[] = {
+	I915_FORMAT_MOD_X_TILED,
+	DRM_FORMAT_MOD_LINEAR,
+	DRM_FORMAT_MOD_INVALID
+};
+
+static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane,
+					    u32 format, u64 modifier)
+{
+	switch (modifier) {
+	case DRM_FORMAT_MOD_LINEAR:
+	case I915_FORMAT_MOD_X_TILED:
+		break;
+	default:
+		return false;
+	}
+
+	switch (format) {
+	case DRM_FORMAT_C8:
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_XRGB1555:
+	case DRM_FORMAT_XRGB8888:
+		return modifier == DRM_FORMAT_MOD_LINEAR ||
+			modifier == I915_FORMAT_MOD_X_TILED;
+	default:
+		return false;
+	}
+}
+
+static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
+					    u32 format, u64 modifier)
+{
+	switch (modifier) {
+	case DRM_FORMAT_MOD_LINEAR:
+	case I915_FORMAT_MOD_X_TILED:
+		break;
+	default:
+		return false;
+	}
+
+	switch (format) {
+	case DRM_FORMAT_C8:
+	case DRM_FORMAT_RGB565:
+	case DRM_FORMAT_XRGB8888:
+	case DRM_FORMAT_XBGR8888:
+	case DRM_FORMAT_ARGB8888:
+	case DRM_FORMAT_ABGR8888:
+	case DRM_FORMAT_XRGB2101010:
+	case DRM_FORMAT_XBGR2101010:
+	case DRM_FORMAT_ARGB2101010:
+	case DRM_FORMAT_ABGR2101010:
+	case DRM_FORMAT_XBGR16161616F:
+		return modifier == DRM_FORMAT_MOD_LINEAR ||
+			modifier == I915_FORMAT_MOD_X_TILED;
+	default:
+		return false;
+	}
+}
+
+static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
+			       enum i9xx_plane_id i9xx_plane)
+{
+	if (!HAS_FBC(dev_priv))
+		return false;
+
+	if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+		return i9xx_plane == PLANE_A; /* tied to pipe A */
+	else if (IS_IVYBRIDGE(dev_priv))
+		return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B ||
+			i9xx_plane == PLANE_C;
+	else if (INTEL_GEN(dev_priv) >= 4)
+		return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B;
+	else
+		return i9xx_plane == PLANE_A;
+}
+
+static void assert_vblank_disabled(struct drm_crtc *crtc)
+{
+	if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
+		drm_crtc_vblank_put(crtc);
+}
+
+u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
+
+	if (!vblank->max_vblank_count)
+		return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
+
+	return crtc->base.funcs->get_vblank_counter(&crtc->base);
+}
+
+u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+	u32 mode_flags = crtc->mode_flags;
+
+	/*
+	 * From Gen 11, In case of dsi cmd mode, frame counter wouldnt
+	 * have updated at the beginning of TE, if we want to use
+	 * the hw counter, then we would find it updated in only
+	 * the next TE, hence switching to sw counter.
+	 */
+	if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1))
+		return 0;
+
+	/*
+	 * On i965gm the hardware frame counter reads
+	 * zero when the TV encoder is enabled :(
+	 */
+	if (IS_I965GM(dev_priv) &&
+	    (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
+		return 0;
+
+	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+		return 0xffffffff; /* full 32 bit counter */
+	else if (INTEL_GEN(dev_priv) >= 3)
+		return 0xffffff; /* only 24 bits of frame count */
+	else
+		return 0; /* Gen2 doesn't have a hardware frame counter */
+}
+
+void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+	assert_vblank_disabled(&crtc->base);
+	drm_crtc_set_max_vblank_count(&crtc->base,
+				      intel_crtc_max_vblank_count(crtc_state));
+	drm_crtc_vblank_on(&crtc->base);
+}
+
+void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+
+	drm_crtc_vblank_off(&crtc->base);
+	assert_vblank_disabled(&crtc->base);
+}
+
+struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc)
+{
+	struct intel_crtc_state *crtc_state;
+
+	crtc_state = kmalloc(sizeof(*crtc_state), GFP_KERNEL);
+
+	if (crtc_state)
+		intel_crtc_state_reset(crtc_state, crtc);
+
+	return crtc_state;
+}
+
+void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
+			    struct intel_crtc *crtc)
+{
+	memset(crtc_state, 0, sizeof(*crtc_state));
+
+	__drm_atomic_helper_crtc_state_reset(&crtc_state->uapi, &crtc->base);
+
+	crtc_state->cpu_transcoder = INVALID_TRANSCODER;
+	crtc_state->master_transcoder = INVALID_TRANSCODER;
+	crtc_state->hsw_workaround_pipe = INVALID_PIPE;
+	crtc_state->output_format = INTEL_OUTPUT_FORMAT_INVALID;
+	crtc_state->scaler_state.scaler_id = -1;
+	crtc_state->mst_master_transcoder = INVALID_TRANSCODER;
+}
+
+static bool i9xx_plane_has_windowing(struct intel_plane *plane)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+
+	if (IS_CHERRYVIEW(dev_priv))
+		return i9xx_plane == PLANE_B;
+	else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+		return false;
+	else if (IS_GEN(dev_priv, 4))
+		return i9xx_plane == PLANE_C;
+	else
+		return i9xx_plane == PLANE_B ||
+			i9xx_plane == PLANE_C;
+}
+
+static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
+			  const struct intel_plane_state *plane_state)
+{
+	struct drm_i915_private *dev_priv =
+		to_i915(plane_state->uapi.plane->dev);
+	const struct drm_framebuffer *fb = plane_state->hw.fb;
+	unsigned int rotation = plane_state->hw.rotation;
+	u32 dspcntr;
+
+	dspcntr = DISPLAY_PLANE_ENABLE;
+
+	if (IS_G4X(dev_priv) || IS_GEN(dev_priv, 5) ||
+	    IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
+		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+
+	switch (fb->format->format) {
+	case DRM_FORMAT_C8:
+		dspcntr |= DISPPLANE_8BPP;
+		break;
+	case DRM_FORMAT_XRGB1555:
+		dspcntr |= DISPPLANE_BGRX555;
+		break;
+	case DRM_FORMAT_ARGB1555:
+		dspcntr |= DISPPLANE_BGRA555;
+		break;
+	case DRM_FORMAT_RGB565:
+		dspcntr |= DISPPLANE_BGRX565;
+		break;
+	case DRM_FORMAT_XRGB8888:
+		dspcntr |= DISPPLANE_BGRX888;
+		break;
+	case DRM_FORMAT_XBGR8888:
+		dspcntr |= DISPPLANE_RGBX888;
+		break;
+	case DRM_FORMAT_ARGB8888:
+		dspcntr |= DISPPLANE_BGRA888;
+		break;
+	case DRM_FORMAT_ABGR8888:
+		dspcntr |= DISPPLANE_RGBA888;
+		break;
+	case DRM_FORMAT_XRGB2101010:
+		dspcntr |= DISPPLANE_BGRX101010;
+		break;
+	case DRM_FORMAT_XBGR2101010:
+		dspcntr |= DISPPLANE_RGBX101010;
+		break;
+	case DRM_FORMAT_ARGB2101010:
+		dspcntr |= DISPPLANE_BGRA101010;
+		break;
+	case DRM_FORMAT_ABGR2101010:
+		dspcntr |= DISPPLANE_RGBA101010;
+		break;
+	case DRM_FORMAT_XBGR16161616F:
+		dspcntr |= DISPPLANE_RGBX161616;
+		break;
+	default:
+		MISSING_CASE(fb->format->format);
+		return 0;
+	}
+
+	if (INTEL_GEN(dev_priv) >= 4 &&
+	    fb->modifier == I915_FORMAT_MOD_X_TILED)
+		dspcntr |= DISPPLANE_TILED;
+
+	if (rotation & DRM_MODE_ROTATE_180)
+		dspcntr |= DISPPLANE_ROTATE_180;
+
+	if (rotation & DRM_MODE_REFLECT_X)
+		dspcntr |= DISPPLANE_MIRROR;
+
+	return dspcntr;
+}
+
+static int
+i9xx_plane_check(struct intel_crtc_state *crtc_state,
+		 struct intel_plane_state *plane_state)
+{
+	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
+	int ret;
+
+	ret = chv_plane_check_rotation(plane_state);
+	if (ret)
+		return ret;
+
+	ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
+						DRM_PLANE_HELPER_NO_SCALING,
+						DRM_PLANE_HELPER_NO_SCALING,
+						i9xx_plane_has_windowing(plane));
+	if (ret)
+		return ret;
+
+	ret = i9xx_check_plane_surface(plane_state);
+	if (ret)
+		return ret;
+
+	if (!plane_state->uapi.visible)
+		return 0;
+
+	ret = intel_plane_check_src_coordinates(plane_state);
+	if (ret)
+		return ret;
+
+	plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);
+
+	return 0;
+}
+
+static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	u32 dspcntr = 0;
+
+	if (crtc_state->gamma_enable)
+		dspcntr |= DISPPLANE_GAMMA_ENABLE;
+
+	if (crtc_state->csc_enable)
+		dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
+
+	if (INTEL_GEN(dev_priv) < 5)
+		dspcntr |= DISPPLANE_SEL_PIPE(crtc->pipe);
+
+	return dspcntr;
+}
+
+static void i9xx_plane_ratio(const struct intel_crtc_state *crtc_state,
+			     const struct intel_plane_state *plane_state,
+			     unsigned int *num, unsigned int *den)
+{
+	const struct drm_framebuffer *fb = plane_state->hw.fb;
+	unsigned int cpp = fb->format->cpp[0];
+
+	/*
+	 * g4x bspec says 64bpp pixel rate can't exceed 80%
+	 * of cdclk when the sprite plane is enabled on the
+	 * same pipe. ilk/snb bspec says 64bpp pixel rate is
+	 * never allowed to exceed 80% of cdclk. Let's just go
+	 * with the ilk/snb limit always.
+	 */
+	if (cpp == 8) {
+		*num = 10;
+		*den = 8;
+	} else {
+		*num = 1;
+		*den = 1;
+	}
+}
+
+static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
+				const struct intel_plane_state *plane_state)
+{
+	unsigned int pixel_rate;
+	unsigned int num, den;
+
+	/*
+	 * Note that crtc_state->pixel_rate accounts for both
+	 * horizontal and vertical panel fitter downscaling factors.
+	 * Pre-HSW bspec tells us to only consider the horizontal
+	 * downscaling factor here. We ignore that and just consider
+	 * both for simplicity.
+	 */
+	pixel_rate = crtc_state->pixel_rate;
+
+	i9xx_plane_ratio(crtc_state, plane_state, &num, &den);
+
+	/* two pixels per clock with double wide pipe */
+	if (crtc_state->double_wide)
+		den *= 2;
+
+	return DIV_ROUND_UP(pixel_rate * num, den);
+}
+
+static void i9xx_update_plane(struct intel_plane *plane,
+			      const struct intel_crtc_state *crtc_state,
+			      const struct intel_plane_state *plane_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+	u32 linear_offset;
+	int x = plane_state->color_plane[0].x;
+	int y = plane_state->color_plane[0].y;
+	int crtc_x = plane_state->uapi.dst.x1;
+	int crtc_y = plane_state->uapi.dst.y1;
+	int crtc_w = drm_rect_width(&plane_state->uapi.dst);
+	int crtc_h = drm_rect_height(&plane_state->uapi.dst);
+	unsigned long irqflags;
+	u32 dspaddr_offset;
+	u32 dspcntr;
+
+	dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
+
+	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
+
+	if (INTEL_GEN(dev_priv) >= 4)
+		dspaddr_offset = plane_state->color_plane[0].offset;
+	else
+		dspaddr_offset = linear_offset;
+
+	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+	intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane),
+			  plane_state->color_plane[0].stride);
+
+	if (INTEL_GEN(dev_priv) < 4) {
+		/*
+		 * PLANE_A doesn't actually have a full window
+		 * generator but let's assume we still need to
+		 * program whatever is there.
+		 */
+		intel_de_write_fw(dev_priv, DSPPOS(i9xx_plane),
+				  (crtc_y << 16) | crtc_x);
+		intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane),
+				  ((crtc_h - 1) << 16) | (crtc_w - 1));
+	} else if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
+		intel_de_write_fw(dev_priv, PRIMPOS(i9xx_plane),
+				  (crtc_y << 16) | crtc_x);
+		intel_de_write_fw(dev_priv, PRIMSIZE(i9xx_plane),
+				  ((crtc_h - 1) << 16) | (crtc_w - 1));
+		intel_de_write_fw(dev_priv, PRIMCNSTALPHA(i9xx_plane), 0);
+	}
+
+	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
+		intel_de_write_fw(dev_priv, DSPOFFSET(i9xx_plane),
+				  (y << 16) | x);
+	} else if (INTEL_GEN(dev_priv) >= 4) {
+		intel_de_write_fw(dev_priv, DSPLINOFF(i9xx_plane),
+				  linear_offset);
+		intel_de_write_fw(dev_priv, DSPTILEOFF(i9xx_plane),
+				  (y << 16) | x);
+	}
+
+	/*
+	 * The control register self-arms if the plane was previously
+	 * disabled. Try to make the plane enable atomic by writing
+	 * the control register just before the surface register.
+	 */
+	intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
+	if (INTEL_GEN(dev_priv) >= 4)
+		intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
+				  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
+	else
+		intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane),
+				  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
+
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static void i9xx_disable_plane(struct intel_plane *plane,
+			       const struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+	unsigned long irqflags;
+	u32 dspcntr;
+
+	/*
+	 * DSPCNTR pipe gamma enable on g4x+ and pipe csc
+	 * enable on ilk+ affect the pipe bottom color as
+	 * well, so we must configure them even if the plane
+	 * is disabled.
+	 *
+	 * On pre-g4x there is no way to gamma correct the
+	 * pipe bottom color but we'll keep on doing this
+	 * anyway so that the crtc state readout works correctly.
+	 */
+	dspcntr = i9xx_plane_ctl_crtc(crtc_state);
+
+	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+	intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
+	if (INTEL_GEN(dev_priv) >= 4)
+		intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0);
+	else
+		intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0);
+
+	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
+				    enum pipe *pipe)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+	enum intel_display_power_domain power_domain;
+	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
+	intel_wakeref_t wakeref;
+	bool ret;
+	u32 val;
+
+	/*
+	 * Not 100% correct for planes that can move between pipes,
+	 * but that's only the case for gen2-4 which don't have any
+	 * display power wells.
+	 */
+	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
+	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
+	if (!wakeref)
+		return false;
+
+	val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane));
+
+	ret = val & DISPLAY_PLANE_ENABLE;
+
+	if (INTEL_GEN(dev_priv) >= 5)
+		*pipe = plane->pipe;
+	else
+		*pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
+			DISPPLANE_SEL_PIPE_SHIFT;
+
+	intel_display_power_put(dev_priv, power_domain, wakeref);
+
+	return ret;
+}
+
+unsigned int
+i9xx_plane_max_stride(struct intel_plane *plane,
+		      u32 pixel_format, u64 modifier,
+		      unsigned int rotation)
+{
+	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
+
+	if (!HAS_GMCH(dev_priv)) {
+		return 32*1024;
+	} else if (INTEL_GEN(dev_priv) >= 4) {
+		if (modifier == I915_FORMAT_MOD_X_TILED)
+			return 16*1024;
+		else
+			return 32*1024;
+	} else if (INTEL_GEN(dev_priv) >= 3) {
+		if (modifier == I915_FORMAT_MOD_X_TILED)
+			return 8*1024;
+		else
+			return 16*1024;
+	} else {
+		if (plane->i9xx_plane == PLANE_C)
+			return 4*1024;
+		else
+			return 8*1024;
+	}
+}
+
+static const struct drm_plane_funcs i965_plane_funcs = {
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
+	.destroy = intel_plane_destroy,
+	.atomic_duplicate_state = intel_plane_duplicate_state,
+	.atomic_destroy_state = intel_plane_destroy_state,
+	.format_mod_supported = i965_plane_format_mod_supported,
+};
+
+static const struct drm_plane_funcs i8xx_plane_funcs = {
+	.update_plane = drm_atomic_helper_update_plane,
+	.disable_plane = drm_atomic_helper_disable_plane,
+	.destroy = intel_plane_destroy,
+	.atomic_duplicate_state = intel_plane_duplicate_state,
+	.atomic_destroy_state = intel_plane_destroy_state,
+	.format_mod_supported = i8xx_plane_format_mod_supported,
+};
+
+static struct intel_plane *
+intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
+{
+	struct intel_plane *plane;
+	const struct drm_plane_funcs *plane_funcs;
+	unsigned int supported_rotations;
+	const u32 *formats;
+	int num_formats;
+	int ret, zpos;
+
+	if (INTEL_GEN(dev_priv) >= 9)
+		return skl_universal_plane_create(dev_priv, pipe,
+						  PLANE_PRIMARY);
+
+	plane = intel_plane_alloc();
+	if (IS_ERR(plane))
+		return plane;
+
+	plane->pipe = pipe;
+	/*
+	 * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
+	 * port is hooked to pipe B. Hence we want plane A feeding pipe B.
+	 */
+	if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) < 4 &&
+	    INTEL_NUM_PIPES(dev_priv) == 2)
+		plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
+	else
+		plane->i9xx_plane = (enum i9xx_plane_id) pipe;
+	plane->id = PLANE_PRIMARY;
+	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
+
+	plane->has_fbc = i9xx_plane_has_fbc(dev_priv, plane->i9xx_plane);
+	if (plane->has_fbc) {
+		struct intel_fbc *fbc = &dev_priv->fbc;
+
+		fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
+	}
+
+	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+		formats = vlv_primary_formats;
+		num_formats = ARRAY_SIZE(vlv_primary_formats);
+	} else if (INTEL_GEN(dev_priv) >= 4) {
+		/*
+		 * WaFP16GammaEnabling:ivb
+		 * "Workaround : When using the 64-bit format, the plane
+		 *  output on each color channel has one quarter amplitude.
+		 *  It can be brought up to full amplitude by using pipe
+		 *  gamma correction or pipe color space conversion to
+		 *  multiply the plane output by four."
+		 *
+		 * There is no dedicated plane gamma for the primary plane,
+		 * and using the pipe gamma/csc could conflict with other
+		 * planes, so we choose not to expose fp16 on IVB primary
+		 * planes. HSW primary planes no longer have this problem.
+		 */
+		if (IS_IVYBRIDGE(dev_priv)) {
+			formats = ivb_primary_formats;
+			num_formats = ARRAY_SIZE(ivb_primary_formats);
+		} else {
+			formats = i965_primary_formats;
+			num_formats = ARRAY_SIZE(i965_primary_formats);
+		}
+	} else {
+		formats = i8xx_primary_formats;
+		num_formats = ARRAY_SIZE(i8xx_primary_formats);
+	}
+
+	if (INTEL_GEN(dev_priv) >= 4)
+		plane_funcs = &i965_plane_funcs;
+	else
+		plane_funcs = &i8xx_plane_funcs;
+
+	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+		plane->min_cdclk = vlv_plane_min_cdclk;
+	else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+		plane->min_cdclk = hsw_plane_min_cdclk;
+	else if (IS_IVYBRIDGE(dev_priv))
+		plane->min_cdclk = ivb_plane_min_cdclk;
+	else
+		plane->min_cdclk = i9xx_plane_min_cdclk;
+
+	plane->max_stride = i9xx_plane_max_stride;
+	plane->update_plane = i9xx_update_plane;
+	plane->disable_plane = i9xx_disable_plane;
+	plane->get_hw_state = i9xx_plane_get_hw_state;
+	plane->check_plane = i9xx_plane_check;
+
+	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
+		ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
+					       0, plane_funcs,
+					       formats, num_formats,
+					       i9xx_format_modifiers,
+					       DRM_PLANE_TYPE_PRIMARY,
+					       "primary %c", pipe_name(pipe));
+	else
+		ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
+					       0, plane_funcs,
+					       formats, num_formats,
+					       i9xx_format_modifiers,
+					       DRM_PLANE_TYPE_PRIMARY,
+					       "plane %c",
+					       plane_name(plane->i9xx_plane));
+	if (ret)
+		goto fail;
+
+	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
+		supported_rotations =
+			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
+			DRM_MODE_REFLECT_X;
+	} else if (INTEL_GEN(dev_priv) >= 4) {
+		supported_rotations =
+			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
+	} else {
+		supported_rotations = DRM_MODE_ROTATE_0;
+	}
+
+	if (INTEL_GEN(dev_priv) >= 4)
+		drm_plane_create_rotation_property(&plane->base,
+						   DRM_MODE_ROTATE_0,
+						   supported_rotations);
+
+	zpos = 0;
+	drm_plane_create_zpos_immutable_property(&plane->base, zpos);
+
+	drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
+
+	return plane;
+
+fail:
+	intel_plane_free(plane);
+
+	return ERR_PTR(ret);
+}
+
+static struct intel_crtc *intel_crtc_alloc(void)
+{
+	struct intel_crtc_state *crtc_state;
+	struct intel_crtc *crtc;
+
+	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
+	if (!crtc)
+		return ERR_PTR(-ENOMEM);
+
+	crtc_state = intel_crtc_state_alloc(crtc);
+	if (!crtc_state) {
+		kfree(crtc);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	crtc->base.state = &crtc_state->uapi;
+	crtc->config = crtc_state;
+
+	return crtc;
+}
+
+static void intel_crtc_free(struct intel_crtc *crtc)
+{
+	intel_crtc_destroy_state(&crtc->base, crtc->base.state);
+	kfree(crtc);
+}
+
+static void intel_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+	drm_crtc_cleanup(crtc);
+	kfree(intel_crtc);
+}
+
+static int intel_crtc_late_register(struct drm_crtc *crtc)
+{
+	intel_crtc_debugfs_add(crtc);
+	return 0;
+}
+
+#define INTEL_CRTC_FUNCS \
+	.gamma_set = drm_atomic_helper_legacy_gamma_set, \
+	.set_config = drm_atomic_helper_set_config, \
+	.destroy = intel_crtc_destroy, \
+	.page_flip = drm_atomic_helper_page_flip, \
+	.atomic_duplicate_state = intel_crtc_duplicate_state, \
+	.atomic_destroy_state = intel_crtc_destroy_state, \
+	.set_crc_source = intel_crtc_set_crc_source, \
+	.verify_crc_source = intel_crtc_verify_crc_source, \
+	.get_crc_sources = intel_crtc_get_crc_sources, \
+	.late_register = intel_crtc_late_register
+
+static const struct drm_crtc_funcs bdw_crtc_funcs = {
+	INTEL_CRTC_FUNCS,
+
+	.get_vblank_counter = g4x_get_vblank_counter,
+	.enable_vblank = bdw_enable_vblank,
+	.disable_vblank = bdw_disable_vblank,
+	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
+};
+
+static const struct drm_crtc_funcs ilk_crtc_funcs = {
+	INTEL_CRTC_FUNCS,
+
+	.get_vblank_counter = g4x_get_vblank_counter,
+	.enable_vblank = ilk_enable_vblank,
+	.disable_vblank = ilk_disable_vblank,
+	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
+};
+
+static const struct drm_crtc_funcs g4x_crtc_funcs = {
+	INTEL_CRTC_FUNCS,
+
+	.get_vblank_counter = g4x_get_vblank_counter,
+	.enable_vblank = i965_enable_vblank,
+	.disable_vblank = i965_disable_vblank,
+	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
+};
+
+static const struct drm_crtc_funcs i965_crtc_funcs = {
+	INTEL_CRTC_FUNCS,
+
+	.get_vblank_counter = i915_get_vblank_counter,
+	.enable_vblank = i965_enable_vblank,
+	.disable_vblank = i965_disable_vblank,
+	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
+};
+
+static const struct drm_crtc_funcs i915gm_crtc_funcs = {
+	INTEL_CRTC_FUNCS,
+
+	.get_vblank_counter = i915_get_vblank_counter,
+	.enable_vblank = i915gm_enable_vblank,
+	.disable_vblank = i915gm_disable_vblank,
+	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
+};
+
+static const struct drm_crtc_funcs i915_crtc_funcs = {
+	INTEL_CRTC_FUNCS,
+
+	.get_vblank_counter = i915_get_vblank_counter,
+	.enable_vblank = i8xx_enable_vblank,
+	.disable_vblank = i8xx_disable_vblank,
+	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
+};
+
+static const struct drm_crtc_funcs i8xx_crtc_funcs = {
+	INTEL_CRTC_FUNCS,
+
+	/* no hw vblank counter */
+	.enable_vblank = i8xx_enable_vblank,
+	.disable_vblank = i8xx_disable_vblank,
+	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
+};
+
+int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
+{
+	struct intel_plane *primary, *cursor;
+	const struct drm_crtc_funcs *funcs;
+	struct intel_crtc *crtc;
+	int sprite, ret;
+
+	crtc = intel_crtc_alloc();
+	if (IS_ERR(crtc))
+		return PTR_ERR(crtc);
+
+	crtc->pipe = pipe;
+	crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe];
+
+	primary = intel_primary_plane_create(dev_priv, pipe);
+	if (IS_ERR(primary)) {
+		ret = PTR_ERR(primary);
+		goto fail;
+	}
+	crtc->plane_ids_mask |= BIT(primary->id);
+
+	for_each_sprite(dev_priv, pipe, sprite) {
+		struct intel_plane *plane;
+
+		plane = intel_sprite_plane_create(dev_priv, pipe, sprite);
+		if (IS_ERR(plane)) {
+			ret = PTR_ERR(plane);
+			goto fail;
+		}
+		crtc->plane_ids_mask |= BIT(plane->id);
+	}
+
+	cursor = intel_cursor_plane_create(dev_priv, pipe);
+	if (IS_ERR(cursor)) {
+		ret = PTR_ERR(cursor);
+		goto fail;
+	}
+	crtc->plane_ids_mask |= BIT(cursor->id);
+
+	if (HAS_GMCH(dev_priv)) {
+		if (IS_CHERRYVIEW(dev_priv) ||
+		    IS_VALLEYVIEW(dev_priv) || IS_G4X(dev_priv))
+			funcs = &g4x_crtc_funcs;
+		else if (IS_GEN(dev_priv, 4))
+			funcs = &i965_crtc_funcs;
+		else if (IS_I945GM(dev_priv) || IS_I915GM(dev_priv))
+			funcs = &i915gm_crtc_funcs;
+		else if (IS_GEN(dev_priv, 3))
+			funcs = &i915_crtc_funcs;
+		else
+			funcs = &i8xx_crtc_funcs;
+	} else {
+		if (INTEL_GEN(dev_priv) >= 8)
+			funcs = &bdw_crtc_funcs;
+		else
+			funcs = &ilk_crtc_funcs;
+	}
+
+	ret = drm_crtc_init_with_planes(&dev_priv->drm, &crtc->base,
+					&primary->base, &cursor->base,
+					funcs, "pipe %c", pipe_name(pipe));
+	if (ret)
+		goto fail;
+
+	BUG_ON(pipe >= ARRAY_SIZE(dev_priv->pipe_to_crtc_mapping) ||
+	       dev_priv->pipe_to_crtc_mapping[pipe] != NULL);
+	dev_priv->pipe_to_crtc_mapping[pipe] = crtc;
+
+	if (INTEL_GEN(dev_priv) < 9) {
+		enum i9xx_plane_id i9xx_plane = primary->i9xx_plane;
+
+		BUG_ON(i9xx_plane >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
+		       dev_priv->plane_to_crtc_mapping[i9xx_plane] != NULL);
+		dev_priv->plane_to_crtc_mapping[i9xx_plane] = crtc;
+	}
+
+	if (INTEL_GEN(dev_priv) >= 10)
+		drm_crtc_create_scaling_filter_property(&crtc->base,
+						BIT(DRM_SCALING_FILTER_DEFAULT) |
+						BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
+
+	intel_color_init(crtc);
+
+	intel_crtc_crc_init(crtc);
+
+	drm_WARN_ON(&dev_priv->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
+
+	return 0;
+
+fail:
+	intel_crtc_free(crtc);
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 0a3b97889248..c6f30e4ec51e 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -87,56 +87,6 @@
 #include "intel_tc.h"
 #include "intel_vga.h"
 
-/* Primary plane formats for gen <= 3 */
-static const u32 i8xx_primary_formats[] = {
-	DRM_FORMAT_C8,
-	DRM_FORMAT_XRGB1555,
-	DRM_FORMAT_RGB565,
-	DRM_FORMAT_XRGB8888,
-};
-
-/* Primary plane formats for ivb (no fp16 due to hw issue) */
-static const u32 ivb_primary_formats[] = {
-	DRM_FORMAT_C8,
-	DRM_FORMAT_RGB565,
-	DRM_FORMAT_XRGB8888,
-	DRM_FORMAT_XBGR8888,
-	DRM_FORMAT_XRGB2101010,
-	DRM_FORMAT_XBGR2101010,
-};
-
-/* Primary plane formats for gen >= 4, except ivb */
-static const u32 i965_primary_formats[] = {
-	DRM_FORMAT_C8,
-	DRM_FORMAT_RGB565,
-	DRM_FORMAT_XRGB8888,
-	DRM_FORMAT_XBGR8888,
-	DRM_FORMAT_XRGB2101010,
-	DRM_FORMAT_XBGR2101010,
-	DRM_FORMAT_XBGR16161616F,
-};
-
-/* Primary plane formats for vlv/chv */
-static const u32 vlv_primary_formats[] = {
-	DRM_FORMAT_C8,
-	DRM_FORMAT_RGB565,
-	DRM_FORMAT_XRGB8888,
-	DRM_FORMAT_XBGR8888,
-	DRM_FORMAT_ARGB8888,
-	DRM_FORMAT_ABGR8888,
-	DRM_FORMAT_XRGB2101010,
-	DRM_FORMAT_XBGR2101010,
-	DRM_FORMAT_ARGB2101010,
-	DRM_FORMAT_ABGR2101010,
-	DRM_FORMAT_XBGR16161616F,
-};
-
-static const u64 i9xx_format_modifiers[] = {
-	I915_FORMAT_MOD_X_TILED,
-	DRM_FORMAT_MOD_LINEAR,
-	DRM_FORMAT_MOD_INVALID
-};
-
 static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
 				struct intel_crtc_state *pipe_config);
 static void ilk_pch_clock_get(struct intel_crtc *crtc,
@@ -162,7 +112,6 @@ static void skl_pfit_enable(const struct intel_crtc_state *crtc_state);
 static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state);
 static void intel_modeset_setup_hw_state(struct drm_device *dev,
 					 struct drm_modeset_acquire_ctx *ctx);
-static struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc);
 
 struct intel_limit {
 	struct {
@@ -1306,12 +1255,6 @@ static void assert_planes_disabled(struct intel_crtc *crtc)
 		assert_plane_disabled(plane);
 }
 
-static void assert_vblank_disabled(struct drm_crtc *crtc)
-{
-	if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
-		drm_crtc_vblank_put(crtc);
-}
-
 void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
 				    enum pipe pipe)
 {
@@ -1796,55 +1739,6 @@ enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
 		return crtc->pipe;
 }
 
-static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
-	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-	u32 mode_flags = crtc->mode_flags;
-
-	/*
-	 * From Gen 11, In case of dsi cmd mode, frame counter wouldnt
-	 * have updated at the beginning of TE, if we want to use
-	 * the hw counter, then we would find it updated in only
-	 * the next TE, hence switching to sw counter.
-	 */
-	if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1))
-		return 0;
-
-	/*
-	 * On i965gm the hardware frame counter reads
-	 * zero when the TV encoder is enabled :(
-	 */
-	if (IS_I965GM(dev_priv) &&
-	    (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
-		return 0;
-
-	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
-		return 0xffffffff; /* full 32 bit counter */
-	else if (INTEL_GEN(dev_priv) >= 3)
-		return 0xffffff; /* only 24 bits of frame count */
-	else
-		return 0; /* Gen2 doesn't have a hardware frame counter */
-}
-
-void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
-{
-	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-
-	assert_vblank_disabled(&crtc->base);
-	drm_crtc_set_max_vblank_count(&crtc->base,
-				      intel_crtc_max_vblank_count(crtc_state));
-	drm_crtc_vblank_on(&crtc->base);
-}
-
-void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state)
-{
-	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-
-	drm_crtc_vblank_off(&crtc->base);
-	assert_vblank_disabled(&crtc->base);
-}
-
 void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
@@ -4057,171 +3951,6 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
 	return 0;
 }
 
-static void i9xx_plane_ratio(const struct intel_crtc_state *crtc_state,
-			     const struct intel_plane_state *plane_state,
-			     unsigned int *num, unsigned int *den)
-{
-	const struct drm_framebuffer *fb = plane_state->hw.fb;
-	unsigned int cpp = fb->format->cpp[0];
-
-	/*
-	 * g4x bspec says 64bpp pixel rate can't exceed 80%
-	 * of cdclk when the sprite plane is enabled on the
-	 * same pipe. ilk/snb bspec says 64bpp pixel rate is
-	 * never allowed to exceed 80% of cdclk. Let's just go
-	 * with the ilk/snb limit always.
-	 */
-	if (cpp == 8) {
-		*num = 10;
-		*den = 8;
-	} else {
-		*num = 1;
-		*den = 1;
-	}
-}
-
-static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
-				const struct intel_plane_state *plane_state)
-{
-	unsigned int pixel_rate;
-	unsigned int num, den;
-
-	/*
-	 * Note that crtc_state->pixel_rate accounts for both
-	 * horizontal and vertical panel fitter downscaling factors.
-	 * Pre-HSW bspec tells us to only consider the horizontal
-	 * downscaling factor here. We ignore that and just consider
-	 * both for simplicity.
-	 */
-	pixel_rate = crtc_state->pixel_rate;
-
-	i9xx_plane_ratio(crtc_state, plane_state, &num, &den);
-
-	/* two pixels per clock with double wide pipe */
-	if (crtc_state->double_wide)
-		den *= 2;
-
-	return DIV_ROUND_UP(pixel_rate * num, den);
-}
-
-unsigned int
-i9xx_plane_max_stride(struct intel_plane *plane,
-		      u32 pixel_format, u64 modifier,
-		      unsigned int rotation)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-
-	if (!HAS_GMCH(dev_priv)) {
-		return 32*1024;
-	} else if (INTEL_GEN(dev_priv) >= 4) {
-		if (modifier == I915_FORMAT_MOD_X_TILED)
-			return 16*1024;
-		else
-			return 32*1024;
-	} else if (INTEL_GEN(dev_priv) >= 3) {
-		if (modifier == I915_FORMAT_MOD_X_TILED)
-			return 8*1024;
-		else
-			return 16*1024;
-	} else {
-		if (plane->i9xx_plane == PLANE_C)
-			return 4*1024;
-		else
-			return 8*1024;
-	}
-}
-
-static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
-{
-	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	u32 dspcntr = 0;
-
-	if (crtc_state->gamma_enable)
-		dspcntr |= DISPPLANE_GAMMA_ENABLE;
-
-	if (crtc_state->csc_enable)
-		dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
-
-	if (INTEL_GEN(dev_priv) < 5)
-		dspcntr |= DISPPLANE_SEL_PIPE(crtc->pipe);
-
-	return dspcntr;
-}
-
-static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
-			  const struct intel_plane_state *plane_state)
-{
-	struct drm_i915_private *dev_priv =
-		to_i915(plane_state->uapi.plane->dev);
-	const struct drm_framebuffer *fb = plane_state->hw.fb;
-	unsigned int rotation = plane_state->hw.rotation;
-	u32 dspcntr;
-
-	dspcntr = DISPLAY_PLANE_ENABLE;
-
-	if (IS_G4X(dev_priv) || IS_GEN(dev_priv, 5) ||
-	    IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
-		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
-
-	switch (fb->format->format) {
-	case DRM_FORMAT_C8:
-		dspcntr |= DISPPLANE_8BPP;
-		break;
-	case DRM_FORMAT_XRGB1555:
-		dspcntr |= DISPPLANE_BGRX555;
-		break;
-	case DRM_FORMAT_ARGB1555:
-		dspcntr |= DISPPLANE_BGRA555;
-		break;
-	case DRM_FORMAT_RGB565:
-		dspcntr |= DISPPLANE_BGRX565;
-		break;
-	case DRM_FORMAT_XRGB8888:
-		dspcntr |= DISPPLANE_BGRX888;
-		break;
-	case DRM_FORMAT_XBGR8888:
-		dspcntr |= DISPPLANE_RGBX888;
-		break;
-	case DRM_FORMAT_ARGB8888:
-		dspcntr |= DISPPLANE_BGRA888;
-		break;
-	case DRM_FORMAT_ABGR8888:
-		dspcntr |= DISPPLANE_RGBA888;
-		break;
-	case DRM_FORMAT_XRGB2101010:
-		dspcntr |= DISPPLANE_BGRX101010;
-		break;
-	case DRM_FORMAT_XBGR2101010:
-		dspcntr |= DISPPLANE_RGBX101010;
-		break;
-	case DRM_FORMAT_ARGB2101010:
-		dspcntr |= DISPPLANE_BGRA101010;
-		break;
-	case DRM_FORMAT_ABGR2101010:
-		dspcntr |= DISPPLANE_RGBA101010;
-		break;
-	case DRM_FORMAT_XBGR16161616F:
-		dspcntr |= DISPPLANE_RGBX161616;
-		break;
-	default:
-		MISSING_CASE(fb->format->format);
-		return 0;
-	}
-
-	if (INTEL_GEN(dev_priv) >= 4 &&
-	    fb->modifier == I915_FORMAT_MOD_X_TILED)
-		dspcntr |= DISPPLANE_TILED;
-
-	if (rotation & DRM_MODE_ROTATE_180)
-		dspcntr |= DISPPLANE_ROTATE_180;
-
-	if (rotation & DRM_MODE_REFLECT_X)
-		dspcntr |= DISPPLANE_MIRROR;
-
-	return dspcntr;
-}
-
 int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
 {
 	struct drm_i915_private *dev_priv =
@@ -4282,197 +4011,6 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
 	return 0;
 }
 
-static bool i9xx_plane_has_windowing(struct intel_plane *plane)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
-
-	if (IS_CHERRYVIEW(dev_priv))
-		return i9xx_plane == PLANE_B;
-	else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
-		return false;
-	else if (IS_GEN(dev_priv, 4))
-		return i9xx_plane == PLANE_C;
-	else
-		return i9xx_plane == PLANE_B ||
-			i9xx_plane == PLANE_C;
-}
-
-static int
-i9xx_plane_check(struct intel_crtc_state *crtc_state,
-		 struct intel_plane_state *plane_state)
-{
-	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
-	int ret;
-
-	ret = chv_plane_check_rotation(plane_state);
-	if (ret)
-		return ret;
-
-	ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
-						DRM_PLANE_HELPER_NO_SCALING,
-						DRM_PLANE_HELPER_NO_SCALING,
-						i9xx_plane_has_windowing(plane));
-	if (ret)
-		return ret;
-
-	ret = i9xx_check_plane_surface(plane_state);
-	if (ret)
-		return ret;
-
-	if (!plane_state->uapi.visible)
-		return 0;
-
-	ret = intel_plane_check_src_coordinates(plane_state);
-	if (ret)
-		return ret;
-
-	plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);
-
-	return 0;
-}
-
-static void i9xx_update_plane(struct intel_plane *plane,
-			      const struct intel_crtc_state *crtc_state,
-			      const struct intel_plane_state *plane_state)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
-	u32 linear_offset;
-	int x = plane_state->color_plane[0].x;
-	int y = plane_state->color_plane[0].y;
-	int crtc_x = plane_state->uapi.dst.x1;
-	int crtc_y = plane_state->uapi.dst.y1;
-	int crtc_w = drm_rect_width(&plane_state->uapi.dst);
-	int crtc_h = drm_rect_height(&plane_state->uapi.dst);
-	unsigned long irqflags;
-	u32 dspaddr_offset;
-	u32 dspcntr;
-
-	dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
-
-	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
-
-	if (INTEL_GEN(dev_priv) >= 4)
-		dspaddr_offset = plane_state->color_plane[0].offset;
-	else
-		dspaddr_offset = linear_offset;
-
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
-	intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane),
-			  plane_state->color_plane[0].stride);
-
-	if (INTEL_GEN(dev_priv) < 4) {
-		/*
-		 * PLANE_A doesn't actually have a full window
-		 * generator but let's assume we still need to
-		 * program whatever is there.
-		 */
-		intel_de_write_fw(dev_priv, DSPPOS(i9xx_plane),
-				  (crtc_y << 16) | crtc_x);
-		intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane),
-				  ((crtc_h - 1) << 16) | (crtc_w - 1));
-	} else if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
-		intel_de_write_fw(dev_priv, PRIMPOS(i9xx_plane),
-				  (crtc_y << 16) | crtc_x);
-		intel_de_write_fw(dev_priv, PRIMSIZE(i9xx_plane),
-				  ((crtc_h - 1) << 16) | (crtc_w - 1));
-		intel_de_write_fw(dev_priv, PRIMCNSTALPHA(i9xx_plane), 0);
-	}
-
-	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
-		intel_de_write_fw(dev_priv, DSPOFFSET(i9xx_plane),
-				  (y << 16) | x);
-	} else if (INTEL_GEN(dev_priv) >= 4) {
-		intel_de_write_fw(dev_priv, DSPLINOFF(i9xx_plane),
-				  linear_offset);
-		intel_de_write_fw(dev_priv, DSPTILEOFF(i9xx_plane),
-				  (y << 16) | x);
-	}
-
-	/*
-	 * The control register self-arms if the plane was previously
-	 * disabled. Try to make the plane enable atomic by writing
-	 * the control register just before the surface register.
-	 */
-	intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
-	if (INTEL_GEN(dev_priv) >= 4)
-		intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
-				  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
-	else
-		intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane),
-				  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
-
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void i9xx_disable_plane(struct intel_plane *plane,
-			       const struct intel_crtc_state *crtc_state)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
-	unsigned long irqflags;
-	u32 dspcntr;
-
-	/*
-	 * DSPCNTR pipe gamma enable on g4x+ and pipe csc
-	 * enable on ilk+ affect the pipe bottom color as
-	 * well, so we must configure them even if the plane
-	 * is disabled.
-	 *
-	 * On pre-g4x there is no way to gamma correct the
-	 * pipe bottom color but we'll keep on doing this
-	 * anyway so that the crtc state readout works correctly.
-	 */
-	dspcntr = i9xx_plane_ctl_crtc(crtc_state);
-
-	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
-	intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
-	if (INTEL_GEN(dev_priv) >= 4)
-		intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0);
-	else
-		intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0);
-
-	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
-				    enum pipe *pipe)
-{
-	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
-	enum intel_display_power_domain power_domain;
-	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
-	intel_wakeref_t wakeref;
-	bool ret;
-	u32 val;
-
-	/*
-	 * Not 100% correct for planes that can move between pipes,
-	 * but that's only the case for gen2-4 which don't have any
-	 * display power wells.
-	 */
-	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
-	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
-	if (!wakeref)
-		return false;
-
-	val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane));
-
-	ret = val & DISPLAY_PLANE_ENABLE;
-
-	if (INTEL_GEN(dev_priv) >= 5)
-		*pipe = plane->pipe;
-	else
-		*pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
-			DISPPLANE_SEL_PIPE_SHIFT;
-
-	intel_display_power_put(dev_priv, power_domain, wakeref);
-
-	return ret;
-}
-
 static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
 {
 	struct drm_device *dev = intel_crtc->base.dev;
@@ -11919,33 +11457,6 @@ static void ilk_pch_clock_get(struct intel_crtc *crtc,
 					 &pipe_config->fdi_m_n);
 }
 
-static void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
-				   struct intel_crtc *crtc)
-{
-	memset(crtc_state, 0, sizeof(*crtc_state));
-
-	__drm_atomic_helper_crtc_state_reset(&crtc_state->uapi, &crtc->base);
-
-	crtc_state->cpu_transcoder = INVALID_TRANSCODER;
-	crtc_state->master_transcoder = INVALID_TRANSCODER;
-	crtc_state->hsw_workaround_pipe = INVALID_PIPE;
-	crtc_state->output_format = INTEL_OUTPUT_FORMAT_INVALID;
-	crtc_state->scaler_state.scaler_id = -1;
-	crtc_state->mst_master_transcoder = INVALID_TRANSCODER;
-}
-
-static struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc)
-{
-	struct intel_crtc_state *crtc_state;
-
-	crtc_state = kmalloc(sizeof(*crtc_state), GFP_KERNEL);
-
-	if (crtc_state)
-		intel_crtc_state_reset(crtc_state, crtc);
-
-	return crtc_state;
-}
-
 /* Returns the currently programmed mode of the given encoder. */
 struct drm_display_mode *
 intel_encoder_current_mode(struct intel_encoder *encoder)
@@ -11986,14 +11497,6 @@ intel_encoder_current_mode(struct intel_encoder *encoder)
 	return mode;
 }
 
-static void intel_crtc_destroy(struct drm_crtc *crtc)
-{
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
-	drm_crtc_cleanup(crtc);
-	kfree(intel_crtc);
-}
-
 /**
  * intel_wm_need_update - Check whether watermarks need updating
  * @cur: current plane state
@@ -15197,17 +14700,6 @@ static int intel_atomic_prepare_commit(struct intel_atomic_state *state)
 	return 0;
 }
 
-u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
-
-	if (!vblank->max_vblank_count)
-		return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
-
-	return crtc->base.funcs->get_vblank_counter(&crtc->base);
-}
-
 void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
 				  struct intel_crtc_state *crtc_state)
 {
@@ -16260,336 +15752,6 @@ void intel_plane_destroy(struct drm_plane *plane)
 	kfree(to_intel_plane(plane));
 }
 
-static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane,
-					    u32 format, u64 modifier)
-{
-	switch (modifier) {
-	case DRM_FORMAT_MOD_LINEAR:
-	case I915_FORMAT_MOD_X_TILED:
-		break;
-	default:
-		return false;
-	}
-
-	switch (format) {
-	case DRM_FORMAT_C8:
-	case DRM_FORMAT_RGB565:
-	case DRM_FORMAT_XRGB1555:
-	case DRM_FORMAT_XRGB8888:
-		return modifier == DRM_FORMAT_MOD_LINEAR ||
-			modifier == I915_FORMAT_MOD_X_TILED;
-	default:
-		return false;
-	}
-}
-
-static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
-					    u32 format, u64 modifier)
-{
-	switch (modifier) {
-	case DRM_FORMAT_MOD_LINEAR:
-	case I915_FORMAT_MOD_X_TILED:
-		break;
-	default:
-		return false;
-	}
-
-	switch (format) {
-	case DRM_FORMAT_C8:
-	case DRM_FORMAT_RGB565:
-	case DRM_FORMAT_XRGB8888:
-	case DRM_FORMAT_XBGR8888:
-	case DRM_FORMAT_ARGB8888:
-	case DRM_FORMAT_ABGR8888:
-	case DRM_FORMAT_XRGB2101010:
-	case DRM_FORMAT_XBGR2101010:
-	case DRM_FORMAT_ARGB2101010:
-	case DRM_FORMAT_ABGR2101010:
-	case DRM_FORMAT_XBGR16161616F:
-		return modifier == DRM_FORMAT_MOD_LINEAR ||
-			modifier == I915_FORMAT_MOD_X_TILED;
-	default:
-		return false;
-	}
-}
-
-static const struct drm_plane_funcs i965_plane_funcs = {
-	.update_plane = drm_atomic_helper_update_plane,
-	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
-	.atomic_duplicate_state = intel_plane_duplicate_state,
-	.atomic_destroy_state = intel_plane_destroy_state,
-	.format_mod_supported = i965_plane_format_mod_supported,
-};
-
-static const struct drm_plane_funcs i8xx_plane_funcs = {
-	.update_plane = drm_atomic_helper_update_plane,
-	.disable_plane = drm_atomic_helper_disable_plane,
-	.destroy = intel_plane_destroy,
-	.atomic_duplicate_state = intel_plane_duplicate_state,
-	.atomic_destroy_state = intel_plane_destroy_state,
-	.format_mod_supported = i8xx_plane_format_mod_supported,
-};
-
-static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
-			       enum i9xx_plane_id i9xx_plane)
-{
-	if (!HAS_FBC(dev_priv))
-		return false;
-
-	if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
-		return i9xx_plane == PLANE_A; /* tied to pipe A */
-	else if (IS_IVYBRIDGE(dev_priv))
-		return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B ||
-			i9xx_plane == PLANE_C;
-	else if (INTEL_GEN(dev_priv) >= 4)
-		return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B;
-	else
-		return i9xx_plane == PLANE_A;
-}
-
-static struct intel_plane *
-intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
-{
-	struct intel_plane *plane;
-	const struct drm_plane_funcs *plane_funcs;
-	unsigned int supported_rotations;
-	const u32 *formats;
-	int num_formats;
-	int ret, zpos;
-
-	if (INTEL_GEN(dev_priv) >= 9)
-		return skl_universal_plane_create(dev_priv, pipe,
-						  PLANE_PRIMARY);
-
-	plane = intel_plane_alloc();
-	if (IS_ERR(plane))
-		return plane;
-
-	plane->pipe = pipe;
-	/*
-	 * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
-	 * port is hooked to pipe B. Hence we want plane A feeding pipe B.
-	 */
-	if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) < 4 &&
-	    INTEL_NUM_PIPES(dev_priv) == 2)
-		plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
-	else
-		plane->i9xx_plane = (enum i9xx_plane_id) pipe;
-	plane->id = PLANE_PRIMARY;
-	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
-
-	plane->has_fbc = i9xx_plane_has_fbc(dev_priv, plane->i9xx_plane);
-	if (plane->has_fbc) {
-		struct intel_fbc *fbc = &dev_priv->fbc;
-
-		fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
-	}
-
-	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
-		formats = vlv_primary_formats;
-		num_formats = ARRAY_SIZE(vlv_primary_formats);
-	} else if (INTEL_GEN(dev_priv) >= 4) {
-		/*
-		 * WaFP16GammaEnabling:ivb
-		 * "Workaround : When using the 64-bit format, the plane
-		 *  output on each color channel has one quarter amplitude.
-		 *  It can be brought up to full amplitude by using pipe
-		 *  gamma correction or pipe color space conversion to
-		 *  multiply the plane output by four."
-		 *
-		 * There is no dedicated plane gamma for the primary plane,
-		 * and using the pipe gamma/csc could conflict with other
-		 * planes, so we choose not to expose fp16 on IVB primary
-		 * planes. HSW primary planes no longer have this problem.
-		 */
-		if (IS_IVYBRIDGE(dev_priv)) {
-			formats = ivb_primary_formats;
-			num_formats = ARRAY_SIZE(ivb_primary_formats);
-		} else {
-			formats = i965_primary_formats;
-			num_formats = ARRAY_SIZE(i965_primary_formats);
-		}
-	} else {
-		formats = i8xx_primary_formats;
-		num_formats = ARRAY_SIZE(i8xx_primary_formats);
-	}
-
-	if (INTEL_GEN(dev_priv) >= 4)
-		plane_funcs = &i965_plane_funcs;
-	else
-		plane_funcs = &i8xx_plane_funcs;
-
-	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-		plane->min_cdclk = vlv_plane_min_cdclk;
-	else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
-		plane->min_cdclk = hsw_plane_min_cdclk;
-	else if (IS_IVYBRIDGE(dev_priv))
-		plane->min_cdclk = ivb_plane_min_cdclk;
-	else
-		plane->min_cdclk = i9xx_plane_min_cdclk;
-
-	plane->max_stride = i9xx_plane_max_stride;
-	plane->update_plane = i9xx_update_plane;
-	plane->disable_plane = i9xx_disable_plane;
-	plane->get_hw_state = i9xx_plane_get_hw_state;
-	plane->check_plane = i9xx_plane_check;
-
-	if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
-		ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
-					       0, plane_funcs,
-					       formats, num_formats,
-					       i9xx_format_modifiers,
-					       DRM_PLANE_TYPE_PRIMARY,
-					       "primary %c", pipe_name(pipe));
-	else
-		ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
-					       0, plane_funcs,
-					       formats, num_formats,
-					       i9xx_format_modifiers,
-					       DRM_PLANE_TYPE_PRIMARY,
-					       "plane %c",
-					       plane_name(plane->i9xx_plane));
-	if (ret)
-		goto fail;
-
-	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
-		supported_rotations =
-			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
-			DRM_MODE_REFLECT_X;
-	} else if (INTEL_GEN(dev_priv) >= 4) {
-		supported_rotations =
-			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
-	} else {
-		supported_rotations = DRM_MODE_ROTATE_0;
-	}
-
-	if (INTEL_GEN(dev_priv) >= 4)
-		drm_plane_create_rotation_property(&plane->base,
-						   DRM_MODE_ROTATE_0,
-						   supported_rotations);
-
-	zpos = 0;
-	drm_plane_create_zpos_immutable_property(&plane->base, zpos);
-
-	drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
-
-	return plane;
-
-fail:
-	intel_plane_free(plane);
-
-	return ERR_PTR(ret);
-}
-
-static int intel_crtc_late_register(struct drm_crtc *crtc)
-{
-	intel_crtc_debugfs_add(crtc);
-	return 0;
-}
-
-#define INTEL_CRTC_FUNCS \
-	.gamma_set = drm_atomic_helper_legacy_gamma_set, \
-	.set_config = drm_atomic_helper_set_config, \
-	.destroy = intel_crtc_destroy, \
-	.page_flip = drm_atomic_helper_page_flip, \
-	.atomic_duplicate_state = intel_crtc_duplicate_state, \
-	.atomic_destroy_state = intel_crtc_destroy_state, \
-	.set_crc_source = intel_crtc_set_crc_source, \
-	.verify_crc_source = intel_crtc_verify_crc_source, \
-	.get_crc_sources = intel_crtc_get_crc_sources, \
-	.late_register = intel_crtc_late_register
-
-static const struct drm_crtc_funcs bdw_crtc_funcs = {
-	INTEL_CRTC_FUNCS,
-
-	.get_vblank_counter = g4x_get_vblank_counter,
-	.enable_vblank = bdw_enable_vblank,
-	.disable_vblank = bdw_disable_vblank,
-	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
-};
-
-static const struct drm_crtc_funcs ilk_crtc_funcs = {
-	INTEL_CRTC_FUNCS,
-
-	.get_vblank_counter = g4x_get_vblank_counter,
-	.enable_vblank = ilk_enable_vblank,
-	.disable_vblank = ilk_disable_vblank,
-	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
-};
-
-static const struct drm_crtc_funcs g4x_crtc_funcs = {
-	INTEL_CRTC_FUNCS,
-
-	.get_vblank_counter = g4x_get_vblank_counter,
-	.enable_vblank = i965_enable_vblank,
-	.disable_vblank = i965_disable_vblank,
-	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
-};
-
-static const struct drm_crtc_funcs i965_crtc_funcs = {
-	INTEL_CRTC_FUNCS,
-
-	.get_vblank_counter = i915_get_vblank_counter,
-	.enable_vblank = i965_enable_vblank,
-	.disable_vblank = i965_disable_vblank,
-	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
-};
-
-static const struct drm_crtc_funcs i915gm_crtc_funcs = {
-	INTEL_CRTC_FUNCS,
-
-	.get_vblank_counter = i915_get_vblank_counter,
-	.enable_vblank = i915gm_enable_vblank,
-	.disable_vblank = i915gm_disable_vblank,
-	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
-};
-
-static const struct drm_crtc_funcs i915_crtc_funcs = {
-	INTEL_CRTC_FUNCS,
-
-	.get_vblank_counter = i915_get_vblank_counter,
-	.enable_vblank = i8xx_enable_vblank,
-	.disable_vblank = i8xx_disable_vblank,
-	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
-};
-
-static const struct drm_crtc_funcs i8xx_crtc_funcs = {
-	INTEL_CRTC_FUNCS,
-
-	/* no hw vblank counter */
-	.enable_vblank = i8xx_enable_vblank,
-	.disable_vblank = i8xx_disable_vblank,
-	.get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
-};
-
-static struct intel_crtc *intel_crtc_alloc(void)
-{
-	struct intel_crtc_state *crtc_state;
-	struct intel_crtc *crtc;
-
-	crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
-	if (!crtc)
-		return ERR_PTR(-ENOMEM);
-
-	crtc_state = intel_crtc_state_alloc(crtc);
-	if (!crtc_state) {
-		kfree(crtc);
-		return ERR_PTR(-ENOMEM);
-	}
-
-	crtc->base.state = &crtc_state->uapi;
-	crtc->config = crtc_state;
-
-	return crtc;
-}
-
-static void intel_crtc_free(struct intel_crtc *crtc)
-{
-	intel_crtc_destroy_state(&crtc->base, crtc->base.state);
-	kfree(crtc);
-}
-
 static void intel_plane_possible_crtcs_init(struct drm_i915_private *dev_priv)
 {
 	struct intel_plane *plane;
@@ -16602,100 +15764,6 @@ static void intel_plane_possible_crtcs_init(struct drm_i915_private *dev_priv)
 	}
 }
 
-static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
-{
-	struct intel_plane *primary, *cursor;
-	const struct drm_crtc_funcs *funcs;
-	struct intel_crtc *crtc;
-	int sprite, ret;
-
-	crtc = intel_crtc_alloc();
-	if (IS_ERR(crtc))
-		return PTR_ERR(crtc);
-
-	crtc->pipe = pipe;
-	crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe];
-
-	primary = intel_primary_plane_create(dev_priv, pipe);
-	if (IS_ERR(primary)) {
-		ret = PTR_ERR(primary);
-		goto fail;
-	}
-	crtc->plane_ids_mask |= BIT(primary->id);
-
-	for_each_sprite(dev_priv, pipe, sprite) {
-		struct intel_plane *plane;
-
-		plane = intel_sprite_plane_create(dev_priv, pipe, sprite);
-		if (IS_ERR(plane)) {
-			ret = PTR_ERR(plane);
-			goto fail;
-		}
-		crtc->plane_ids_mask |= BIT(plane->id);
-	}
-
-	cursor = intel_cursor_plane_create(dev_priv, pipe);
-	if (IS_ERR(cursor)) {
-		ret = PTR_ERR(cursor);
-		goto fail;
-	}
-	crtc->plane_ids_mask |= BIT(cursor->id);
-
-	if (HAS_GMCH(dev_priv)) {
-		if (IS_CHERRYVIEW(dev_priv) ||
-		    IS_VALLEYVIEW(dev_priv) || IS_G4X(dev_priv))
-			funcs = &g4x_crtc_funcs;
-		else if (IS_GEN(dev_priv, 4))
-			funcs = &i965_crtc_funcs;
-		else if (IS_I945GM(dev_priv) || IS_I915GM(dev_priv))
-			funcs = &i915gm_crtc_funcs;
-		else if (IS_GEN(dev_priv, 3))
-			funcs = &i915_crtc_funcs;
-		else
-			funcs = &i8xx_crtc_funcs;
-	} else {
-		if (INTEL_GEN(dev_priv) >= 8)
-			funcs = &bdw_crtc_funcs;
-		else
-			funcs = &ilk_crtc_funcs;
-	}
-
-	ret = drm_crtc_init_with_planes(&dev_priv->drm, &crtc->base,
-					&primary->base, &cursor->base,
-					funcs, "pipe %c", pipe_name(pipe));
-	if (ret)
-		goto fail;
-
-	BUG_ON(pipe >= ARRAY_SIZE(dev_priv->pipe_to_crtc_mapping) ||
-	       dev_priv->pipe_to_crtc_mapping[pipe] != NULL);
-	dev_priv->pipe_to_crtc_mapping[pipe] = crtc;
-
-	if (INTEL_GEN(dev_priv) < 9) {
-		enum i9xx_plane_id i9xx_plane = primary->i9xx_plane;
-
-		BUG_ON(i9xx_plane >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
-		       dev_priv->plane_to_crtc_mapping[i9xx_plane] != NULL);
-		dev_priv->plane_to_crtc_mapping[i9xx_plane] = crtc;
-	}
-
-	if (INTEL_GEN(dev_priv) >= 10)
-		drm_crtc_create_scaling_filter_property(&crtc->base,
-						BIT(DRM_SCALING_FILTER_DEFAULT) |
-						BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
-
-	intel_color_init(crtc);
-
-	intel_crtc_crc_init(crtc);
-
-	drm_WARN_ON(&dev_priv->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
-
-	return 0;
-
-fail:
-	intel_crtc_free(crtc);
-
-	return ret;
-}
 
 int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
 				      struct drm_file *file)
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index f0a5bf69656f..0eba91d18e96 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -659,6 +659,13 @@ struct intel_plane *
 intel_cursor_plane_create(struct drm_i915_private *dev_priv,
 			  enum pipe pipe);
 
+/* crtc */
+u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state);
+int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe);
+struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc);
+void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
+			    struct intel_crtc *crtc);
+
 /* modesetting */
 void intel_modeset_init_hw(struct drm_i915_private *i915);
 int intel_modeset_init_noirq(struct drm_i915_private *i915);
-- 
2.27.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Intel-gfx] [PATCH 3/4] drm/i915: refactor pll code out into intel_clock.c
  2020-12-09  4:21 [Intel-gfx] [rfc] start slimming down intel_display.c Dave Airlie
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 1/4] drm/i915: refactor cursor code out of i915_display.c Dave Airlie
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 2/4] drm/i915: refactor some crtc code out of intel display Dave Airlie
@ 2020-12-09  4:21 ` Dave Airlie
  2020-12-09 10:55   ` Daniel Vetter
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 4/4] drm/i915: split fdi code out from intel_display.c Dave Airlie
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Dave Airlie @ 2020-12-09  4:21 UTC (permalink / raw)
  To: intel-gfx

From: Dave Airlie <airlied@redhat.com>

This pulls a large chunk of the pll calculation code out of
intel_display.c to a new file.

One function makse sense to be an inline, otherwise this
is pretty much a straight copy cover. also all the
remaining hooks for g45 and older end up the same now.

Fixed one , instead of ; error in chv_find_best_dpll.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/i915/Makefile                 |    1 +
 drivers/gpu/drm/i915/display/intel_clock.c    | 1370 ++++++++++++++++
 drivers/gpu/drm/i915/display/intel_display.c  | 1392 +----------------
 drivers/gpu/drm/i915/display/intel_display.h  |   13 +-
 .../drm/i915/display/intel_display_types.h    |    5 +
 5 files changed, 1398 insertions(+), 1383 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/display/intel_clock.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index ffec257702af..8b357c212ae2 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -193,6 +193,7 @@ i915-y += \
 	display/intel_bios.o \
 	display/intel_bw.o \
 	display/intel_cdclk.o \
+	display/intel_clock.o \
 	display/intel_color.o \
 	display/intel_combo_phy.o \
 	display/intel_connector.o \
diff --git a/drivers/gpu/drm/i915/display/intel_clock.c b/drivers/gpu/drm/i915/display/intel_clock.c
new file mode 100644
index 000000000000..75819c1da039
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_clock.c
@@ -0,0 +1,1370 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+#include <linux/kernel.h>
+#include "intel_display_types.h"
+#include "intel_display.h"
+#include "intel_lvds.h"
+#include "intel_panel.h"
+
+static bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
+{
+	if (dev_priv->params.panel_use_ssc >= 0)
+		return dev_priv->params.panel_use_ssc != 0;
+	return dev_priv->vbt.lvds_use_ssc
+		&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
+}
+
+struct intel_limit {
+	struct {
+		int min, max;
+	} dot, vco, n, m, m1, m2, p, p1;
+
+	struct {
+		int dot_limit;
+		int p2_slow, p2_fast;
+	} p2;
+};
+static const struct intel_limit intel_limits_i8xx_dac = {
+	.dot = { .min = 25000, .max = 350000 },
+	.vco = { .min = 908000, .max = 1512000 },
+	.n = { .min = 2, .max = 16 },
+	.m = { .min = 96, .max = 140 },
+	.m1 = { .min = 18, .max = 26 },
+	.m2 = { .min = 6, .max = 16 },
+	.p = { .min = 4, .max = 128 },
+	.p1 = { .min = 2, .max = 33 },
+	.p2 = { .dot_limit = 165000,
+		.p2_slow = 4, .p2_fast = 2 },
+};
+
+static const struct intel_limit intel_limits_i8xx_dvo = {
+	.dot = { .min = 25000, .max = 350000 },
+	.vco = { .min = 908000, .max = 1512000 },
+	.n = { .min = 2, .max = 16 },
+	.m = { .min = 96, .max = 140 },
+	.m1 = { .min = 18, .max = 26 },
+	.m2 = { .min = 6, .max = 16 },
+	.p = { .min = 4, .max = 128 },
+	.p1 = { .min = 2, .max = 33 },
+	.p2 = { .dot_limit = 165000,
+		.p2_slow = 4, .p2_fast = 4 },
+};
+
+static const struct intel_limit intel_limits_i8xx_lvds = {
+	.dot = { .min = 25000, .max = 350000 },
+	.vco = { .min = 908000, .max = 1512000 },
+	.n = { .min = 2, .max = 16 },
+	.m = { .min = 96, .max = 140 },
+	.m1 = { .min = 18, .max = 26 },
+	.m2 = { .min = 6, .max = 16 },
+	.p = { .min = 4, .max = 128 },
+	.p1 = { .min = 1, .max = 6 },
+	.p2 = { .dot_limit = 165000,
+		.p2_slow = 14, .p2_fast = 7 },
+};
+
+static const struct intel_limit intel_limits_i9xx_sdvo = {
+	.dot = { .min = 20000, .max = 400000 },
+	.vco = { .min = 1400000, .max = 2800000 },
+	.n = { .min = 1, .max = 6 },
+	.m = { .min = 70, .max = 120 },
+	.m1 = { .min = 8, .max = 18 },
+	.m2 = { .min = 3, .max = 7 },
+	.p = { .min = 5, .max = 80 },
+	.p1 = { .min = 1, .max = 8 },
+	.p2 = { .dot_limit = 200000,
+		.p2_slow = 10, .p2_fast = 5 },
+};
+
+static const struct intel_limit intel_limits_i9xx_lvds = {
+	.dot = { .min = 20000, .max = 400000 },
+	.vco = { .min = 1400000, .max = 2800000 },
+	.n = { .min = 1, .max = 6 },
+	.m = { .min = 70, .max = 120 },
+	.m1 = { .min = 8, .max = 18 },
+	.m2 = { .min = 3, .max = 7 },
+	.p = { .min = 7, .max = 98 },
+	.p1 = { .min = 1, .max = 8 },
+	.p2 = { .dot_limit = 112000,
+		.p2_slow = 14, .p2_fast = 7 },
+};
+
+
+static const struct intel_limit intel_limits_g4x_sdvo = {
+	.dot = { .min = 25000, .max = 270000 },
+	.vco = { .min = 1750000, .max = 3500000},
+	.n = { .min = 1, .max = 4 },
+	.m = { .min = 104, .max = 138 },
+	.m1 = { .min = 17, .max = 23 },
+	.m2 = { .min = 5, .max = 11 },
+	.p = { .min = 10, .max = 30 },
+	.p1 = { .min = 1, .max = 3},
+	.p2 = { .dot_limit = 270000,
+		.p2_slow = 10,
+		.p2_fast = 10
+	},
+};
+
+static const struct intel_limit intel_limits_g4x_hdmi = {
+	.dot = { .min = 22000, .max = 400000 },
+	.vco = { .min = 1750000, .max = 3500000},
+	.n = { .min = 1, .max = 4 },
+	.m = { .min = 104, .max = 138 },
+	.m1 = { .min = 16, .max = 23 },
+	.m2 = { .min = 5, .max = 11 },
+	.p = { .min = 5, .max = 80 },
+	.p1 = { .min = 1, .max = 8},
+	.p2 = { .dot_limit = 165000,
+		.p2_slow = 10, .p2_fast = 5 },
+};
+
+static const struct intel_limit intel_limits_g4x_single_channel_lvds = {
+	.dot = { .min = 20000, .max = 115000 },
+	.vco = { .min = 1750000, .max = 3500000 },
+	.n = { .min = 1, .max = 3 },
+	.m = { .min = 104, .max = 138 },
+	.m1 = { .min = 17, .max = 23 },
+	.m2 = { .min = 5, .max = 11 },
+	.p = { .min = 28, .max = 112 },
+	.p1 = { .min = 2, .max = 8 },
+	.p2 = { .dot_limit = 0,
+		.p2_slow = 14, .p2_fast = 14
+	},
+};
+
+static const struct intel_limit intel_limits_g4x_dual_channel_lvds = {
+	.dot = { .min = 80000, .max = 224000 },
+	.vco = { .min = 1750000, .max = 3500000 },
+	.n = { .min = 1, .max = 3 },
+	.m = { .min = 104, .max = 138 },
+	.m1 = { .min = 17, .max = 23 },
+	.m2 = { .min = 5, .max = 11 },
+	.p = { .min = 14, .max = 42 },
+	.p1 = { .min = 2, .max = 6 },
+	.p2 = { .dot_limit = 0,
+		.p2_slow = 7, .p2_fast = 7
+	},
+};
+
+static const struct intel_limit pnv_limits_sdvo = {
+	.dot = { .min = 20000, .max = 400000},
+	.vco = { .min = 1700000, .max = 3500000 },
+	/* Pineview's Ncounter is a ring counter */
+	.n = { .min = 3, .max = 6 },
+	.m = { .min = 2, .max = 256 },
+	/* Pineview only has one combined m divider, which we treat as m2. */
+	.m1 = { .min = 0, .max = 0 },
+	.m2 = { .min = 0, .max = 254 },
+	.p = { .min = 5, .max = 80 },
+	.p1 = { .min = 1, .max = 8 },
+	.p2 = { .dot_limit = 200000,
+		.p2_slow = 10, .p2_fast = 5 },
+};
+
+static const struct intel_limit pnv_limits_lvds = {
+	.dot = { .min = 20000, .max = 400000 },
+	.vco = { .min = 1700000, .max = 3500000 },
+	.n = { .min = 3, .max = 6 },
+	.m = { .min = 2, .max = 256 },
+	.m1 = { .min = 0, .max = 0 },
+	.m2 = { .min = 0, .max = 254 },
+	.p = { .min = 7, .max = 112 },
+	.p1 = { .min = 1, .max = 8 },
+	.p2 = { .dot_limit = 112000,
+		.p2_slow = 14, .p2_fast = 14 },
+};
+
+/* Ironlake / Sandybridge
+ *
+ * We calculate clock using (register_value + 2) for N/M1/M2, so here
+ * the range value for them is (actual_value - 2).
+ */
+static const struct intel_limit ilk_limits_dac = {
+	.dot = { .min = 25000, .max = 350000 },
+	.vco = { .min = 1760000, .max = 3510000 },
+	.n = { .min = 1, .max = 5 },
+	.m = { .min = 79, .max = 127 },
+	.m1 = { .min = 12, .max = 22 },
+	.m2 = { .min = 5, .max = 9 },
+	.p = { .min = 5, .max = 80 },
+	.p1 = { .min = 1, .max = 8 },
+	.p2 = { .dot_limit = 225000,
+		.p2_slow = 10, .p2_fast = 5 },
+};
+
+static const struct intel_limit ilk_limits_single_lvds = {
+	.dot = { .min = 25000, .max = 350000 },
+	.vco = { .min = 1760000, .max = 3510000 },
+	.n = { .min = 1, .max = 3 },
+	.m = { .min = 79, .max = 118 },
+	.m1 = { .min = 12, .max = 22 },
+	.m2 = { .min = 5, .max = 9 },
+	.p = { .min = 28, .max = 112 },
+	.p1 = { .min = 2, .max = 8 },
+	.p2 = { .dot_limit = 225000,
+		.p2_slow = 14, .p2_fast = 14 },
+};
+
+static const struct intel_limit ilk_limits_dual_lvds = {
+	.dot = { .min = 25000, .max = 350000 },
+	.vco = { .min = 1760000, .max = 3510000 },
+	.n = { .min = 1, .max = 3 },
+	.m = { .min = 79, .max = 127 },
+	.m1 = { .min = 12, .max = 22 },
+	.m2 = { .min = 5, .max = 9 },
+	.p = { .min = 14, .max = 56 },
+	.p1 = { .min = 2, .max = 8 },
+	.p2 = { .dot_limit = 225000,
+		.p2_slow = 7, .p2_fast = 7 },
+};
+
+/* LVDS 100mhz refclk limits. */
+static const struct intel_limit ilk_limits_single_lvds_100m = {
+	.dot = { .min = 25000, .max = 350000 },
+	.vco = { .min = 1760000, .max = 3510000 },
+	.n = { .min = 1, .max = 2 },
+	.m = { .min = 79, .max = 126 },
+	.m1 = { .min = 12, .max = 22 },
+	.m2 = { .min = 5, .max = 9 },
+	.p = { .min = 28, .max = 112 },
+	.p1 = { .min = 2, .max = 8 },
+	.p2 = { .dot_limit = 225000,
+		.p2_slow = 14, .p2_fast = 14 },
+};
+
+static const struct intel_limit ilk_limits_dual_lvds_100m = {
+	.dot = { .min = 25000, .max = 350000 },
+	.vco = { .min = 1760000, .max = 3510000 },
+	.n = { .min = 1, .max = 3 },
+	.m = { .min = 79, .max = 126 },
+	.m1 = { .min = 12, .max = 22 },
+	.m2 = { .min = 5, .max = 9 },
+	.p = { .min = 14, .max = 42 },
+	.p1 = { .min = 2, .max = 6 },
+	.p2 = { .dot_limit = 225000,
+		.p2_slow = 7, .p2_fast = 7 },
+};
+
+static const struct intel_limit intel_limits_vlv = {
+	 /*
+	  * These are the data rate limits (measured in fast clocks)
+	  * since those are the strictest limits we have. The fast
+	  * clock and actual rate limits are more relaxed, so checking
+	  * them would make no difference.
+	  */
+	.dot = { .min = 25000 * 5, .max = 270000 * 5 },
+	.vco = { .min = 4000000, .max = 6000000 },
+	.n = { .min = 1, .max = 7 },
+	.m1 = { .min = 2, .max = 3 },
+	.m2 = { .min = 11, .max = 156 },
+	.p1 = { .min = 2, .max = 3 },
+	.p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */
+};
+
+static const struct intel_limit intel_limits_chv = {
+	/*
+	 * These are the data rate limits (measured in fast clocks)
+	 * since those are the strictest limits we have.  The fast
+	 * clock and actual rate limits are more relaxed, so checking
+	 * them would make no difference.
+	 */
+	.dot = { .min = 25000 * 5, .max = 540000 * 5},
+	.vco = { .min = 4800000, .max = 6480000 },
+	.n = { .min = 1, .max = 1 },
+	.m1 = { .min = 2, .max = 2 },
+	.m2 = { .min = 24 << 22, .max = 175 << 22 },
+	.p1 = { .min = 2, .max = 4 },
+	.p2 = {	.p2_slow = 1, .p2_fast = 14 },
+};
+
+static const struct intel_limit intel_limits_bxt = {
+	/* FIXME: find real dot limits */
+	.dot = { .min = 0, .max = INT_MAX },
+	.vco = { .min = 4800000, .max = 6700000 },
+	.n = { .min = 1, .max = 1 },
+	.m1 = { .min = 2, .max = 2 },
+	/* FIXME: find real m2 limits */
+	.m2 = { .min = 2 << 22, .max = 255 << 22 },
+	.p1 = { .min = 2, .max = 4 },
+	.p2 = { .p2_slow = 1, .p2_fast = 20 },
+};
+
+/*
+ * Platform specific helpers to calculate the port PLL loopback- (clock.m),
+ * and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast
+ * (clock.dot) clock rates. This fast dot clock is fed to the port's IO logic.
+ * The helpers' return value is the rate of the clock that is fed to the
+ * display engine's pipe which can be the above fast dot clock rate or a
+ * divided-down version of it.
+ */
+/* m1 is reserved as 0 in Pineview, n is a ring counter */
+int pnv_calc_dpll_params(int refclk, struct dpll *clock)
+{
+	clock->m = clock->m2 + 2;
+	clock->p = clock->p1 * clock->p2;
+	if (WARN_ON(clock->n == 0 || clock->p == 0))
+		return 0;
+	clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
+	clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
+
+	return clock->dot;
+}
+
+static u32 i9xx_dpll_compute_m(struct dpll *dpll)
+{
+	return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
+}
+
+int i9xx_calc_dpll_params(int refclk, struct dpll *clock)
+{
+	clock->m = i9xx_dpll_compute_m(clock);
+	clock->p = clock->p1 * clock->p2;
+	if (WARN_ON(clock->n + 2 == 0 || clock->p == 0))
+		return 0;
+	clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2);
+	clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
+
+	return clock->dot;
+}
+
+int vlv_calc_dpll_params(int refclk, struct dpll *clock)
+{
+	clock->m = clock->m1 * clock->m2;
+	clock->p = clock->p1 * clock->p2;
+	if (WARN_ON(clock->n == 0 || clock->p == 0))
+		return 0;
+	clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
+	clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
+
+	return clock->dot / 5;
+}
+
+int chv_calc_dpll_params(int refclk, struct dpll *clock)
+{
+	clock->m = clock->m1 * clock->m2;
+	clock->p = clock->p1 * clock->p2;
+	if (WARN_ON(clock->n == 0 || clock->p == 0))
+		return 0;
+	clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
+					   clock->n << 22);
+	clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
+
+	return clock->dot / 5;
+}
+
+/*
+ * Returns whether the given set of divisors are valid for a given refclk with
+ * the given connectors.
+ */
+static bool intel_pll_is_valid(struct drm_i915_private *dev_priv,
+			       const struct intel_limit *limit,
+			       const struct dpll *clock)
+{
+	if (clock->n < limit->n.min || limit->n.max < clock->n)
+		return false;
+	if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
+		return false;
+	if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2)
+		return false;
+	if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
+		return false;
+
+	if (!IS_PINEVIEW(dev_priv) && !IS_VALLEYVIEW(dev_priv) &&
+	    !IS_CHERRYVIEW(dev_priv) && !IS_GEN9_LP(dev_priv))
+		if (clock->m1 <= clock->m2)
+			return false;
+
+	if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
+	    !IS_GEN9_LP(dev_priv)) {
+		if (clock->p < limit->p.min || limit->p.max < clock->p)
+			return false;
+		if (clock->m < limit->m.min || limit->m.max < clock->m)
+			return false;
+	}
+
+	if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
+		return false;
+	/* XXX: We may need to be checking "Dot clock" depending on the multiplier,
+	 * connector, etc., rather than just a single range.
+	 */
+	if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
+		return false;
+
+	return true;
+}
+
+static int
+i9xx_select_p2_div(const struct intel_limit *limit,
+		   const struct intel_crtc_state *crtc_state,
+		   int target)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+		/*
+		 * For LVDS just rely on its current settings for dual-channel.
+		 * We haven't figured out how to reliably set up different
+		 * single/dual channel state, if we even can.
+		 */
+		if (intel_is_dual_link_lvds(dev_priv))
+			return limit->p2.p2_fast;
+		else
+			return limit->p2.p2_slow;
+	} else {
+		if (target < limit->p2.dot_limit)
+			return limit->p2.p2_slow;
+		else
+			return limit->p2.p2_fast;
+	}
+}
+
+/*
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE.  The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ *
+ * Target and reference clocks are specified in kHz.
+ *
+ * If match_clock is provided, then best_clock P divider must match the P
+ * divider from @match_clock used for LVDS downclocking.
+ */
+static bool
+i9xx_find_best_dpll(const struct intel_limit *limit,
+		    struct intel_crtc_state *crtc_state,
+		    int target, int refclk, struct dpll *match_clock,
+		    struct dpll *best_clock)
+{
+	struct drm_device *dev = crtc_state->uapi.crtc->dev;
+	struct dpll clock;
+	int err = target;
+
+	memset(best_clock, 0, sizeof(*best_clock));
+
+	clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
+
+	for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
+	     clock.m1++) {
+		for (clock.m2 = limit->m2.min;
+		     clock.m2 <= limit->m2.max; clock.m2++) {
+			if (clock.m2 >= clock.m1)
+				break;
+			for (clock.n = limit->n.min;
+			     clock.n <= limit->n.max; clock.n++) {
+				for (clock.p1 = limit->p1.min;
+					clock.p1 <= limit->p1.max; clock.p1++) {
+					int this_err;
+
+					i9xx_calc_dpll_params(refclk, &clock);
+					if (!intel_pll_is_valid(to_i915(dev),
+								limit,
+								&clock))
+						continue;
+					if (match_clock &&
+					    clock.p != match_clock->p)
+						continue;
+
+					this_err = abs(clock.dot - target);
+					if (this_err < err) {
+						*best_clock = clock;
+						err = this_err;
+					}
+				}
+			}
+		}
+	}
+
+	return (err != target);
+}
+
+/*
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE.  The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ *
+ * Target and reference clocks are specified in kHz.
+ *
+ * If match_clock is provided, then best_clock P divider must match the P
+ * divider from @match_clock used for LVDS downclocking.
+ */
+static bool
+pnv_find_best_dpll(const struct intel_limit *limit,
+		   struct intel_crtc_state *crtc_state,
+		   int target, int refclk, struct dpll *match_clock,
+		   struct dpll *best_clock)
+{
+	struct drm_device *dev = crtc_state->uapi.crtc->dev;
+	struct dpll clock;
+	int err = target;
+
+	memset(best_clock, 0, sizeof(*best_clock));
+
+	clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
+
+	for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
+	     clock.m1++) {
+		for (clock.m2 = limit->m2.min;
+		     clock.m2 <= limit->m2.max; clock.m2++) {
+			for (clock.n = limit->n.min;
+			     clock.n <= limit->n.max; clock.n++) {
+				for (clock.p1 = limit->p1.min;
+					clock.p1 <= limit->p1.max; clock.p1++) {
+					int this_err;
+
+					pnv_calc_dpll_params(refclk, &clock);
+					if (!intel_pll_is_valid(to_i915(dev),
+								limit,
+								&clock))
+						continue;
+					if (match_clock &&
+					    clock.p != match_clock->p)
+						continue;
+
+					this_err = abs(clock.dot - target);
+					if (this_err < err) {
+						*best_clock = clock;
+						err = this_err;
+					}
+				}
+			}
+		}
+	}
+
+	return (err != target);
+}
+
+/*
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE.  The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ *
+ * Target and reference clocks are specified in kHz.
+ *
+ * If match_clock is provided, then best_clock P divider must match the P
+ * divider from @match_clock used for LVDS downclocking.
+ */
+static bool
+g4x_find_best_dpll(const struct intel_limit *limit,
+		   struct intel_crtc_state *crtc_state,
+		   int target, int refclk, struct dpll *match_clock,
+		   struct dpll *best_clock)
+{
+	struct drm_device *dev = crtc_state->uapi.crtc->dev;
+	struct dpll clock;
+	int max_n;
+	bool found = false;
+	/* approximately equals target * 0.00585 */
+	int err_most = (target >> 8) + (target >> 9);
+
+	memset(best_clock, 0, sizeof(*best_clock));
+
+	clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
+
+	max_n = limit->n.max;
+	/* based on hardware requirement, prefer smaller n to precision */
+	for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
+		/* based on hardware requirement, prefere larger m1,m2 */
+		for (clock.m1 = limit->m1.max;
+		     clock.m1 >= limit->m1.min; clock.m1--) {
+			for (clock.m2 = limit->m2.max;
+			     clock.m2 >= limit->m2.min; clock.m2--) {
+				for (clock.p1 = limit->p1.max;
+				     clock.p1 >= limit->p1.min; clock.p1--) {
+					int this_err;
+
+					i9xx_calc_dpll_params(refclk, &clock);
+					if (!intel_pll_is_valid(to_i915(dev),
+								limit,
+								&clock))
+						continue;
+
+					this_err = abs(clock.dot - target);
+					if (this_err < err_most) {
+						*best_clock = clock;
+						err_most = this_err;
+						max_n = clock.n;
+						found = true;
+					}
+				}
+			}
+		}
+	}
+	return found;
+}
+
+/*
+ * Check if the calculated PLL configuration is more optimal compared to the
+ * best configuration and error found so far. Return the calculated error.
+ */
+static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
+			       const struct dpll *calculated_clock,
+			       const struct dpll *best_clock,
+			       unsigned int best_error_ppm,
+			       unsigned int *error_ppm)
+{
+	/*
+	 * For CHV ignore the error and consider only the P value.
+	 * Prefer a bigger P value based on HW requirements.
+	 */
+	if (IS_CHERRYVIEW(to_i915(dev))) {
+		*error_ppm = 0;
+
+		return calculated_clock->p > best_clock->p;
+	}
+
+	if (drm_WARN_ON_ONCE(dev, !target_freq))
+		return false;
+
+	*error_ppm = div_u64(1000000ULL *
+				abs(target_freq - calculated_clock->dot),
+			     target_freq);
+	/*
+	 * Prefer a better P value over a better (smaller) error if the error
+	 * is small. Ensure this preference for future configurations too by
+	 * setting the error to 0.
+	 */
+	if (*error_ppm < 100 && calculated_clock->p > best_clock->p) {
+		*error_ppm = 0;
+
+		return true;
+	}
+
+	return *error_ppm + 10 < best_error_ppm;
+}
+
+/*
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE.  The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ */
+static bool
+vlv_find_best_dpll(const struct intel_limit *limit,
+		   struct intel_crtc_state *crtc_state,
+		   int target, int refclk, struct dpll *match_clock,
+		   struct dpll *best_clock)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+	struct drm_device *dev = crtc->base.dev;
+	struct dpll clock;
+	unsigned int bestppm = 1000000;
+	/* min update 19.2 MHz */
+	int max_n = min(limit->n.max, refclk / 19200);
+	bool found = false;
+
+	target *= 5; /* fast clock */
+
+	memset(best_clock, 0, sizeof(*best_clock));
+
+	/* based on hardware requirement, prefer smaller n to precision */
+	for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
+		for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
+			for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow;
+			     clock.p2 -= clock.p2 > 10 ? 2 : 1) {
+				clock.p = clock.p1 * clock.p2;
+				/* based on hardware requirement, prefer bigger m1,m2 values */
+				for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
+					unsigned int ppm;
+
+					clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n,
+								     refclk * clock.m1);
+
+					vlv_calc_dpll_params(refclk, &clock);
+
+					if (!intel_pll_is_valid(to_i915(dev),
+								limit,
+								&clock))
+						continue;
+
+					if (!vlv_PLL_is_optimal(dev, target,
+								&clock,
+								best_clock,
+								bestppm, &ppm))
+						continue;
+
+					*best_clock = clock;
+					bestppm = ppm;
+					found = true;
+				}
+			}
+		}
+	}
+
+	return found;
+}
+
+/*
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE.  The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ */
+static bool
+chv_find_best_dpll(const struct intel_limit *limit,
+		   struct intel_crtc_state *crtc_state,
+		   int target, int refclk, struct dpll *match_clock,
+		   struct dpll *best_clock)
+{
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+	struct drm_device *dev = crtc->base.dev;
+	unsigned int best_error_ppm;
+	struct dpll clock;
+	u64 m2;
+	int found = false;
+
+	memset(best_clock, 0, sizeof(*best_clock));
+	best_error_ppm = 1000000;
+
+	/*
+	 * Based on hardware doc, the n always set to 1, and m1 always
+	 * set to 2.  If requires to support 200Mhz refclk, we need to
+	 * revisit this because n may not 1 anymore.
+	 */
+	clock.n = 1;
+	clock.m1 = 2;
+	target *= 5;	/* fast clock */
+
+	for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
+		for (clock.p2 = limit->p2.p2_fast;
+				clock.p2 >= limit->p2.p2_slow;
+				clock.p2 -= clock.p2 > 10 ? 2 : 1) {
+			unsigned int error_ppm;
+
+			clock.p = clock.p1 * clock.p2;
+
+			m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
+						   refclk * clock.m1);
+
+			if (m2 > INT_MAX/clock.m1)
+				continue;
+
+			clock.m2 = m2;
+
+			chv_calc_dpll_params(refclk, &clock);
+
+			if (!intel_pll_is_valid(to_i915(dev), limit, &clock))
+				continue;
+
+			if (!vlv_PLL_is_optimal(dev, target, &clock, best_clock,
+						best_error_ppm, &error_ppm))
+				continue;
+
+			*best_clock = clock;
+			best_error_ppm = error_ppm;
+			found = true;
+		}
+	}
+
+	return found;
+}
+
+bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
+			struct dpll *best_clock)
+{
+	int refclk = 100000;
+	const struct intel_limit *limit = &intel_limits_bxt;
+
+	return chv_find_best_dpll(limit, crtc_state,
+				  crtc_state->port_clock, refclk,
+				  NULL, best_clock);
+}
+
+static u32 pnv_dpll_compute_fp(struct dpll *dpll)
+{
+	return (1 << dpll->n) << 16 | dpll->m2;
+}
+
+static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
+				     struct intel_crtc_state *crtc_state,
+				     struct dpll *reduced_clock)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	u32 fp, fp2 = 0;
+
+	if (IS_PINEVIEW(dev_priv)) {
+		fp = pnv_dpll_compute_fp(&crtc_state->dpll);
+		if (reduced_clock)
+			fp2 = pnv_dpll_compute_fp(reduced_clock);
+	} else {
+		fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
+		if (reduced_clock)
+			fp2 = i9xx_dpll_compute_fp(reduced_clock);
+	}
+
+	crtc_state->dpll_hw_state.fp0 = fp;
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
+	    reduced_clock) {
+		crtc_state->dpll_hw_state.fp1 = fp2;
+	} else {
+		crtc_state->dpll_hw_state.fp1 = fp;
+	}
+}
+
+static void i9xx_compute_dpll(struct intel_crtc *crtc,
+			      struct intel_crtc_state *crtc_state,
+			      struct dpll *reduced_clock)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	u32 dpll;
+	struct dpll *clock = &crtc_state->dpll;
+
+	i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
+
+	dpll = DPLL_VGA_MODE_DIS;
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
+		dpll |= DPLLB_MODE_LVDS;
+	else
+		dpll |= DPLLB_MODE_DAC_SERIAL;
+
+	if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
+	    IS_G33(dev_priv) || IS_PINEVIEW(dev_priv)) {
+		dpll |= (crtc_state->pixel_multiplier - 1)
+			<< SDVO_MULTIPLIER_SHIFT_HIRES;
+	}
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
+	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+		dpll |= DPLL_SDVO_HIGH_SPEED;
+
+	if (intel_crtc_has_dp_encoder(crtc_state))
+		dpll |= DPLL_SDVO_HIGH_SPEED;
+
+	/* compute bitmask from p1 value */
+	if (IS_PINEVIEW(dev_priv))
+		dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
+	else {
+		dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+		if (IS_G4X(dev_priv) && reduced_clock)
+			dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+	}
+	switch (clock->p2) {
+	case 5:
+		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+		break;
+	case 7:
+		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+		break;
+	case 10:
+		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+		break;
+	case 14:
+		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+		break;
+	}
+	if (INTEL_GEN(dev_priv) >= 4)
+		dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
+
+	if (crtc_state->sdvo_tv_clock)
+		dpll |= PLL_REF_INPUT_TVCLKINBC;
+	else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
+		 intel_panel_use_ssc(dev_priv))
+		dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+	else
+		dpll |= PLL_REF_INPUT_DREFCLK;
+
+	dpll |= DPLL_VCO_ENABLE;
+	crtc_state->dpll_hw_state.dpll = dpll;
+
+	if (INTEL_GEN(dev_priv) >= 4) {
+		u32 dpll_md = (crtc_state->pixel_multiplier - 1)
+			<< DPLL_MD_UDI_MULTIPLIER_SHIFT;
+		crtc_state->dpll_hw_state.dpll_md = dpll_md;
+	}
+}
+
+static void i8xx_compute_dpll(struct intel_crtc *crtc,
+			      struct intel_crtc_state *crtc_state,
+			      struct dpll *reduced_clock)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	u32 dpll;
+	struct dpll *clock = &crtc_state->dpll;
+
+	i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
+
+	dpll = DPLL_VGA_MODE_DIS;
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+		dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+	} else {
+		if (clock->p1 == 2)
+			dpll |= PLL_P1_DIVIDE_BY_TWO;
+		else
+			dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+		if (clock->p2 == 4)
+			dpll |= PLL_P2_DIVIDE_BY_4;
+	}
+
+	/*
+	 * Bspec:
+	 * "[Almador Errata}: For the correct operation of the muxed DVO pins
+	 *  (GDEVSELB/I2Cdata, GIRDBY/I2CClk) and (GFRAMEB/DVI_Data,
+	 *  GTRDYB/DVI_Clk): Bit 31 (DPLL VCO Enable) and Bit 30 (2X Clock
+	 *  Enable) must be set to “1” in both the DPLL A Control Register
+	 *  (06014h-06017h) and DPLL B Control Register (06018h-0601Bh)."
+	 *
+	 * For simplicity We simply keep both bits always enabled in
+	 * both DPLLS. The spec says we should disable the DVO 2X clock
+	 * when not needed, but this seems to work fine in practice.
+	 */
+	if (IS_I830(dev_priv) ||
+	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO))
+		dpll |= DPLL_DVO_2X_MODE;
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
+	    intel_panel_use_ssc(dev_priv))
+		dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+	else
+		dpll |= PLL_REF_INPUT_DREFCLK;
+
+	dpll |= DPLL_VCO_ENABLE;
+	crtc_state->dpll_hw_state.dpll = dpll;
+}
+
+static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
+				  struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	struct intel_atomic_state *state =
+		to_intel_atomic_state(crtc_state->uapi.state);
+
+	if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) ||
+	    INTEL_GEN(dev_priv) >= 11) {
+		struct intel_encoder *encoder =
+			intel_get_crtc_new_encoder(state, crtc_state);
+
+		if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
+			drm_dbg_kms(&dev_priv->drm,
+				    "failed to find PLL for pipe %c\n",
+				    pipe_name(crtc->pipe));
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static bool ilk_needs_fb_cb_tune(struct dpll *dpll, int factor)
+{
+	return i9xx_dpll_compute_m(dpll) < factor * dpll->n;
+}
+
+
+static void ilk_compute_dpll(struct intel_crtc *crtc,
+			     struct intel_crtc_state *crtc_state,
+			     struct dpll *reduced_clock)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	u32 dpll, fp, fp2;
+	int factor;
+
+	/* Enable autotuning of the PLL clock (if permissible) */
+	factor = 21;
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+		if ((intel_panel_use_ssc(dev_priv) &&
+		     dev_priv->vbt.lvds_ssc_freq == 100000) ||
+		    (HAS_PCH_IBX(dev_priv) &&
+		     intel_is_dual_link_lvds(dev_priv)))
+			factor = 25;
+	} else if (crtc_state->sdvo_tv_clock) {
+		factor = 20;
+	}
+
+	fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
+
+	if (ilk_needs_fb_cb_tune(&crtc_state->dpll, factor))
+		fp |= FP_CB_TUNE;
+
+	if (reduced_clock) {
+		fp2 = i9xx_dpll_compute_fp(reduced_clock);
+
+		if (reduced_clock->m < factor * reduced_clock->n)
+			fp2 |= FP_CB_TUNE;
+	} else {
+		fp2 = fp;
+	}
+
+	dpll = 0;
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
+		dpll |= DPLLB_MODE_LVDS;
+	else
+		dpll |= DPLLB_MODE_DAC_SERIAL;
+
+	dpll |= (crtc_state->pixel_multiplier - 1)
+		<< PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
+	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
+		dpll |= DPLL_SDVO_HIGH_SPEED;
+
+	if (intel_crtc_has_dp_encoder(crtc_state))
+		dpll |= DPLL_SDVO_HIGH_SPEED;
+
+	/*
+	 * The high speed IO clock is only really required for
+	 * SDVO/HDMI/DP, but we also enable it for CRT to make it
+	 * possible to share the DPLL between CRT and HDMI. Enabling
+	 * the clock needlessly does no real harm, except use up a
+	 * bit of power potentially.
+	 *
+	 * We'll limit this to IVB with 3 pipes, since it has only two
+	 * DPLLs and so DPLL sharing is the only way to get three pipes
+	 * driving PCH ports at the same time. On SNB we could do this,
+	 * and potentially avoid enabling the second DPLL, but it's not
+	 * clear if it''s a win or loss power wise. No point in doing
+	 * this on ILK at all since it has a fixed DPLL<->pipe mapping.
+	 */
+	if (INTEL_NUM_PIPES(dev_priv) == 3 &&
+	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
+		dpll |= DPLL_SDVO_HIGH_SPEED;
+
+	/* compute bitmask from p1 value */
+	dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+	/* also FPA1 */
+	dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+
+	switch (crtc_state->dpll.p2) {
+	case 5:
+		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+		break;
+	case 7:
+		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+		break;
+	case 10:
+		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+		break;
+	case 14:
+		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+		break;
+	}
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
+	    intel_panel_use_ssc(dev_priv))
+		dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+	else
+		dpll |= PLL_REF_INPUT_DREFCLK;
+
+	dpll |= DPLL_VCO_ENABLE;
+
+	crtc_state->dpll_hw_state.dpll = dpll;
+	crtc_state->dpll_hw_state.fp0 = fp;
+	crtc_state->dpll_hw_state.fp1 = fp2;
+}
+
+static int ilk_crtc_compute_clock(struct intel_crtc *crtc,
+				  struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	struct intel_atomic_state *state =
+		to_intel_atomic_state(crtc_state->uapi.state);
+	const struct intel_limit *limit;
+	int refclk = 120000;
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
+	/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
+	if (!crtc_state->has_pch_encoder)
+		return 0;
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+		if (intel_panel_use_ssc(dev_priv)) {
+			drm_dbg_kms(&dev_priv->drm,
+				    "using SSC reference clock of %d kHz\n",
+				    dev_priv->vbt.lvds_ssc_freq);
+			refclk = dev_priv->vbt.lvds_ssc_freq;
+		}
+
+		if (intel_is_dual_link_lvds(dev_priv)) {
+			if (refclk == 100000)
+				limit = &ilk_limits_dual_lvds_100m;
+			else
+				limit = &ilk_limits_dual_lvds;
+		} else {
+			if (refclk == 100000)
+				limit = &ilk_limits_single_lvds_100m;
+			else
+				limit = &ilk_limits_single_lvds;
+		}
+	} else {
+		limit = &ilk_limits_dac;
+	}
+
+	if (!crtc_state->clock_set &&
+	    !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+				refclk, NULL, &crtc_state->dpll)) {
+		drm_err(&dev_priv->drm,
+			"Couldn't find PLL settings for mode!\n");
+		return -EINVAL;
+	}
+
+	ilk_compute_dpll(crtc, crtc_state, NULL);
+
+	if (!intel_reserve_shared_dplls(state, crtc, NULL)) {
+		drm_dbg_kms(&dev_priv->drm,
+			    "failed to find PLL for pipe %c\n",
+			    pipe_name(crtc->pipe));
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void vlv_compute_dpll(struct intel_crtc *crtc,
+		      struct intel_crtc_state *pipe_config)
+{
+	pipe_config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV |
+		DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
+	if (crtc->pipe != PIPE_A)
+		pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
+
+	/* DPLL not used with DSI, but still need the rest set up */
+	if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
+		pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE |
+			DPLL_EXT_BUFFER_ENABLE_VLV;
+
+	pipe_config->dpll_hw_state.dpll_md =
+		(pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+}
+
+void chv_compute_dpll(struct intel_crtc *crtc,
+		      struct intel_crtc_state *pipe_config)
+{
+	pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV |
+		DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
+	if (crtc->pipe != PIPE_A)
+		pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
+
+	/* DPLL not used with DSI, but still need the rest set up */
+	if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
+		pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE;
+
+	pipe_config->dpll_hw_state.dpll_md =
+		(pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+}
+
+static int chv_crtc_compute_clock(struct intel_crtc *crtc,
+				  struct intel_crtc_state *crtc_state)
+{
+	int refclk = 100000;
+	const struct intel_limit *limit = &intel_limits_chv;
+	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
+	if (!crtc_state->clock_set &&
+	    !chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+				refclk, NULL, &crtc_state->dpll)) {
+		drm_err(&i915->drm, "Couldn't find PLL settings for mode!\n");
+		return -EINVAL;
+	}
+
+	chv_compute_dpll(crtc, crtc_state);
+
+	return 0;
+}
+
+static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
+				  struct intel_crtc_state *crtc_state)
+{
+	int refclk = 100000;
+	const struct intel_limit *limit = &intel_limits_vlv;
+	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
+	if (!crtc_state->clock_set &&
+	    !vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+				refclk, NULL, &crtc_state->dpll)) {
+		drm_err(&i915->drm,  "Couldn't find PLL settings for mode!\n");
+		return -EINVAL;
+	}
+
+	vlv_compute_dpll(crtc, crtc_state);
+
+	return 0;
+}
+
+static int g4x_crtc_compute_clock(struct intel_crtc *crtc,
+				  struct intel_crtc_state *crtc_state)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	const struct intel_limit *limit;
+	int refclk = 96000;
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+		if (intel_panel_use_ssc(dev_priv)) {
+			refclk = dev_priv->vbt.lvds_ssc_freq;
+			drm_dbg_kms(&dev_priv->drm,
+				    "using SSC reference clock of %d kHz\n",
+				    refclk);
+		}
+
+		if (intel_is_dual_link_lvds(dev_priv))
+			limit = &intel_limits_g4x_dual_channel_lvds;
+		else
+			limit = &intel_limits_g4x_single_channel_lvds;
+	} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
+		   intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
+		limit = &intel_limits_g4x_hdmi;
+	} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO)) {
+		limit = &intel_limits_g4x_sdvo;
+	} else {
+		/* The option is for other outputs */
+		limit = &intel_limits_i9xx_sdvo;
+	}
+
+	if (!crtc_state->clock_set &&
+	    !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+				refclk, NULL, &crtc_state->dpll)) {
+		drm_err(&dev_priv->drm,
+			"Couldn't find PLL settings for mode!\n");
+		return -EINVAL;
+	}
+
+	i9xx_compute_dpll(crtc, crtc_state, NULL);
+
+	return 0;
+}
+
+static int pnv_crtc_compute_clock(struct intel_crtc *crtc,
+				  struct intel_crtc_state *crtc_state)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	const struct intel_limit *limit;
+	int refclk = 96000;
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+		if (intel_panel_use_ssc(dev_priv)) {
+			refclk = dev_priv->vbt.lvds_ssc_freq;
+			drm_dbg_kms(&dev_priv->drm,
+				    "using SSC reference clock of %d kHz\n",
+				    refclk);
+		}
+
+		limit = &pnv_limits_lvds;
+	} else {
+		limit = &pnv_limits_sdvo;
+	}
+
+	if (!crtc_state->clock_set &&
+	    !pnv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+				refclk, NULL, &crtc_state->dpll)) {
+		drm_err(&dev_priv->drm,
+			"Couldn't find PLL settings for mode!\n");
+		return -EINVAL;
+	}
+
+	i9xx_compute_dpll(crtc, crtc_state, NULL);
+
+	return 0;
+}
+
+static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
+				   struct intel_crtc_state *crtc_state)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	const struct intel_limit *limit;
+	int refclk = 96000;
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+		if (intel_panel_use_ssc(dev_priv)) {
+			refclk = dev_priv->vbt.lvds_ssc_freq;
+			drm_dbg_kms(&dev_priv->drm,
+				    "using SSC reference clock of %d kHz\n",
+				    refclk);
+		}
+
+		limit = &intel_limits_i9xx_lvds;
+	} else {
+		limit = &intel_limits_i9xx_sdvo;
+	}
+
+	if (!crtc_state->clock_set &&
+	    !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+				 refclk, NULL, &crtc_state->dpll)) {
+		drm_err(&dev_priv->drm,
+			"Couldn't find PLL settings for mode!\n");
+		return -EINVAL;
+	}
+
+	i9xx_compute_dpll(crtc, crtc_state, NULL);
+
+	return 0;
+}
+
+static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
+				   struct intel_crtc_state *crtc_state)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	const struct intel_limit *limit;
+	int refclk = 48000;
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
+	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
+		if (intel_panel_use_ssc(dev_priv)) {
+			refclk = dev_priv->vbt.lvds_ssc_freq;
+			drm_dbg_kms(&dev_priv->drm,
+				    "using SSC reference clock of %d kHz\n",
+				    refclk);
+		}
+
+		limit = &intel_limits_i8xx_lvds;
+	} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO)) {
+		limit = &intel_limits_i8xx_dvo;
+	} else {
+		limit = &intel_limits_i8xx_dac;
+	}
+
+	if (!crtc_state->clock_set &&
+	    !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
+				 refclk, NULL, &crtc_state->dpll)) {
+		drm_err(&dev_priv->drm,
+			"Couldn't find PLL settings for mode!\n");
+		return -EINVAL;
+	}
+
+	i8xx_compute_dpll(crtc, crtc_state, NULL);
+
+	return 0;
+}
+
+void
+intel_init_clock_hook(struct drm_i915_private *dev_priv)
+{
+	if (INTEL_GEN(dev_priv) >= 9 || HAS_DDI(dev_priv))
+		dev_priv->display.crtc_compute_clock = hsw_crtc_compute_clock;
+	else if (HAS_PCH_SPLIT(dev_priv))
+		dev_priv->display.crtc_compute_clock = ilk_crtc_compute_clock;
+	else if (IS_CHERRYVIEW(dev_priv))
+		dev_priv->display.crtc_compute_clock = chv_crtc_compute_clock;
+	else if (IS_VALLEYVIEW(dev_priv))
+		dev_priv->display.crtc_compute_clock = vlv_crtc_compute_clock;
+	else if (IS_G4X(dev_priv))
+		dev_priv->display.crtc_compute_clock = g4x_crtc_compute_clock;
+	else if (IS_PINEVIEW(dev_priv))
+		dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock;
+	else if (!IS_GEN(dev_priv, 2))
+		dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
+	else
+		dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock;
+}
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index c6f30e4ec51e..788b1def61ee 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -113,17 +113,6 @@ static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state);
 static void intel_modeset_setup_hw_state(struct drm_device *dev,
 					 struct drm_modeset_acquire_ctx *ctx);
 
-struct intel_limit {
-	struct {
-		int min, max;
-	} dot, vco, n, m, m1, m2, p, p1;
-
-	struct {
-		int dot_limit;
-		int p2_slow, p2_fast;
-	} p2;
-};
-
 /* returns HPLL frequency in kHz */
 int vlv_get_hpll_vco(struct drm_i915_private *dev_priv)
 {
@@ -191,271 +180,6 @@ static u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
 		return dev_priv->fdi_pll_freq;
 }
 
-static const struct intel_limit intel_limits_i8xx_dac = {
-	.dot = { .min = 25000, .max = 350000 },
-	.vco = { .min = 908000, .max = 1512000 },
-	.n = { .min = 2, .max = 16 },
-	.m = { .min = 96, .max = 140 },
-	.m1 = { .min = 18, .max = 26 },
-	.m2 = { .min = 6, .max = 16 },
-	.p = { .min = 4, .max = 128 },
-	.p1 = { .min = 2, .max = 33 },
-	.p2 = { .dot_limit = 165000,
-		.p2_slow = 4, .p2_fast = 2 },
-};
-
-static const struct intel_limit intel_limits_i8xx_dvo = {
-	.dot = { .min = 25000, .max = 350000 },
-	.vco = { .min = 908000, .max = 1512000 },
-	.n = { .min = 2, .max = 16 },
-	.m = { .min = 96, .max = 140 },
-	.m1 = { .min = 18, .max = 26 },
-	.m2 = { .min = 6, .max = 16 },
-	.p = { .min = 4, .max = 128 },
-	.p1 = { .min = 2, .max = 33 },
-	.p2 = { .dot_limit = 165000,
-		.p2_slow = 4, .p2_fast = 4 },
-};
-
-static const struct intel_limit intel_limits_i8xx_lvds = {
-	.dot = { .min = 25000, .max = 350000 },
-	.vco = { .min = 908000, .max = 1512000 },
-	.n = { .min = 2, .max = 16 },
-	.m = { .min = 96, .max = 140 },
-	.m1 = { .min = 18, .max = 26 },
-	.m2 = { .min = 6, .max = 16 },
-	.p = { .min = 4, .max = 128 },
-	.p1 = { .min = 1, .max = 6 },
-	.p2 = { .dot_limit = 165000,
-		.p2_slow = 14, .p2_fast = 7 },
-};
-
-static const struct intel_limit intel_limits_i9xx_sdvo = {
-	.dot = { .min = 20000, .max = 400000 },
-	.vco = { .min = 1400000, .max = 2800000 },
-	.n = { .min = 1, .max = 6 },
-	.m = { .min = 70, .max = 120 },
-	.m1 = { .min = 8, .max = 18 },
-	.m2 = { .min = 3, .max = 7 },
-	.p = { .min = 5, .max = 80 },
-	.p1 = { .min = 1, .max = 8 },
-	.p2 = { .dot_limit = 200000,
-		.p2_slow = 10, .p2_fast = 5 },
-};
-
-static const struct intel_limit intel_limits_i9xx_lvds = {
-	.dot = { .min = 20000, .max = 400000 },
-	.vco = { .min = 1400000, .max = 2800000 },
-	.n = { .min = 1, .max = 6 },
-	.m = { .min = 70, .max = 120 },
-	.m1 = { .min = 8, .max = 18 },
-	.m2 = { .min = 3, .max = 7 },
-	.p = { .min = 7, .max = 98 },
-	.p1 = { .min = 1, .max = 8 },
-	.p2 = { .dot_limit = 112000,
-		.p2_slow = 14, .p2_fast = 7 },
-};
-
-
-static const struct intel_limit intel_limits_g4x_sdvo = {
-	.dot = { .min = 25000, .max = 270000 },
-	.vco = { .min = 1750000, .max = 3500000},
-	.n = { .min = 1, .max = 4 },
-	.m = { .min = 104, .max = 138 },
-	.m1 = { .min = 17, .max = 23 },
-	.m2 = { .min = 5, .max = 11 },
-	.p = { .min = 10, .max = 30 },
-	.p1 = { .min = 1, .max = 3},
-	.p2 = { .dot_limit = 270000,
-		.p2_slow = 10,
-		.p2_fast = 10
-	},
-};
-
-static const struct intel_limit intel_limits_g4x_hdmi = {
-	.dot = { .min = 22000, .max = 400000 },
-	.vco = { .min = 1750000, .max = 3500000},
-	.n = { .min = 1, .max = 4 },
-	.m = { .min = 104, .max = 138 },
-	.m1 = { .min = 16, .max = 23 },
-	.m2 = { .min = 5, .max = 11 },
-	.p = { .min = 5, .max = 80 },
-	.p1 = { .min = 1, .max = 8},
-	.p2 = { .dot_limit = 165000,
-		.p2_slow = 10, .p2_fast = 5 },
-};
-
-static const struct intel_limit intel_limits_g4x_single_channel_lvds = {
-	.dot = { .min = 20000, .max = 115000 },
-	.vco = { .min = 1750000, .max = 3500000 },
-	.n = { .min = 1, .max = 3 },
-	.m = { .min = 104, .max = 138 },
-	.m1 = { .min = 17, .max = 23 },
-	.m2 = { .min = 5, .max = 11 },
-	.p = { .min = 28, .max = 112 },
-	.p1 = { .min = 2, .max = 8 },
-	.p2 = { .dot_limit = 0,
-		.p2_slow = 14, .p2_fast = 14
-	},
-};
-
-static const struct intel_limit intel_limits_g4x_dual_channel_lvds = {
-	.dot = { .min = 80000, .max = 224000 },
-	.vco = { .min = 1750000, .max = 3500000 },
-	.n = { .min = 1, .max = 3 },
-	.m = { .min = 104, .max = 138 },
-	.m1 = { .min = 17, .max = 23 },
-	.m2 = { .min = 5, .max = 11 },
-	.p = { .min = 14, .max = 42 },
-	.p1 = { .min = 2, .max = 6 },
-	.p2 = { .dot_limit = 0,
-		.p2_slow = 7, .p2_fast = 7
-	},
-};
-
-static const struct intel_limit pnv_limits_sdvo = {
-	.dot = { .min = 20000, .max = 400000},
-	.vco = { .min = 1700000, .max = 3500000 },
-	/* Pineview's Ncounter is a ring counter */
-	.n = { .min = 3, .max = 6 },
-	.m = { .min = 2, .max = 256 },
-	/* Pineview only has one combined m divider, which we treat as m2. */
-	.m1 = { .min = 0, .max = 0 },
-	.m2 = { .min = 0, .max = 254 },
-	.p = { .min = 5, .max = 80 },
-	.p1 = { .min = 1, .max = 8 },
-	.p2 = { .dot_limit = 200000,
-		.p2_slow = 10, .p2_fast = 5 },
-};
-
-static const struct intel_limit pnv_limits_lvds = {
-	.dot = { .min = 20000, .max = 400000 },
-	.vco = { .min = 1700000, .max = 3500000 },
-	.n = { .min = 3, .max = 6 },
-	.m = { .min = 2, .max = 256 },
-	.m1 = { .min = 0, .max = 0 },
-	.m2 = { .min = 0, .max = 254 },
-	.p = { .min = 7, .max = 112 },
-	.p1 = { .min = 1, .max = 8 },
-	.p2 = { .dot_limit = 112000,
-		.p2_slow = 14, .p2_fast = 14 },
-};
-
-/* Ironlake / Sandybridge
- *
- * We calculate clock using (register_value + 2) for N/M1/M2, so here
- * the range value for them is (actual_value - 2).
- */
-static const struct intel_limit ilk_limits_dac = {
-	.dot = { .min = 25000, .max = 350000 },
-	.vco = { .min = 1760000, .max = 3510000 },
-	.n = { .min = 1, .max = 5 },
-	.m = { .min = 79, .max = 127 },
-	.m1 = { .min = 12, .max = 22 },
-	.m2 = { .min = 5, .max = 9 },
-	.p = { .min = 5, .max = 80 },
-	.p1 = { .min = 1, .max = 8 },
-	.p2 = { .dot_limit = 225000,
-		.p2_slow = 10, .p2_fast = 5 },
-};
-
-static const struct intel_limit ilk_limits_single_lvds = {
-	.dot = { .min = 25000, .max = 350000 },
-	.vco = { .min = 1760000, .max = 3510000 },
-	.n = { .min = 1, .max = 3 },
-	.m = { .min = 79, .max = 118 },
-	.m1 = { .min = 12, .max = 22 },
-	.m2 = { .min = 5, .max = 9 },
-	.p = { .min = 28, .max = 112 },
-	.p1 = { .min = 2, .max = 8 },
-	.p2 = { .dot_limit = 225000,
-		.p2_slow = 14, .p2_fast = 14 },
-};
-
-static const struct intel_limit ilk_limits_dual_lvds = {
-	.dot = { .min = 25000, .max = 350000 },
-	.vco = { .min = 1760000, .max = 3510000 },
-	.n = { .min = 1, .max = 3 },
-	.m = { .min = 79, .max = 127 },
-	.m1 = { .min = 12, .max = 22 },
-	.m2 = { .min = 5, .max = 9 },
-	.p = { .min = 14, .max = 56 },
-	.p1 = { .min = 2, .max = 8 },
-	.p2 = { .dot_limit = 225000,
-		.p2_slow = 7, .p2_fast = 7 },
-};
-
-/* LVDS 100mhz refclk limits. */
-static const struct intel_limit ilk_limits_single_lvds_100m = {
-	.dot = { .min = 25000, .max = 350000 },
-	.vco = { .min = 1760000, .max = 3510000 },
-	.n = { .min = 1, .max = 2 },
-	.m = { .min = 79, .max = 126 },
-	.m1 = { .min = 12, .max = 22 },
-	.m2 = { .min = 5, .max = 9 },
-	.p = { .min = 28, .max = 112 },
-	.p1 = { .min = 2, .max = 8 },
-	.p2 = { .dot_limit = 225000,
-		.p2_slow = 14, .p2_fast = 14 },
-};
-
-static const struct intel_limit ilk_limits_dual_lvds_100m = {
-	.dot = { .min = 25000, .max = 350000 },
-	.vco = { .min = 1760000, .max = 3510000 },
-	.n = { .min = 1, .max = 3 },
-	.m = { .min = 79, .max = 126 },
-	.m1 = { .min = 12, .max = 22 },
-	.m2 = { .min = 5, .max = 9 },
-	.p = { .min = 14, .max = 42 },
-	.p1 = { .min = 2, .max = 6 },
-	.p2 = { .dot_limit = 225000,
-		.p2_slow = 7, .p2_fast = 7 },
-};
-
-static const struct intel_limit intel_limits_vlv = {
-	 /*
-	  * These are the data rate limits (measured in fast clocks)
-	  * since those are the strictest limits we have. The fast
-	  * clock and actual rate limits are more relaxed, so checking
-	  * them would make no difference.
-	  */
-	.dot = { .min = 25000 * 5, .max = 270000 * 5 },
-	.vco = { .min = 4000000, .max = 6000000 },
-	.n = { .min = 1, .max = 7 },
-	.m1 = { .min = 2, .max = 3 },
-	.m2 = { .min = 11, .max = 156 },
-	.p1 = { .min = 2, .max = 3 },
-	.p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */
-};
-
-static const struct intel_limit intel_limits_chv = {
-	/*
-	 * These are the data rate limits (measured in fast clocks)
-	 * since those are the strictest limits we have.  The fast
-	 * clock and actual rate limits are more relaxed, so checking
-	 * them would make no difference.
-	 */
-	.dot = { .min = 25000 * 5, .max = 540000 * 5},
-	.vco = { .min = 4800000, .max = 6480000 },
-	.n = { .min = 1, .max = 1 },
-	.m1 = { .min = 2, .max = 2 },
-	.m2 = { .min = 24 << 22, .max = 175 << 22 },
-	.p1 = { .min = 2, .max = 4 },
-	.p2 = {	.p2_slow = 1, .p2_fast = 14 },
-};
-
-static const struct intel_limit intel_limits_bxt = {
-	/* FIXME: find real dot limits */
-	.dot = { .min = 0, .max = INT_MAX },
-	.vco = { .min = 4800000, .max = 6700000 },
-	.n = { .min = 1, .max = 1 },
-	.m1 = { .min = 2, .max = 2 },
-	/* FIXME: find real m2 limits */
-	.m2 = { .min = 2 << 22, .max = 255 << 22 },
-	.p1 = { .min = 2, .max = 4 },
-	.p2 = { .p2_slow = 1, .p2_fast = 20 },
-};
-
 /* WA Display #0827: Gen9:all */
 static void
 skl_wa_827(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable)
@@ -506,482 +230,6 @@ is_trans_port_sync_mode(const struct intel_crtc_state *crtc_state)
 		is_trans_port_sync_slave(crtc_state);
 }
 
-/*
- * Platform specific helpers to calculate the port PLL loopback- (clock.m),
- * and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast
- * (clock.dot) clock rates. This fast dot clock is fed to the port's IO logic.
- * The helpers' return value is the rate of the clock that is fed to the
- * display engine's pipe which can be the above fast dot clock rate or a
- * divided-down version of it.
- */
-/* m1 is reserved as 0 in Pineview, n is a ring counter */
-static int pnv_calc_dpll_params(int refclk, struct dpll *clock)
-{
-	clock->m = clock->m2 + 2;
-	clock->p = clock->p1 * clock->p2;
-	if (WARN_ON(clock->n == 0 || clock->p == 0))
-		return 0;
-	clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
-	clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
-
-	return clock->dot;
-}
-
-static u32 i9xx_dpll_compute_m(struct dpll *dpll)
-{
-	return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
-}
-
-static int i9xx_calc_dpll_params(int refclk, struct dpll *clock)
-{
-	clock->m = i9xx_dpll_compute_m(clock);
-	clock->p = clock->p1 * clock->p2;
-	if (WARN_ON(clock->n + 2 == 0 || clock->p == 0))
-		return 0;
-	clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2);
-	clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
-
-	return clock->dot;
-}
-
-static int vlv_calc_dpll_params(int refclk, struct dpll *clock)
-{
-	clock->m = clock->m1 * clock->m2;
-	clock->p = clock->p1 * clock->p2;
-	if (WARN_ON(clock->n == 0 || clock->p == 0))
-		return 0;
-	clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
-	clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
-
-	return clock->dot / 5;
-}
-
-int chv_calc_dpll_params(int refclk, struct dpll *clock)
-{
-	clock->m = clock->m1 * clock->m2;
-	clock->p = clock->p1 * clock->p2;
-	if (WARN_ON(clock->n == 0 || clock->p == 0))
-		return 0;
-	clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
-					   clock->n << 22);
-	clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
-
-	return clock->dot / 5;
-}
-
-/*
- * Returns whether the given set of divisors are valid for a given refclk with
- * the given connectors.
- */
-static bool intel_pll_is_valid(struct drm_i915_private *dev_priv,
-			       const struct intel_limit *limit,
-			       const struct dpll *clock)
-{
-	if (clock->n < limit->n.min || limit->n.max < clock->n)
-		return false;
-	if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
-		return false;
-	if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2)
-		return false;
-	if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
-		return false;
-
-	if (!IS_PINEVIEW(dev_priv) && !IS_VALLEYVIEW(dev_priv) &&
-	    !IS_CHERRYVIEW(dev_priv) && !IS_GEN9_LP(dev_priv))
-		if (clock->m1 <= clock->m2)
-			return false;
-
-	if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
-	    !IS_GEN9_LP(dev_priv)) {
-		if (clock->p < limit->p.min || limit->p.max < clock->p)
-			return false;
-		if (clock->m < limit->m.min || limit->m.max < clock->m)
-			return false;
-	}
-
-	if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
-		return false;
-	/* XXX: We may need to be checking "Dot clock" depending on the multiplier,
-	 * connector, etc., rather than just a single range.
-	 */
-	if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
-		return false;
-
-	return true;
-}
-
-static int
-i9xx_select_p2_div(const struct intel_limit *limit,
-		   const struct intel_crtc_state *crtc_state,
-		   int target)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-		/*
-		 * For LVDS just rely on its current settings for dual-channel.
-		 * We haven't figured out how to reliably set up different
-		 * single/dual channel state, if we even can.
-		 */
-		if (intel_is_dual_link_lvds(dev_priv))
-			return limit->p2.p2_fast;
-		else
-			return limit->p2.p2_slow;
-	} else {
-		if (target < limit->p2.dot_limit)
-			return limit->p2.p2_slow;
-		else
-			return limit->p2.p2_fast;
-	}
-}
-
-/*
- * Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE.  The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
- *
- * Target and reference clocks are specified in kHz.
- *
- * If match_clock is provided, then best_clock P divider must match the P
- * divider from @match_clock used for LVDS downclocking.
- */
-static bool
-i9xx_find_best_dpll(const struct intel_limit *limit,
-		    struct intel_crtc_state *crtc_state,
-		    int target, int refclk, struct dpll *match_clock,
-		    struct dpll *best_clock)
-{
-	struct drm_device *dev = crtc_state->uapi.crtc->dev;
-	struct dpll clock;
-	int err = target;
-
-	memset(best_clock, 0, sizeof(*best_clock));
-
-	clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
-
-	for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
-	     clock.m1++) {
-		for (clock.m2 = limit->m2.min;
-		     clock.m2 <= limit->m2.max; clock.m2++) {
-			if (clock.m2 >= clock.m1)
-				break;
-			for (clock.n = limit->n.min;
-			     clock.n <= limit->n.max; clock.n++) {
-				for (clock.p1 = limit->p1.min;
-					clock.p1 <= limit->p1.max; clock.p1++) {
-					int this_err;
-
-					i9xx_calc_dpll_params(refclk, &clock);
-					if (!intel_pll_is_valid(to_i915(dev),
-								limit,
-								&clock))
-						continue;
-					if (match_clock &&
-					    clock.p != match_clock->p)
-						continue;
-
-					this_err = abs(clock.dot - target);
-					if (this_err < err) {
-						*best_clock = clock;
-						err = this_err;
-					}
-				}
-			}
-		}
-	}
-
-	return (err != target);
-}
-
-/*
- * Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE.  The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
- *
- * Target and reference clocks are specified in kHz.
- *
- * If match_clock is provided, then best_clock P divider must match the P
- * divider from @match_clock used for LVDS downclocking.
- */
-static bool
-pnv_find_best_dpll(const struct intel_limit *limit,
-		   struct intel_crtc_state *crtc_state,
-		   int target, int refclk, struct dpll *match_clock,
-		   struct dpll *best_clock)
-{
-	struct drm_device *dev = crtc_state->uapi.crtc->dev;
-	struct dpll clock;
-	int err = target;
-
-	memset(best_clock, 0, sizeof(*best_clock));
-
-	clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
-
-	for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
-	     clock.m1++) {
-		for (clock.m2 = limit->m2.min;
-		     clock.m2 <= limit->m2.max; clock.m2++) {
-			for (clock.n = limit->n.min;
-			     clock.n <= limit->n.max; clock.n++) {
-				for (clock.p1 = limit->p1.min;
-					clock.p1 <= limit->p1.max; clock.p1++) {
-					int this_err;
-
-					pnv_calc_dpll_params(refclk, &clock);
-					if (!intel_pll_is_valid(to_i915(dev),
-								limit,
-								&clock))
-						continue;
-					if (match_clock &&
-					    clock.p != match_clock->p)
-						continue;
-
-					this_err = abs(clock.dot - target);
-					if (this_err < err) {
-						*best_clock = clock;
-						err = this_err;
-					}
-				}
-			}
-		}
-	}
-
-	return (err != target);
-}
-
-/*
- * Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE.  The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
- *
- * Target and reference clocks are specified in kHz.
- *
- * If match_clock is provided, then best_clock P divider must match the P
- * divider from @match_clock used for LVDS downclocking.
- */
-static bool
-g4x_find_best_dpll(const struct intel_limit *limit,
-		   struct intel_crtc_state *crtc_state,
-		   int target, int refclk, struct dpll *match_clock,
-		   struct dpll *best_clock)
-{
-	struct drm_device *dev = crtc_state->uapi.crtc->dev;
-	struct dpll clock;
-	int max_n;
-	bool found = false;
-	/* approximately equals target * 0.00585 */
-	int err_most = (target >> 8) + (target >> 9);
-
-	memset(best_clock, 0, sizeof(*best_clock));
-
-	clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
-
-	max_n = limit->n.max;
-	/* based on hardware requirement, prefer smaller n to precision */
-	for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
-		/* based on hardware requirement, prefere larger m1,m2 */
-		for (clock.m1 = limit->m1.max;
-		     clock.m1 >= limit->m1.min; clock.m1--) {
-			for (clock.m2 = limit->m2.max;
-			     clock.m2 >= limit->m2.min; clock.m2--) {
-				for (clock.p1 = limit->p1.max;
-				     clock.p1 >= limit->p1.min; clock.p1--) {
-					int this_err;
-
-					i9xx_calc_dpll_params(refclk, &clock);
-					if (!intel_pll_is_valid(to_i915(dev),
-								limit,
-								&clock))
-						continue;
-
-					this_err = abs(clock.dot - target);
-					if (this_err < err_most) {
-						*best_clock = clock;
-						err_most = this_err;
-						max_n = clock.n;
-						found = true;
-					}
-				}
-			}
-		}
-	}
-	return found;
-}
-
-/*
- * Check if the calculated PLL configuration is more optimal compared to the
- * best configuration and error found so far. Return the calculated error.
- */
-static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
-			       const struct dpll *calculated_clock,
-			       const struct dpll *best_clock,
-			       unsigned int best_error_ppm,
-			       unsigned int *error_ppm)
-{
-	/*
-	 * For CHV ignore the error and consider only the P value.
-	 * Prefer a bigger P value based on HW requirements.
-	 */
-	if (IS_CHERRYVIEW(to_i915(dev))) {
-		*error_ppm = 0;
-
-		return calculated_clock->p > best_clock->p;
-	}
-
-	if (drm_WARN_ON_ONCE(dev, !target_freq))
-		return false;
-
-	*error_ppm = div_u64(1000000ULL *
-				abs(target_freq - calculated_clock->dot),
-			     target_freq);
-	/*
-	 * Prefer a better P value over a better (smaller) error if the error
-	 * is small. Ensure this preference for future configurations too by
-	 * setting the error to 0.
-	 */
-	if (*error_ppm < 100 && calculated_clock->p > best_clock->p) {
-		*error_ppm = 0;
-
-		return true;
-	}
-
-	return *error_ppm + 10 < best_error_ppm;
-}
-
-/*
- * Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE.  The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
- */
-static bool
-vlv_find_best_dpll(const struct intel_limit *limit,
-		   struct intel_crtc_state *crtc_state,
-		   int target, int refclk, struct dpll *match_clock,
-		   struct dpll *best_clock)
-{
-	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-	struct drm_device *dev = crtc->base.dev;
-	struct dpll clock;
-	unsigned int bestppm = 1000000;
-	/* min update 19.2 MHz */
-	int max_n = min(limit->n.max, refclk / 19200);
-	bool found = false;
-
-	target *= 5; /* fast clock */
-
-	memset(best_clock, 0, sizeof(*best_clock));
-
-	/* based on hardware requirement, prefer smaller n to precision */
-	for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
-		for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
-			for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow;
-			     clock.p2 -= clock.p2 > 10 ? 2 : 1) {
-				clock.p = clock.p1 * clock.p2;
-				/* based on hardware requirement, prefer bigger m1,m2 values */
-				for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
-					unsigned int ppm;
-
-					clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n,
-								     refclk * clock.m1);
-
-					vlv_calc_dpll_params(refclk, &clock);
-
-					if (!intel_pll_is_valid(to_i915(dev),
-								limit,
-								&clock))
-						continue;
-
-					if (!vlv_PLL_is_optimal(dev, target,
-								&clock,
-								best_clock,
-								bestppm, &ppm))
-						continue;
-
-					*best_clock = clock;
-					bestppm = ppm;
-					found = true;
-				}
-			}
-		}
-	}
-
-	return found;
-}
-
-/*
- * Returns a set of divisors for the desired target clock with the given
- * refclk, or FALSE.  The returned values represent the clock equation:
- * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
- */
-static bool
-chv_find_best_dpll(const struct intel_limit *limit,
-		   struct intel_crtc_state *crtc_state,
-		   int target, int refclk, struct dpll *match_clock,
-		   struct dpll *best_clock)
-{
-	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
-	struct drm_device *dev = crtc->base.dev;
-	unsigned int best_error_ppm;
-	struct dpll clock;
-	u64 m2;
-	int found = false;
-
-	memset(best_clock, 0, sizeof(*best_clock));
-	best_error_ppm = 1000000;
-
-	/*
-	 * Based on hardware doc, the n always set to 1, and m1 always
-	 * set to 2.  If requires to support 200Mhz refclk, we need to
-	 * revisit this because n may not 1 anymore.
-	 */
-	clock.n = 1, clock.m1 = 2;
-	target *= 5;	/* fast clock */
-
-	for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
-		for (clock.p2 = limit->p2.p2_fast;
-				clock.p2 >= limit->p2.p2_slow;
-				clock.p2 -= clock.p2 > 10 ? 2 : 1) {
-			unsigned int error_ppm;
-
-			clock.p = clock.p1 * clock.p2;
-
-			m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
-						   refclk * clock.m1);
-
-			if (m2 > INT_MAX/clock.m1)
-				continue;
-
-			clock.m2 = m2;
-
-			chv_calc_dpll_params(refclk, &clock);
-
-			if (!intel_pll_is_valid(to_i915(dev), limit, &clock))
-				continue;
-
-			if (!vlv_PLL_is_optimal(dev, target, &clock, best_clock,
-						best_error_ppm, &error_ppm))
-				continue;
-
-			*best_clock = clock;
-			best_error_ppm = error_ppm;
-			found = true;
-		}
-	}
-
-	return found;
-}
-
-bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
-			struct dpll *best_clock)
-{
-	int refclk = 100000;
-	const struct intel_limit *limit = &intel_limits_bxt;
-
-	return chv_find_best_dpll(limit, crtc_state,
-				  crtc_state->port_clock, refclk,
-				  NULL, best_clock);
-}
-
 static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv,
 				    enum pipe pipe)
 {
@@ -5284,7 +4532,7 @@ static void ivb_update_fdi_bc_bifurcation(const struct intel_crtc_state *crtc_st
  * Finds the encoder associated with the given CRTC. This can only be
  * used when we know that the CRTC isn't feeding multiple encoders!
  */
-static struct intel_encoder *
+struct intel_encoder *
 intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
 			   const struct intel_crtc_state *crtc_state)
 {
@@ -7960,43 +7208,6 @@ static bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
 		&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
 }
 
-static u32 pnv_dpll_compute_fp(struct dpll *dpll)
-{
-	return (1 << dpll->n) << 16 | dpll->m2;
-}
-
-static u32 i9xx_dpll_compute_fp(struct dpll *dpll)
-{
-	return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
-}
-
-static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
-				     struct intel_crtc_state *crtc_state,
-				     struct dpll *reduced_clock)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	u32 fp, fp2 = 0;
-
-	if (IS_PINEVIEW(dev_priv)) {
-		fp = pnv_dpll_compute_fp(&crtc_state->dpll);
-		if (reduced_clock)
-			fp2 = pnv_dpll_compute_fp(reduced_clock);
-	} else {
-		fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
-		if (reduced_clock)
-			fp2 = i9xx_dpll_compute_fp(reduced_clock);
-	}
-
-	crtc_state->dpll_hw_state.fp0 = fp;
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-	    reduced_clock) {
-		crtc_state->dpll_hw_state.fp1 = fp2;
-	} else {
-		crtc_state->dpll_hw_state.fp1 = fp;
-	}
-}
-
 static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe
 		pipe)
 {
@@ -8121,39 +7332,6 @@ void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state, enum link_m_n_s
 		intel_cpu_transcoder_set_m_n(crtc_state, dp_m_n, dp_m2_n2);
 }
 
-static void vlv_compute_dpll(struct intel_crtc *crtc,
-			     struct intel_crtc_state *pipe_config)
-{
-	pipe_config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV |
-		DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
-	if (crtc->pipe != PIPE_A)
-		pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
-
-	/* DPLL not used with DSI, but still need the rest set up */
-	if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
-		pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE |
-			DPLL_EXT_BUFFER_ENABLE_VLV;
-
-	pipe_config->dpll_hw_state.dpll_md =
-		(pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-}
-
-static void chv_compute_dpll(struct intel_crtc *crtc,
-			     struct intel_crtc_state *pipe_config)
-{
-	pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV |
-		DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
-	if (crtc->pipe != PIPE_A)
-		pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
-
-	/* DPLL not used with DSI, but still need the rest set up */
-	if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
-		pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE;
-
-	pipe_config->dpll_hw_state.dpll_md =
-		(pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
-}
-
 static void vlv_prepare_pll(struct intel_crtc *crtc,
 			    const struct intel_crtc_state *pipe_config)
 {
@@ -8413,128 +7591,7 @@ void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe)
 		vlv_disable_pll(dev_priv, pipe);
 }
 
-static void i9xx_compute_dpll(struct intel_crtc *crtc,
-			      struct intel_crtc_state *crtc_state,
-			      struct dpll *reduced_clock)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	u32 dpll;
-	struct dpll *clock = &crtc_state->dpll;
-
-	i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
-
-	dpll = DPLL_VGA_MODE_DIS;
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
-		dpll |= DPLLB_MODE_LVDS;
-	else
-		dpll |= DPLLB_MODE_DAC_SERIAL;
-
-	if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
-	    IS_G33(dev_priv) || IS_PINEVIEW(dev_priv)) {
-		dpll |= (crtc_state->pixel_multiplier - 1)
-			<< SDVO_MULTIPLIER_SHIFT_HIRES;
-	}
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
-	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
-		dpll |= DPLL_SDVO_HIGH_SPEED;
-
-	if (intel_crtc_has_dp_encoder(crtc_state))
-		dpll |= DPLL_SDVO_HIGH_SPEED;
-
-	/* compute bitmask from p1 value */
-	if (IS_PINEVIEW(dev_priv))
-		dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
-	else {
-		dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-		if (IS_G4X(dev_priv) && reduced_clock)
-			dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
-	}
-	switch (clock->p2) {
-	case 5:
-		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
-		break;
-	case 7:
-		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
-		break;
-	case 10:
-		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
-		break;
-	case 14:
-		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
-		break;
-	}
-	if (INTEL_GEN(dev_priv) >= 4)
-		dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
-
-	if (crtc_state->sdvo_tv_clock)
-		dpll |= PLL_REF_INPUT_TVCLKINBC;
-	else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-		 intel_panel_use_ssc(dev_priv))
-		dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
-	else
-		dpll |= PLL_REF_INPUT_DREFCLK;
-
-	dpll |= DPLL_VCO_ENABLE;
-	crtc_state->dpll_hw_state.dpll = dpll;
-
-	if (INTEL_GEN(dev_priv) >= 4) {
-		u32 dpll_md = (crtc_state->pixel_multiplier - 1)
-			<< DPLL_MD_UDI_MULTIPLIER_SHIFT;
-		crtc_state->dpll_hw_state.dpll_md = dpll_md;
-	}
-}
-
-static void i8xx_compute_dpll(struct intel_crtc *crtc,
-			      struct intel_crtc_state *crtc_state,
-			      struct dpll *reduced_clock)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	u32 dpll;
-	struct dpll *clock = &crtc_state->dpll;
-
-	i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
-
-	dpll = DPLL_VGA_MODE_DIS;
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-		dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-	} else {
-		if (clock->p1 == 2)
-			dpll |= PLL_P1_DIVIDE_BY_TWO;
-		else
-			dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-		if (clock->p2 == 4)
-			dpll |= PLL_P2_DIVIDE_BY_4;
-	}
-
-	/*
-	 * Bspec:
-	 * "[Almador Errata}: For the correct operation of the muxed DVO pins
-	 *  (GDEVSELB/I2Cdata, GIRDBY/I2CClk) and (GFRAMEB/DVI_Data,
-	 *  GTRDYB/DVI_Clk): Bit 31 (DPLL VCO Enable) and Bit 30 (2X Clock
-	 *  Enable) must be set to “1” in both the DPLL A Control Register
-	 *  (06014h-06017h) and DPLL B Control Register (06018h-0601Bh)."
-	 *
-	 * For simplicity We simply keep both bits always enabled in
-	 * both DPLLS. The spec says we should disable the DVO 2X clock
-	 * when not needed, but this seems to work fine in practice.
-	 */
-	if (IS_I830(dev_priv) ||
-	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO))
-		dpll |= DPLL_DVO_2X_MODE;
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-	    intel_panel_use_ssc(dev_priv))
-		dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
-	else
-		dpll |= PLL_REF_INPUT_DREFCLK;
 
-	dpll |= DPLL_VCO_ENABLE;
-	crtc_state->dpll_hw_state.dpll = dpll;
-}
 
 static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state)
 {
@@ -8740,207 +7797,6 @@ static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state)
 	intel_de_posting_read(dev_priv, PIPECONF(crtc->pipe));
 }
 
-static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
-				   struct intel_crtc_state *crtc_state)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	const struct intel_limit *limit;
-	int refclk = 48000;
-
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-		if (intel_panel_use_ssc(dev_priv)) {
-			refclk = dev_priv->vbt.lvds_ssc_freq;
-			drm_dbg_kms(&dev_priv->drm,
-				    "using SSC reference clock of %d kHz\n",
-				    refclk);
-		}
-
-		limit = &intel_limits_i8xx_lvds;
-	} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO)) {
-		limit = &intel_limits_i8xx_dvo;
-	} else {
-		limit = &intel_limits_i8xx_dac;
-	}
-
-	if (!crtc_state->clock_set &&
-	    !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
-				 refclk, NULL, &crtc_state->dpll)) {
-		drm_err(&dev_priv->drm,
-			"Couldn't find PLL settings for mode!\n");
-		return -EINVAL;
-	}
-
-	i8xx_compute_dpll(crtc, crtc_state, NULL);
-
-	return 0;
-}
-
-static int g4x_crtc_compute_clock(struct intel_crtc *crtc,
-				  struct intel_crtc_state *crtc_state)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	const struct intel_limit *limit;
-	int refclk = 96000;
-
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-		if (intel_panel_use_ssc(dev_priv)) {
-			refclk = dev_priv->vbt.lvds_ssc_freq;
-			drm_dbg_kms(&dev_priv->drm,
-				    "using SSC reference clock of %d kHz\n",
-				    refclk);
-		}
-
-		if (intel_is_dual_link_lvds(dev_priv))
-			limit = &intel_limits_g4x_dual_channel_lvds;
-		else
-			limit = &intel_limits_g4x_single_channel_lvds;
-	} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
-		   intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
-		limit = &intel_limits_g4x_hdmi;
-	} else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO)) {
-		limit = &intel_limits_g4x_sdvo;
-	} else {
-		/* The option is for other outputs */
-		limit = &intel_limits_i9xx_sdvo;
-	}
-
-	if (!crtc_state->clock_set &&
-	    !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
-				refclk, NULL, &crtc_state->dpll)) {
-		drm_err(&dev_priv->drm,
-			"Couldn't find PLL settings for mode!\n");
-		return -EINVAL;
-	}
-
-	i9xx_compute_dpll(crtc, crtc_state, NULL);
-
-	return 0;
-}
-
-static int pnv_crtc_compute_clock(struct intel_crtc *crtc,
-				  struct intel_crtc_state *crtc_state)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	const struct intel_limit *limit;
-	int refclk = 96000;
-
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-		if (intel_panel_use_ssc(dev_priv)) {
-			refclk = dev_priv->vbt.lvds_ssc_freq;
-			drm_dbg_kms(&dev_priv->drm,
-				    "using SSC reference clock of %d kHz\n",
-				    refclk);
-		}
-
-		limit = &pnv_limits_lvds;
-	} else {
-		limit = &pnv_limits_sdvo;
-	}
-
-	if (!crtc_state->clock_set &&
-	    !pnv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
-				refclk, NULL, &crtc_state->dpll)) {
-		drm_err(&dev_priv->drm,
-			"Couldn't find PLL settings for mode!\n");
-		return -EINVAL;
-	}
-
-	i9xx_compute_dpll(crtc, crtc_state, NULL);
-
-	return 0;
-}
-
-static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
-				   struct intel_crtc_state *crtc_state)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	const struct intel_limit *limit;
-	int refclk = 96000;
-
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-		if (intel_panel_use_ssc(dev_priv)) {
-			refclk = dev_priv->vbt.lvds_ssc_freq;
-			drm_dbg_kms(&dev_priv->drm,
-				    "using SSC reference clock of %d kHz\n",
-				    refclk);
-		}
-
-		limit = &intel_limits_i9xx_lvds;
-	} else {
-		limit = &intel_limits_i9xx_sdvo;
-	}
-
-	if (!crtc_state->clock_set &&
-	    !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
-				 refclk, NULL, &crtc_state->dpll)) {
-		drm_err(&dev_priv->drm,
-			"Couldn't find PLL settings for mode!\n");
-		return -EINVAL;
-	}
-
-	i9xx_compute_dpll(crtc, crtc_state, NULL);
-
-	return 0;
-}
-
-static int chv_crtc_compute_clock(struct intel_crtc *crtc,
-				  struct intel_crtc_state *crtc_state)
-{
-	int refclk = 100000;
-	const struct intel_limit *limit = &intel_limits_chv;
-	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
-
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
-	if (!crtc_state->clock_set &&
-	    !chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
-				refclk, NULL, &crtc_state->dpll)) {
-		drm_err(&i915->drm, "Couldn't find PLL settings for mode!\n");
-		return -EINVAL;
-	}
-
-	chv_compute_dpll(crtc, crtc_state);
-
-	return 0;
-}
-
-static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
-				  struct intel_crtc_state *crtc_state)
-{
-	int refclk = 100000;
-	const struct intel_limit *limit = &intel_limits_vlv;
-	struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
-
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
-	if (!crtc_state->clock_set &&
-	    !vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
-				refclk, NULL, &crtc_state->dpll)) {
-		drm_err(&i915->drm,  "Couldn't find PLL settings for mode!\n");
-		return -EINVAL;
-	}
-
-	vlv_compute_dpll(crtc, crtc_state);
-
-	return 0;
-}
 
 static bool i9xx_has_pfit(struct drm_i915_private *dev_priv)
 {
@@ -9951,172 +8807,6 @@ int ilk_get_lanes_required(int target_clock, int link_bw, int bpp)
 	return DIV_ROUND_UP(bps, link_bw * 8);
 }
 
-static bool ilk_needs_fb_cb_tune(struct dpll *dpll, int factor)
-{
-	return i9xx_dpll_compute_m(dpll) < factor * dpll->n;
-}
-
-static void ilk_compute_dpll(struct intel_crtc *crtc,
-			     struct intel_crtc_state *crtc_state,
-			     struct dpll *reduced_clock)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	u32 dpll, fp, fp2;
-	int factor;
-
-	/* Enable autotuning of the PLL clock (if permissible) */
-	factor = 21;
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-		if ((intel_panel_use_ssc(dev_priv) &&
-		     dev_priv->vbt.lvds_ssc_freq == 100000) ||
-		    (HAS_PCH_IBX(dev_priv) &&
-		     intel_is_dual_link_lvds(dev_priv)))
-			factor = 25;
-	} else if (crtc_state->sdvo_tv_clock) {
-		factor = 20;
-	}
-
-	fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
-
-	if (ilk_needs_fb_cb_tune(&crtc_state->dpll, factor))
-		fp |= FP_CB_TUNE;
-
-	if (reduced_clock) {
-		fp2 = i9xx_dpll_compute_fp(reduced_clock);
-
-		if (reduced_clock->m < factor * reduced_clock->n)
-			fp2 |= FP_CB_TUNE;
-	} else {
-		fp2 = fp;
-	}
-
-	dpll = 0;
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
-		dpll |= DPLLB_MODE_LVDS;
-	else
-		dpll |= DPLLB_MODE_DAC_SERIAL;
-
-	dpll |= (crtc_state->pixel_multiplier - 1)
-		<< PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
-	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
-		dpll |= DPLL_SDVO_HIGH_SPEED;
-
-	if (intel_crtc_has_dp_encoder(crtc_state))
-		dpll |= DPLL_SDVO_HIGH_SPEED;
-
-	/*
-	 * The high speed IO clock is only really required for
-	 * SDVO/HDMI/DP, but we also enable it for CRT to make it
-	 * possible to share the DPLL between CRT and HDMI. Enabling
-	 * the clock needlessly does no real harm, except use up a
-	 * bit of power potentially.
-	 *
-	 * We'll limit this to IVB with 3 pipes, since it has only two
-	 * DPLLs and so DPLL sharing is the only way to get three pipes
-	 * driving PCH ports at the same time. On SNB we could do this,
-	 * and potentially avoid enabling the second DPLL, but it's not
-	 * clear if it''s a win or loss power wise. No point in doing
-	 * this on ILK at all since it has a fixed DPLL<->pipe mapping.
-	 */
-	if (INTEL_NUM_PIPES(dev_priv) == 3 &&
-	    intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
-		dpll |= DPLL_SDVO_HIGH_SPEED;
-
-	/* compute bitmask from p1 value */
-	dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
-	/* also FPA1 */
-	dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
-
-	switch (crtc_state->dpll.p2) {
-	case 5:
-		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
-		break;
-	case 7:
-		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
-		break;
-	case 10:
-		dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
-		break;
-	case 14:
-		dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
-		break;
-	}
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
-	    intel_panel_use_ssc(dev_priv))
-		dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
-	else
-		dpll |= PLL_REF_INPUT_DREFCLK;
-
-	dpll |= DPLL_VCO_ENABLE;
-
-	crtc_state->dpll_hw_state.dpll = dpll;
-	crtc_state->dpll_hw_state.fp0 = fp;
-	crtc_state->dpll_hw_state.fp1 = fp2;
-}
-
-static int ilk_crtc_compute_clock(struct intel_crtc *crtc,
-				  struct intel_crtc_state *crtc_state)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	struct intel_atomic_state *state =
-		to_intel_atomic_state(crtc_state->uapi.state);
-	const struct intel_limit *limit;
-	int refclk = 120000;
-
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
-	/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
-	if (!crtc_state->has_pch_encoder)
-		return 0;
-
-	if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
-		if (intel_panel_use_ssc(dev_priv)) {
-			drm_dbg_kms(&dev_priv->drm,
-				    "using SSC reference clock of %d kHz\n",
-				    dev_priv->vbt.lvds_ssc_freq);
-			refclk = dev_priv->vbt.lvds_ssc_freq;
-		}
-
-		if (intel_is_dual_link_lvds(dev_priv)) {
-			if (refclk == 100000)
-				limit = &ilk_limits_dual_lvds_100m;
-			else
-				limit = &ilk_limits_dual_lvds;
-		} else {
-			if (refclk == 100000)
-				limit = &ilk_limits_single_lvds_100m;
-			else
-				limit = &ilk_limits_single_lvds;
-		}
-	} else {
-		limit = &ilk_limits_dac;
-	}
-
-	if (!crtc_state->clock_set &&
-	    !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
-				refclk, NULL, &crtc_state->dpll)) {
-		drm_err(&dev_priv->drm,
-			"Couldn't find PLL settings for mode!\n");
-		return -EINVAL;
-	}
-
-	ilk_compute_dpll(crtc, crtc_state, NULL);
-
-	if (!intel_reserve_shared_dplls(state, crtc, NULL)) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "failed to find PLL for pipe %c\n",
-			    pipe_name(crtc->pipe));
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
 static void intel_pch_transcoder_get_m_n(struct intel_crtc *crtc,
 					 struct intel_link_m_n *m_n)
 {
@@ -10529,29 +9219,6 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
 	return ret;
 }
 
-static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
-				  struct intel_crtc_state *crtc_state)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	struct intel_atomic_state *state =
-		to_intel_atomic_state(crtc_state->uapi.state);
-
-	if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) ||
-	    INTEL_GEN(dev_priv) >= 11) {
-		struct intel_encoder *encoder =
-			intel_get_crtc_new_encoder(state, crtc_state);
-
-		if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
-			drm_dbg_kms(&dev_priv->drm,
-				    "failed to find PLL for pipe %c\n",
-				    pipe_name(crtc->pipe));
-			return -EINVAL;
-		}
-	}
-
-	return 0;
-}
-
 static void dg1_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
 			    struct intel_crtc_state *pipe_config)
 {
@@ -16486,69 +15153,27 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
 {
 	intel_init_cdclk_hooks(dev_priv);
 
+	intel_init_clock_hook(dev_priv);
+
 	if (INTEL_GEN(dev_priv) >= 9) {
 		dev_priv->display.get_pipe_config = hsw_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			skl_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock = hsw_crtc_compute_clock;
 		dev_priv->display.crtc_enable = hsw_crtc_enable;
 		dev_priv->display.crtc_disable = hsw_crtc_disable;
 	} else if (HAS_DDI(dev_priv)) {
 		dev_priv->display.get_pipe_config = hsw_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			i9xx_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock =
-			hsw_crtc_compute_clock;
 		dev_priv->display.crtc_enable = hsw_crtc_enable;
 		dev_priv->display.crtc_disable = hsw_crtc_disable;
 	} else if (HAS_PCH_SPLIT(dev_priv)) {
 		dev_priv->display.get_pipe_config = ilk_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			i9xx_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock =
-			ilk_crtc_compute_clock;
 		dev_priv->display.crtc_enable = ilk_crtc_enable;
 		dev_priv->display.crtc_disable = ilk_crtc_disable;
-	} else if (IS_CHERRYVIEW(dev_priv)) {
-		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			i9xx_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock = chv_crtc_compute_clock;
-		dev_priv->display.crtc_enable = valleyview_crtc_enable;
-		dev_priv->display.crtc_disable = i9xx_crtc_disable;
-	} else if (IS_VALLEYVIEW(dev_priv)) {
+	} else if (IS_CHERRYVIEW(dev_priv) ||
+		   IS_VALLEYVIEW(dev_priv)) {
 		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			i9xx_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock = vlv_crtc_compute_clock;
 		dev_priv->display.crtc_enable = valleyview_crtc_enable;
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
-	} else if (IS_G4X(dev_priv)) {
-		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			i9xx_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock = g4x_crtc_compute_clock;
-		dev_priv->display.crtc_enable = i9xx_crtc_enable;
-		dev_priv->display.crtc_disable = i9xx_crtc_disable;
-	} else if (IS_PINEVIEW(dev_priv)) {
-		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			i9xx_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock;
-		dev_priv->display.crtc_enable = i9xx_crtc_enable;
-		dev_priv->display.crtc_disable = i9xx_crtc_disable;
-	} else if (!IS_GEN(dev_priv, 2)) {
-		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			i9xx_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
-		dev_priv->display.crtc_enable = i9xx_crtc_enable;
-		dev_priv->display.crtc_disable = i9xx_crtc_disable;
 	} else {
 		dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
-		dev_priv->display.get_initial_plane_config =
-			i9xx_get_initial_plane_config;
-		dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock;
 		dev_priv->display.crtc_enable = i9xx_crtc_enable;
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
 	}
@@ -16562,10 +15187,13 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
 		dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
 	}
 
-	if (INTEL_GEN(dev_priv) >= 9)
+	if (INTEL_GEN(dev_priv) >= 9) {
 		dev_priv->display.commit_modeset_enables = skl_commit_modeset_enables;
-	else
+		dev_priv->display.get_initial_plane_config = skl_get_initial_plane_config;
+	} else {
 		dev_priv->display.commit_modeset_enables = intel_commit_modeset_enables;
+		dev_priv->display.get_initial_plane_config = i9xx_get_initial_plane_config;
+	}
 
 }
 
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index 0eba91d18e96..f1e36cca86c1 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -653,7 +653,9 @@ u32 intel_plane_compute_aligned_offset(int *x, int *y,
 				       int color_plane);
 int intel_plane_pin_fb(struct intel_plane_state *plane_state);
 void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state);
-
+struct intel_encoder *
+intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
+			   const struct intel_crtc_state *crtc_state);
 /* cursor */
 struct intel_plane *
 intel_cursor_plane_create(struct drm_i915_private *dev_priv,
@@ -665,6 +667,15 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe);
 struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc);
 void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
 			    struct intel_crtc *crtc);
+/* clock */
+void intel_init_clock_hook(struct drm_i915_private *dev_priv);
+int vlv_calc_dpll_params(int refclk, struct dpll *clock);
+int pnv_calc_dpll_params(int refclk, struct dpll *clock);
+int i9xx_calc_dpll_params(int refclk, struct dpll *clock);
+void vlv_compute_dpll(struct intel_crtc *crtc,
+		      struct intel_crtc_state *pipe_config);
+void chv_compute_dpll(struct intel_crtc *crtc,
+		      struct intel_crtc_state *pipe_config);
 
 /* modesetting */
 void intel_modeset_init_hw(struct drm_i915_private *i915);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 5bc5bfbc4551..823083b231bc 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1799,4 +1799,9 @@ static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
 	return i915_ggtt_offset(state->vma);
 }
 
+static inline u32 i9xx_dpll_compute_fp(struct dpll *dpll)
+{
+	return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
+}
+
 #endif /*  __INTEL_DISPLAY_TYPES_H__ */
-- 
2.27.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Intel-gfx] [PATCH 4/4] drm/i915: split fdi code out from intel_display.c
  2020-12-09  4:21 [Intel-gfx] [rfc] start slimming down intel_display.c Dave Airlie
                   ` (2 preceding siblings ...)
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 3/4] drm/i915: refactor pll code out into intel_clock.c Dave Airlie
@ 2020-12-09  4:21 ` Dave Airlie
  2020-12-09 10:48   ` Daniel Vetter
  2020-12-09  4:56 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c Patchwork
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 13+ messages in thread
From: Dave Airlie @ 2020-12-09  4:21 UTC (permalink / raw)
  To: intel-gfx

From: Dave Airlie <airlied@redhat.com>

This just refactors out the fdi code to a separate file.

Signed-off-by: Dave Airlie <airlied@redhat.com>
---
 drivers/gpu/drm/i915/Makefile                 |   1 +
 drivers/gpu/drm/i915/display/intel_display.c  | 684 +-----------------
 drivers/gpu/drm/i915/display/intel_display.h  |  10 +
 .../drm/i915/display/intel_display_types.h    |   9 +
 drivers/gpu/drm/i915/display/intel_fdi.c      | 682 +++++++++++++++++
 5 files changed, 704 insertions(+), 682 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/display/intel_fdi.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 8b357c212ae2..f74b7c13ffbd 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -206,6 +206,7 @@ i915-y += \
 	display/intel_dpll_mgr.o \
 	display/intel_dsb.o \
 	display/intel_fbc.o \
+	display/intel_fdi.o \
 	display/intel_fifo_underrun.o \
 	display/intel_frontbuffer.o \
 	display/intel_global_state.o \
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 788b1def61ee..5119a0040e36 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -170,16 +170,6 @@ static void intel_update_czclk(struct drm_i915_private *dev_priv)
 		dev_priv->czclk_freq);
 }
 
-/* units of 100MHz */
-static u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
-			       const struct intel_crtc_state *pipe_config)
-{
-	if (HAS_DDI(dev_priv))
-		return pipe_config->port_clock; /* SPLL */
-	else
-		return dev_priv->fdi_pll_freq;
-}
-
 /* WA Display #0827: Gen9:all */
 static void
 skl_wa_827(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable)
@@ -3776,532 +3766,6 @@ static void icl_set_pipe_chicken(struct intel_crtc *crtc)
 	intel_de_write(dev_priv, PIPE_CHICKEN(pipe), tmp);
 }
 
-static void intel_fdi_normal_train(struct intel_crtc *crtc)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	enum pipe pipe = crtc->pipe;
-	i915_reg_t reg;
-	u32 temp;
-
-	/* enable normal train */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	if (IS_IVYBRIDGE(dev_priv)) {
-		temp &= ~FDI_LINK_TRAIN_NONE_IVB;
-		temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
-	} else {
-		temp &= ~FDI_LINK_TRAIN_NONE;
-		temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
-	}
-	intel_de_write(dev_priv, reg, temp);
-
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	if (HAS_PCH_CPT(dev_priv)) {
-		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-		temp |= FDI_LINK_TRAIN_NORMAL_CPT;
-	} else {
-		temp &= ~FDI_LINK_TRAIN_NONE;
-		temp |= FDI_LINK_TRAIN_NONE;
-	}
-	intel_de_write(dev_priv, reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-
-	/* wait one idle pattern time */
-	intel_de_posting_read(dev_priv, reg);
-	udelay(1000);
-
-	/* IVB wants error correction enabled */
-	if (IS_IVYBRIDGE(dev_priv))
-		intel_de_write(dev_priv, reg,
-		               intel_de_read(dev_priv, reg) | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
-}
-
-/* The FDI link training functions for ILK/Ibexpeak. */
-static void ilk_fdi_link_train(struct intel_crtc *crtc,
-			       const struct intel_crtc_state *crtc_state)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	enum pipe pipe = crtc->pipe;
-	i915_reg_t reg;
-	u32 temp, tries;
-
-	/* FDI needs bits from pipe first */
-	assert_pipe_enabled(dev_priv, crtc_state->cpu_transcoder);
-
-	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
-	   for train result */
-	reg = FDI_RX_IMR(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_RX_SYMBOL_LOCK;
-	temp &= ~FDI_RX_BIT_LOCK;
-	intel_de_write(dev_priv, reg, temp);
-	intel_de_read(dev_priv, reg);
-	udelay(150);
-
-	/* enable CPU FDI TX and PCH FDI RX */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_DP_PORT_WIDTH_MASK;
-	temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
-	temp &= ~FDI_LINK_TRAIN_NONE;
-	temp |= FDI_LINK_TRAIN_PATTERN_1;
-	intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
-
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_LINK_TRAIN_NONE;
-	temp |= FDI_LINK_TRAIN_PATTERN_1;
-	intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(150);
-
-	/* Ironlake workaround, enable clock pointer after FDI enable*/
-	intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
-		       FDI_RX_PHASE_SYNC_POINTER_OVR);
-	intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
-		       FDI_RX_PHASE_SYNC_POINTER_OVR | FDI_RX_PHASE_SYNC_POINTER_EN);
-
-	reg = FDI_RX_IIR(pipe);
-	for (tries = 0; tries < 5; tries++) {
-		temp = intel_de_read(dev_priv, reg);
-		drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
-
-		if ((temp & FDI_RX_BIT_LOCK)) {
-			drm_dbg_kms(&dev_priv->drm, "FDI train 1 done.\n");
-			intel_de_write(dev_priv, reg, temp | FDI_RX_BIT_LOCK);
-			break;
-		}
-	}
-	if (tries == 5)
-		drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
-
-	/* Train 2 */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_LINK_TRAIN_NONE;
-	temp |= FDI_LINK_TRAIN_PATTERN_2;
-	intel_de_write(dev_priv, reg, temp);
-
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_LINK_TRAIN_NONE;
-	temp |= FDI_LINK_TRAIN_PATTERN_2;
-	intel_de_write(dev_priv, reg, temp);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(150);
-
-	reg = FDI_RX_IIR(pipe);
-	for (tries = 0; tries < 5; tries++) {
-		temp = intel_de_read(dev_priv, reg);
-		drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
-
-		if (temp & FDI_RX_SYMBOL_LOCK) {
-			intel_de_write(dev_priv, reg,
-				       temp | FDI_RX_SYMBOL_LOCK);
-			drm_dbg_kms(&dev_priv->drm, "FDI train 2 done.\n");
-			break;
-		}
-	}
-	if (tries == 5)
-		drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
-
-	drm_dbg_kms(&dev_priv->drm, "FDI train done\n");
-
-}
-
-static const int snb_b_fdi_train_param[] = {
-	FDI_LINK_TRAIN_400MV_0DB_SNB_B,
-	FDI_LINK_TRAIN_400MV_6DB_SNB_B,
-	FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
-	FDI_LINK_TRAIN_800MV_0DB_SNB_B,
-};
-
-/* The FDI link training functions for SNB/Cougarpoint. */
-static void gen6_fdi_link_train(struct intel_crtc *crtc,
-				const struct intel_crtc_state *crtc_state)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	enum pipe pipe = crtc->pipe;
-	i915_reg_t reg;
-	u32 temp, i, retry;
-
-	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
-	   for train result */
-	reg = FDI_RX_IMR(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_RX_SYMBOL_LOCK;
-	temp &= ~FDI_RX_BIT_LOCK;
-	intel_de_write(dev_priv, reg, temp);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(150);
-
-	/* enable CPU FDI TX and PCH FDI RX */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_DP_PORT_WIDTH_MASK;
-	temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
-	temp &= ~FDI_LINK_TRAIN_NONE;
-	temp |= FDI_LINK_TRAIN_PATTERN_1;
-	temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
-	/* SNB-B */
-	temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
-	intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
-
-	intel_de_write(dev_priv, FDI_RX_MISC(pipe),
-		       FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
-
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	if (HAS_PCH_CPT(dev_priv)) {
-		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
-	} else {
-		temp &= ~FDI_LINK_TRAIN_NONE;
-		temp |= FDI_LINK_TRAIN_PATTERN_1;
-	}
-	intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(150);
-
-	for (i = 0; i < 4; i++) {
-		reg = FDI_TX_CTL(pipe);
-		temp = intel_de_read(dev_priv, reg);
-		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
-		temp |= snb_b_fdi_train_param[i];
-		intel_de_write(dev_priv, reg, temp);
-
-		intel_de_posting_read(dev_priv, reg);
-		udelay(500);
-
-		for (retry = 0; retry < 5; retry++) {
-			reg = FDI_RX_IIR(pipe);
-			temp = intel_de_read(dev_priv, reg);
-			drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
-			if (temp & FDI_RX_BIT_LOCK) {
-				intel_de_write(dev_priv, reg,
-					       temp | FDI_RX_BIT_LOCK);
-				drm_dbg_kms(&dev_priv->drm,
-					    "FDI train 1 done.\n");
-				break;
-			}
-			udelay(50);
-		}
-		if (retry < 5)
-			break;
-	}
-	if (i == 4)
-		drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
-
-	/* Train 2 */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_LINK_TRAIN_NONE;
-	temp |= FDI_LINK_TRAIN_PATTERN_2;
-	if (IS_GEN(dev_priv, 6)) {
-		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
-		/* SNB-B */
-		temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
-	}
-	intel_de_write(dev_priv, reg, temp);
-
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	if (HAS_PCH_CPT(dev_priv)) {
-		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-		temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
-	} else {
-		temp &= ~FDI_LINK_TRAIN_NONE;
-		temp |= FDI_LINK_TRAIN_PATTERN_2;
-	}
-	intel_de_write(dev_priv, reg, temp);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(150);
-
-	for (i = 0; i < 4; i++) {
-		reg = FDI_TX_CTL(pipe);
-		temp = intel_de_read(dev_priv, reg);
-		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
-		temp |= snb_b_fdi_train_param[i];
-		intel_de_write(dev_priv, reg, temp);
-
-		intel_de_posting_read(dev_priv, reg);
-		udelay(500);
-
-		for (retry = 0; retry < 5; retry++) {
-			reg = FDI_RX_IIR(pipe);
-			temp = intel_de_read(dev_priv, reg);
-			drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
-			if (temp & FDI_RX_SYMBOL_LOCK) {
-				intel_de_write(dev_priv, reg,
-					       temp | FDI_RX_SYMBOL_LOCK);
-				drm_dbg_kms(&dev_priv->drm,
-					    "FDI train 2 done.\n");
-				break;
-			}
-			udelay(50);
-		}
-		if (retry < 5)
-			break;
-	}
-	if (i == 4)
-		drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
-
-	drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
-}
-
-/* Manual link training for Ivy Bridge A0 parts */
-static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
-				      const struct intel_crtc_state *crtc_state)
-{
-	struct drm_device *dev = crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	enum pipe pipe = crtc->pipe;
-	i915_reg_t reg;
-	u32 temp, i, j;
-
-	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
-	   for train result */
-	reg = FDI_RX_IMR(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_RX_SYMBOL_LOCK;
-	temp &= ~FDI_RX_BIT_LOCK;
-	intel_de_write(dev_priv, reg, temp);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(150);
-
-	drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR before link train 0x%x\n",
-		    intel_de_read(dev_priv, FDI_RX_IIR(pipe)));
-
-	/* Try each vswing and preemphasis setting twice before moving on */
-	for (j = 0; j < ARRAY_SIZE(snb_b_fdi_train_param) * 2; j++) {
-		/* disable first in case we need to retry */
-		reg = FDI_TX_CTL(pipe);
-		temp = intel_de_read(dev_priv, reg);
-		temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
-		temp &= ~FDI_TX_ENABLE;
-		intel_de_write(dev_priv, reg, temp);
-
-		reg = FDI_RX_CTL(pipe);
-		temp = intel_de_read(dev_priv, reg);
-		temp &= ~FDI_LINK_TRAIN_AUTO;
-		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-		temp &= ~FDI_RX_ENABLE;
-		intel_de_write(dev_priv, reg, temp);
-
-		/* enable CPU FDI TX and PCH FDI RX */
-		reg = FDI_TX_CTL(pipe);
-		temp = intel_de_read(dev_priv, reg);
-		temp &= ~FDI_DP_PORT_WIDTH_MASK;
-		temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
-		temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
-		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
-		temp |= snb_b_fdi_train_param[j/2];
-		temp |= FDI_COMPOSITE_SYNC;
-		intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
-
-		intel_de_write(dev_priv, FDI_RX_MISC(pipe),
-			       FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
-
-		reg = FDI_RX_CTL(pipe);
-		temp = intel_de_read(dev_priv, reg);
-		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
-		temp |= FDI_COMPOSITE_SYNC;
-		intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
-
-		intel_de_posting_read(dev_priv, reg);
-		udelay(1); /* should be 0.5us */
-
-		for (i = 0; i < 4; i++) {
-			reg = FDI_RX_IIR(pipe);
-			temp = intel_de_read(dev_priv, reg);
-			drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
-
-			if (temp & FDI_RX_BIT_LOCK ||
-			    (intel_de_read(dev_priv, reg) & FDI_RX_BIT_LOCK)) {
-				intel_de_write(dev_priv, reg,
-					       temp | FDI_RX_BIT_LOCK);
-				drm_dbg_kms(&dev_priv->drm,
-					    "FDI train 1 done, level %i.\n",
-					    i);
-				break;
-			}
-			udelay(1); /* should be 0.5us */
-		}
-		if (i == 4) {
-			drm_dbg_kms(&dev_priv->drm,
-				    "FDI train 1 fail on vswing %d\n", j / 2);
-			continue;
-		}
-
-		/* Train 2 */
-		reg = FDI_TX_CTL(pipe);
-		temp = intel_de_read(dev_priv, reg);
-		temp &= ~FDI_LINK_TRAIN_NONE_IVB;
-		temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
-		intel_de_write(dev_priv, reg, temp);
-
-		reg = FDI_RX_CTL(pipe);
-		temp = intel_de_read(dev_priv, reg);
-		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-		temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
-		intel_de_write(dev_priv, reg, temp);
-
-		intel_de_posting_read(dev_priv, reg);
-		udelay(2); /* should be 1.5us */
-
-		for (i = 0; i < 4; i++) {
-			reg = FDI_RX_IIR(pipe);
-			temp = intel_de_read(dev_priv, reg);
-			drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
-
-			if (temp & FDI_RX_SYMBOL_LOCK ||
-			    (intel_de_read(dev_priv, reg) & FDI_RX_SYMBOL_LOCK)) {
-				intel_de_write(dev_priv, reg,
-					       temp | FDI_RX_SYMBOL_LOCK);
-				drm_dbg_kms(&dev_priv->drm,
-					    "FDI train 2 done, level %i.\n",
-					    i);
-				goto train_done;
-			}
-			udelay(2); /* should be 1.5us */
-		}
-		if (i == 4)
-			drm_dbg_kms(&dev_priv->drm,
-				    "FDI train 2 fail on vswing %d\n", j / 2);
-	}
-
-train_done:
-	drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
-}
-
-static void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state)
-{
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
-	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
-	enum pipe pipe = intel_crtc->pipe;
-	i915_reg_t reg;
-	u32 temp;
-
-	/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
-	temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
-	temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
-	intel_de_write(dev_priv, reg, temp | FDI_RX_PLL_ENABLE);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(200);
-
-	/* Switch from Rawclk to PCDclk */
-	temp = intel_de_read(dev_priv, reg);
-	intel_de_write(dev_priv, reg, temp | FDI_PCDCLK);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(200);
-
-	/* Enable CPU FDI TX PLL, always on for Ironlake */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	if ((temp & FDI_TX_PLL_ENABLE) == 0) {
-		intel_de_write(dev_priv, reg, temp | FDI_TX_PLL_ENABLE);
-
-		intel_de_posting_read(dev_priv, reg);
-		udelay(100);
-	}
-}
-
-static void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc)
-{
-	struct drm_device *dev = intel_crtc->base.dev;
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	enum pipe pipe = intel_crtc->pipe;
-	i915_reg_t reg;
-	u32 temp;
-
-	/* Switch from PCDclk to Rawclk */
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	intel_de_write(dev_priv, reg, temp & ~FDI_PCDCLK);
-
-	/* Disable CPU FDI TX PLL */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	intel_de_write(dev_priv, reg, temp & ~FDI_TX_PLL_ENABLE);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(100);
-
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	intel_de_write(dev_priv, reg, temp & ~FDI_RX_PLL_ENABLE);
-
-	/* Wait for the clocks to turn off. */
-	intel_de_posting_read(dev_priv, reg);
-	udelay(100);
-}
-
-static void ilk_fdi_disable(struct intel_crtc *crtc)
-{
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	enum pipe pipe = crtc->pipe;
-	i915_reg_t reg;
-	u32 temp;
-
-	/* disable CPU FDI tx and PCH FDI rx */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	intel_de_write(dev_priv, reg, temp & ~FDI_TX_ENABLE);
-	intel_de_posting_read(dev_priv, reg);
-
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~(0x7 << 16);
-	temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
-	intel_de_write(dev_priv, reg, temp & ~FDI_RX_ENABLE);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(100);
-
-	/* Ironlake workaround, disable clock pointer after downing FDI */
-	if (HAS_PCH_IBX(dev_priv))
-		intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
-			       FDI_RX_PHASE_SYNC_POINTER_OVR);
-
-	/* still set train pattern 1 */
-	reg = FDI_TX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	temp &= ~FDI_LINK_TRAIN_NONE;
-	temp |= FDI_LINK_TRAIN_PATTERN_1;
-	intel_de_write(dev_priv, reg, temp);
-
-	reg = FDI_RX_CTL(pipe);
-	temp = intel_de_read(dev_priv, reg);
-	if (HAS_PCH_CPT(dev_priv)) {
-		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
-	} else {
-		temp &= ~FDI_LINK_TRAIN_NONE;
-		temp |= FDI_LINK_TRAIN_PATTERN_1;
-	}
-	/* BPC in FDI rx is consistent with that in PIPECONF */
-	temp &= ~(0x07 << 16);
-	temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
-	intel_de_write(dev_priv, reg, temp);
-
-	intel_de_posting_read(dev_priv, reg);
-	udelay(100);
-}
-
 bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv)
 {
 	struct drm_crtc *crtc;
@@ -6708,143 +6172,6 @@ static void intel_connector_verify_state(struct intel_crtc_state *crtc_state,
 	}
 }
 
-static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
-{
-	if (crtc_state->hw.enable && crtc_state->has_pch_encoder)
-		return crtc_state->fdi_lanes;
-
-	return 0;
-}
-
-static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
-			       struct intel_crtc_state *pipe_config)
-{
-	struct drm_i915_private *dev_priv = to_i915(dev);
-	struct drm_atomic_state *state = pipe_config->uapi.state;
-	struct intel_crtc *other_crtc;
-	struct intel_crtc_state *other_crtc_state;
-
-	drm_dbg_kms(&dev_priv->drm,
-		    "checking fdi config on pipe %c, lanes %i\n",
-		    pipe_name(pipe), pipe_config->fdi_lanes);
-	if (pipe_config->fdi_lanes > 4) {
-		drm_dbg_kms(&dev_priv->drm,
-			    "invalid fdi lane config on pipe %c: %i lanes\n",
-			    pipe_name(pipe), pipe_config->fdi_lanes);
-		return -EINVAL;
-	}
-
-	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
-		if (pipe_config->fdi_lanes > 2) {
-			drm_dbg_kms(&dev_priv->drm,
-				    "only 2 lanes on haswell, required: %i lanes\n",
-				    pipe_config->fdi_lanes);
-			return -EINVAL;
-		} else {
-			return 0;
-		}
-	}
-
-	if (INTEL_NUM_PIPES(dev_priv) == 2)
-		return 0;
-
-	/* Ivybridge 3 pipe is really complicated */
-	switch (pipe) {
-	case PIPE_A:
-		return 0;
-	case PIPE_B:
-		if (pipe_config->fdi_lanes <= 2)
-			return 0;
-
-		other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_C);
-		other_crtc_state =
-			intel_atomic_get_crtc_state(state, other_crtc);
-		if (IS_ERR(other_crtc_state))
-			return PTR_ERR(other_crtc_state);
-
-		if (pipe_required_fdi_lanes(other_crtc_state) > 0) {
-			drm_dbg_kms(&dev_priv->drm,
-				    "invalid shared fdi lane config on pipe %c: %i lanes\n",
-				    pipe_name(pipe), pipe_config->fdi_lanes);
-			return -EINVAL;
-		}
-		return 0;
-	case PIPE_C:
-		if (pipe_config->fdi_lanes > 2) {
-			drm_dbg_kms(&dev_priv->drm,
-				    "only 2 lanes on pipe %c: required %i lanes\n",
-				    pipe_name(pipe), pipe_config->fdi_lanes);
-			return -EINVAL;
-		}
-
-		other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_B);
-		other_crtc_state =
-			intel_atomic_get_crtc_state(state, other_crtc);
-		if (IS_ERR(other_crtc_state))
-			return PTR_ERR(other_crtc_state);
-
-		if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
-			drm_dbg_kms(&dev_priv->drm,
-				    "fdi link B uses too many lanes to enable link C\n");
-			return -EINVAL;
-		}
-		return 0;
-	default:
-		BUG();
-	}
-}
-
-#define RETRY 1
-static int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
-				  struct intel_crtc_state *pipe_config)
-{
-	struct drm_device *dev = intel_crtc->base.dev;
-	struct drm_i915_private *i915 = to_i915(dev);
-	const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
-	int lane, link_bw, fdi_dotclock, ret;
-	bool needs_recompute = false;
-
-retry:
-	/* FDI is a binary signal running at ~2.7GHz, encoding
-	 * each output octet as 10 bits. The actual frequency
-	 * is stored as a divider into a 100MHz clock, and the
-	 * mode pixel clock is stored in units of 1KHz.
-	 * Hence the bw of each lane in terms of the mode signal
-	 * is:
-	 */
-	link_bw = intel_fdi_link_freq(i915, pipe_config);
-
-	fdi_dotclock = adjusted_mode->crtc_clock;
-
-	lane = ilk_get_lanes_required(fdi_dotclock, link_bw,
-				      pipe_config->pipe_bpp);
-
-	pipe_config->fdi_lanes = lane;
-
-	intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
-			       link_bw, &pipe_config->fdi_m_n, false, false);
-
-	ret = ilk_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
-	if (ret == -EDEADLK)
-		return ret;
-
-	if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
-		pipe_config->pipe_bpp -= 2*3;
-		drm_dbg_kms(&i915->drm,
-			    "fdi link bw constraint, reducing pipe bpp to %i\n",
-			    pipe_config->pipe_bpp);
-		needs_recompute = true;
-		pipe_config->bw_constrained = true;
-
-		goto retry;
-	}
-
-	if (needs_recompute)
-		return RETRY;
-
-	return ret;
-}
-
 bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
@@ -11379,7 +10706,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
 		return ret;
 	}
 
-	if (ret == RETRY) {
+	if (ret == I915_DISPLAY_CONFIG_RETRY) {
 		if (drm_WARN(&i915->drm, !retry,
 			     "loop in pipe configuration computation\n"))
 			return -EINVAL;
@@ -15178,14 +14505,7 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
 	}
 
-	if (IS_GEN(dev_priv, 5)) {
-		dev_priv->display.fdi_link_train = ilk_fdi_link_train;
-	} else if (IS_GEN(dev_priv, 6)) {
-		dev_priv->display.fdi_link_train = gen6_fdi_link_train;
-	} else if (IS_IVYBRIDGE(dev_priv)) {
-		/* FIXME: detect B0+ stepping and use auto training */
-		dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
-	}
+	intel_init_fdi_hook(dev_priv);
 
 	if (INTEL_GEN(dev_priv) >= 9) {
 		dev_priv->display.commit_modeset_enables = skl_commit_modeset_enables;
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index f1e36cca86c1..731ea6f7777a 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -677,6 +677,16 @@ void vlv_compute_dpll(struct intel_crtc *crtc,
 void chv_compute_dpll(struct intel_crtc *crtc,
 		      struct intel_crtc_state *pipe_config);
 
+/* fdi */
+#define I915_DISPLAY_CONFIG_RETRY 1
+int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
+			   struct intel_crtc_state *pipe_config);
+void intel_fdi_normal_train(struct intel_crtc *crtc);
+void ilk_fdi_disable(struct intel_crtc *crtc);
+void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc);
+void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state);
+void intel_init_fdi_hook(struct drm_i915_private *dev_priv);
+
 /* modesetting */
 void intel_modeset_init_hw(struct drm_i915_private *i915);
 int intel_modeset_init_noirq(struct drm_i915_private *i915);
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 823083b231bc..9c684552903c 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1804,4 +1804,13 @@ static inline u32 i9xx_dpll_compute_fp(struct dpll *dpll)
 	return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
 }
 
+static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
+				      const struct intel_crtc_state *pipe_config)
+{
+	if (HAS_DDI(dev_priv))
+		return pipe_config->port_clock; /* SPLL */
+	else
+		return dev_priv->fdi_pll_freq;
+}
+
 #endif /*  __INTEL_DISPLAY_TYPES_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c
new file mode 100644
index 000000000000..bf4ef84686ef
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_fdi.c
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+#include "intel_atomic.h"
+#include "intel_display_types.h"
+
+/* units of 100MHz */
+static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
+{
+	if (crtc_state->hw.enable && crtc_state->has_pch_encoder)
+		return crtc_state->fdi_lanes;
+
+	return 0;
+}
+
+static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
+			       struct intel_crtc_state *pipe_config)
+{
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_atomic_state *state = pipe_config->uapi.state;
+	struct intel_crtc *other_crtc;
+	struct intel_crtc_state *other_crtc_state;
+
+	drm_dbg_kms(&dev_priv->drm,
+		    "checking fdi config on pipe %c, lanes %i\n",
+		    pipe_name(pipe), pipe_config->fdi_lanes);
+	if (pipe_config->fdi_lanes > 4) {
+		drm_dbg_kms(&dev_priv->drm,
+			    "invalid fdi lane config on pipe %c: %i lanes\n",
+			    pipe_name(pipe), pipe_config->fdi_lanes);
+		return -EINVAL;
+	}
+
+	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
+		if (pipe_config->fdi_lanes > 2) {
+			drm_dbg_kms(&dev_priv->drm,
+				    "only 2 lanes on haswell, required: %i lanes\n",
+				    pipe_config->fdi_lanes);
+			return -EINVAL;
+		} else {
+			return 0;
+		}
+	}
+
+	if (INTEL_NUM_PIPES(dev_priv) == 2)
+		return 0;
+
+	/* Ivybridge 3 pipe is really complicated */
+	switch (pipe) {
+	case PIPE_A:
+		return 0;
+	case PIPE_B:
+		if (pipe_config->fdi_lanes <= 2)
+			return 0;
+
+		other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_C);
+		other_crtc_state =
+			intel_atomic_get_crtc_state(state, other_crtc);
+		if (IS_ERR(other_crtc_state))
+			return PTR_ERR(other_crtc_state);
+
+		if (pipe_required_fdi_lanes(other_crtc_state) > 0) {
+			drm_dbg_kms(&dev_priv->drm,
+				    "invalid shared fdi lane config on pipe %c: %i lanes\n",
+				    pipe_name(pipe), pipe_config->fdi_lanes);
+			return -EINVAL;
+		}
+		return 0;
+	case PIPE_C:
+		if (pipe_config->fdi_lanes > 2) {
+			drm_dbg_kms(&dev_priv->drm,
+				    "only 2 lanes on pipe %c: required %i lanes\n",
+				    pipe_name(pipe), pipe_config->fdi_lanes);
+			return -EINVAL;
+		}
+
+		other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_B);
+		other_crtc_state =
+			intel_atomic_get_crtc_state(state, other_crtc);
+		if (IS_ERR(other_crtc_state))
+			return PTR_ERR(other_crtc_state);
+
+		if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
+			drm_dbg_kms(&dev_priv->drm,
+				    "fdi link B uses too many lanes to enable link C\n");
+			return -EINVAL;
+		}
+		return 0;
+	default:
+		BUG();
+	}
+}
+
+int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
+				  struct intel_crtc_state *pipe_config)
+{
+	struct drm_device *dev = intel_crtc->base.dev;
+	struct drm_i915_private *i915 = to_i915(dev);
+	const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
+	int lane, link_bw, fdi_dotclock, ret;
+	bool needs_recompute = false;
+
+retry:
+	/* FDI is a binary signal running at ~2.7GHz, encoding
+	 * each output octet as 10 bits. The actual frequency
+	 * is stored as a divider into a 100MHz clock, and the
+	 * mode pixel clock is stored in units of 1KHz.
+	 * Hence the bw of each lane in terms of the mode signal
+	 * is:
+	 */
+	link_bw = intel_fdi_link_freq(i915, pipe_config);
+
+	fdi_dotclock = adjusted_mode->crtc_clock;
+
+	lane = ilk_get_lanes_required(fdi_dotclock, link_bw,
+				      pipe_config->pipe_bpp);
+
+	pipe_config->fdi_lanes = lane;
+
+	intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
+			       link_bw, &pipe_config->fdi_m_n, false, false);
+
+	ret = ilk_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
+	if (ret == -EDEADLK)
+		return ret;
+
+	if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
+		pipe_config->pipe_bpp -= 2*3;
+		drm_dbg_kms(&i915->drm,
+			    "fdi link bw constraint, reducing pipe bpp to %i\n",
+			    pipe_config->pipe_bpp);
+		needs_recompute = true;
+		pipe_config->bw_constrained = true;
+
+		goto retry;
+	}
+
+	if (needs_recompute)
+		return I915_DISPLAY_CONFIG_RETRY;
+
+	return ret;
+}
+
+void intel_fdi_normal_train(struct intel_crtc *crtc)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	enum pipe pipe = crtc->pipe;
+	i915_reg_t reg;
+	u32 temp;
+
+	/* enable normal train */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	if (IS_IVYBRIDGE(dev_priv)) {
+		temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+		temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+	}
+	intel_de_write(dev_priv, reg, temp);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	if (HAS_PCH_CPT(dev_priv)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_NONE;
+	}
+	intel_de_write(dev_priv, reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+	/* wait one idle pattern time */
+	intel_de_posting_read(dev_priv, reg);
+	udelay(1000);
+
+	/* IVB wants error correction enabled */
+	if (IS_IVYBRIDGE(dev_priv))
+		intel_de_write(dev_priv, reg,
+			       intel_de_read(dev_priv, reg) | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
+}
+
+/* The FDI link training functions for ILK/Ibexpeak. */
+static void ilk_fdi_link_train(struct intel_crtc *crtc,
+			       const struct intel_crtc_state *crtc_state)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	enum pipe pipe = crtc->pipe;
+	i915_reg_t reg;
+	u32 temp, tries;
+
+	/* FDI needs bits from pipe first */
+	assert_pipe_enabled(dev_priv, crtc_state->cpu_transcoder);
+
+	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+	   for train result */
+	reg = FDI_RX_IMR(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_RX_SYMBOL_LOCK;
+	temp &= ~FDI_RX_BIT_LOCK;
+	intel_de_write(dev_priv, reg, temp);
+	intel_de_read(dev_priv, reg);
+	udelay(150);
+
+	/* enable CPU FDI TX and PCH FDI RX */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_DP_PORT_WIDTH_MASK;
+	temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_1;
+	intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_1;
+	intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(150);
+
+	/* Ironlake workaround, enable clock pointer after FDI enable*/
+	intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
+		       FDI_RX_PHASE_SYNC_POINTER_OVR);
+	intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
+		       FDI_RX_PHASE_SYNC_POINTER_OVR | FDI_RX_PHASE_SYNC_POINTER_EN);
+
+	reg = FDI_RX_IIR(pipe);
+	for (tries = 0; tries < 5; tries++) {
+		temp = intel_de_read(dev_priv, reg);
+		drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
+
+		if ((temp & FDI_RX_BIT_LOCK)) {
+			drm_dbg_kms(&dev_priv->drm, "FDI train 1 done.\n");
+			intel_de_write(dev_priv, reg, temp | FDI_RX_BIT_LOCK);
+			break;
+		}
+	}
+	if (tries == 5)
+		drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
+
+	/* Train 2 */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_2;
+	intel_de_write(dev_priv, reg, temp);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_2;
+	intel_de_write(dev_priv, reg, temp);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(150);
+
+	reg = FDI_RX_IIR(pipe);
+	for (tries = 0; tries < 5; tries++) {
+		temp = intel_de_read(dev_priv, reg);
+		drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
+
+		if (temp & FDI_RX_SYMBOL_LOCK) {
+			intel_de_write(dev_priv, reg,
+				       temp | FDI_RX_SYMBOL_LOCK);
+			drm_dbg_kms(&dev_priv->drm, "FDI train 2 done.\n");
+			break;
+		}
+	}
+	if (tries == 5)
+		drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
+
+	drm_dbg_kms(&dev_priv->drm, "FDI train done\n");
+
+}
+
+static const int snb_b_fdi_train_param[] = {
+	FDI_LINK_TRAIN_400MV_0DB_SNB_B,
+	FDI_LINK_TRAIN_400MV_6DB_SNB_B,
+	FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
+	FDI_LINK_TRAIN_800MV_0DB_SNB_B,
+};
+
+/* The FDI link training functions for SNB/Cougarpoint. */
+static void gen6_fdi_link_train(struct intel_crtc *crtc,
+				const struct intel_crtc_state *crtc_state)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	enum pipe pipe = crtc->pipe;
+	i915_reg_t reg;
+	u32 temp, i, retry;
+
+	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+	   for train result */
+	reg = FDI_RX_IMR(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_RX_SYMBOL_LOCK;
+	temp &= ~FDI_RX_BIT_LOCK;
+	intel_de_write(dev_priv, reg, temp);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(150);
+
+	/* enable CPU FDI TX and PCH FDI RX */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_DP_PORT_WIDTH_MASK;
+	temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_1;
+	temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+	/* SNB-B */
+	temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+	intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
+
+	intel_de_write(dev_priv, FDI_RX_MISC(pipe),
+		       FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	if (HAS_PCH_CPT(dev_priv)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_1;
+	}
+	intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(150);
+
+	for (i = 0; i < 4; i++) {
+		reg = FDI_TX_CTL(pipe);
+		temp = intel_de_read(dev_priv, reg);
+		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+		temp |= snb_b_fdi_train_param[i];
+		intel_de_write(dev_priv, reg, temp);
+
+		intel_de_posting_read(dev_priv, reg);
+		udelay(500);
+
+		for (retry = 0; retry < 5; retry++) {
+			reg = FDI_RX_IIR(pipe);
+			temp = intel_de_read(dev_priv, reg);
+			drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
+			if (temp & FDI_RX_BIT_LOCK) {
+				intel_de_write(dev_priv, reg,
+					       temp | FDI_RX_BIT_LOCK);
+				drm_dbg_kms(&dev_priv->drm,
+					    "FDI train 1 done.\n");
+				break;
+			}
+			udelay(50);
+		}
+		if (retry < 5)
+			break;
+	}
+	if (i == 4)
+		drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
+
+	/* Train 2 */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_2;
+	if (IS_GEN(dev_priv, 6)) {
+		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+		/* SNB-B */
+		temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+	}
+	intel_de_write(dev_priv, reg, temp);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	if (HAS_PCH_CPT(dev_priv)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_2;
+	}
+	intel_de_write(dev_priv, reg, temp);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(150);
+
+	for (i = 0; i < 4; i++) {
+		reg = FDI_TX_CTL(pipe);
+		temp = intel_de_read(dev_priv, reg);
+		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+		temp |= snb_b_fdi_train_param[i];
+		intel_de_write(dev_priv, reg, temp);
+
+		intel_de_posting_read(dev_priv, reg);
+		udelay(500);
+
+		for (retry = 0; retry < 5; retry++) {
+			reg = FDI_RX_IIR(pipe);
+			temp = intel_de_read(dev_priv, reg);
+			drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
+			if (temp & FDI_RX_SYMBOL_LOCK) {
+				intel_de_write(dev_priv, reg,
+					       temp | FDI_RX_SYMBOL_LOCK);
+				drm_dbg_kms(&dev_priv->drm,
+					    "FDI train 2 done.\n");
+				break;
+			}
+			udelay(50);
+		}
+		if (retry < 5)
+			break;
+	}
+	if (i == 4)
+		drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
+
+	drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
+}
+
+/* Manual link training for Ivy Bridge A0 parts */
+static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
+				      const struct intel_crtc_state *crtc_state)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	enum pipe pipe = crtc->pipe;
+	i915_reg_t reg;
+	u32 temp, i, j;
+
+	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+	   for train result */
+	reg = FDI_RX_IMR(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_RX_SYMBOL_LOCK;
+	temp &= ~FDI_RX_BIT_LOCK;
+	intel_de_write(dev_priv, reg, temp);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(150);
+
+	drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR before link train 0x%x\n",
+		    intel_de_read(dev_priv, FDI_RX_IIR(pipe)));
+
+	/* Try each vswing and preemphasis setting twice before moving on */
+	for (j = 0; j < ARRAY_SIZE(snb_b_fdi_train_param) * 2; j++) {
+		/* disable first in case we need to retry */
+		reg = FDI_TX_CTL(pipe);
+		temp = intel_de_read(dev_priv, reg);
+		temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
+		temp &= ~FDI_TX_ENABLE;
+		intel_de_write(dev_priv, reg, temp);
+
+		reg = FDI_RX_CTL(pipe);
+		temp = intel_de_read(dev_priv, reg);
+		temp &= ~FDI_LINK_TRAIN_AUTO;
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp &= ~FDI_RX_ENABLE;
+		intel_de_write(dev_priv, reg, temp);
+
+		/* enable CPU FDI TX and PCH FDI RX */
+		reg = FDI_TX_CTL(pipe);
+		temp = intel_de_read(dev_priv, reg);
+		temp &= ~FDI_DP_PORT_WIDTH_MASK;
+		temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
+		temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
+		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+		temp |= snb_b_fdi_train_param[j/2];
+		temp |= FDI_COMPOSITE_SYNC;
+		intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
+
+		intel_de_write(dev_priv, FDI_RX_MISC(pipe),
+			       FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
+
+		reg = FDI_RX_CTL(pipe);
+		temp = intel_de_read(dev_priv, reg);
+		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+		temp |= FDI_COMPOSITE_SYNC;
+		intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
+
+		intel_de_posting_read(dev_priv, reg);
+		udelay(1); /* should be 0.5us */
+
+		for (i = 0; i < 4; i++) {
+			reg = FDI_RX_IIR(pipe);
+			temp = intel_de_read(dev_priv, reg);
+			drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
+
+			if (temp & FDI_RX_BIT_LOCK ||
+			    (intel_de_read(dev_priv, reg) & FDI_RX_BIT_LOCK)) {
+				intel_de_write(dev_priv, reg,
+					       temp | FDI_RX_BIT_LOCK);
+				drm_dbg_kms(&dev_priv->drm,
+					    "FDI train 1 done, level %i.\n",
+					    i);
+				break;
+			}
+			udelay(1); /* should be 0.5us */
+		}
+		if (i == 4) {
+			drm_dbg_kms(&dev_priv->drm,
+				    "FDI train 1 fail on vswing %d\n", j / 2);
+			continue;
+		}
+
+		/* Train 2 */
+		reg = FDI_TX_CTL(pipe);
+		temp = intel_de_read(dev_priv, reg);
+		temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+		temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
+		intel_de_write(dev_priv, reg, temp);
+
+		reg = FDI_RX_CTL(pipe);
+		temp = intel_de_read(dev_priv, reg);
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+		intel_de_write(dev_priv, reg, temp);
+
+		intel_de_posting_read(dev_priv, reg);
+		udelay(2); /* should be 1.5us */
+
+		for (i = 0; i < 4; i++) {
+			reg = FDI_RX_IIR(pipe);
+			temp = intel_de_read(dev_priv, reg);
+			drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
+
+			if (temp & FDI_RX_SYMBOL_LOCK ||
+			    (intel_de_read(dev_priv, reg) & FDI_RX_SYMBOL_LOCK)) {
+				intel_de_write(dev_priv, reg,
+					       temp | FDI_RX_SYMBOL_LOCK);
+				drm_dbg_kms(&dev_priv->drm,
+					    "FDI train 2 done, level %i.\n",
+					    i);
+				goto train_done;
+			}
+			udelay(2); /* should be 1.5us */
+		}
+		if (i == 4)
+			drm_dbg_kms(&dev_priv->drm,
+				    "FDI train 2 fail on vswing %d\n", j / 2);
+	}
+
+train_done:
+	drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
+}
+
+void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
+	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
+	enum pipe pipe = intel_crtc->pipe;
+	i915_reg_t reg;
+	u32 temp;
+
+	/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
+	temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
+	temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
+	intel_de_write(dev_priv, reg, temp | FDI_RX_PLL_ENABLE);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(200);
+
+	/* Switch from Rawclk to PCDclk */
+	temp = intel_de_read(dev_priv, reg);
+	intel_de_write(dev_priv, reg, temp | FDI_PCDCLK);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(200);
+
+	/* Enable CPU FDI TX PLL, always on for Ironlake */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+		intel_de_write(dev_priv, reg, temp | FDI_TX_PLL_ENABLE);
+
+		intel_de_posting_read(dev_priv, reg);
+		udelay(100);
+	}
+}
+
+void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc)
+{
+	struct drm_device *dev = intel_crtc->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	enum pipe pipe = intel_crtc->pipe;
+	i915_reg_t reg;
+	u32 temp;
+
+	/* Switch from PCDclk to Rawclk */
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	intel_de_write(dev_priv, reg, temp & ~FDI_PCDCLK);
+
+	/* Disable CPU FDI TX PLL */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	intel_de_write(dev_priv, reg, temp & ~FDI_TX_PLL_ENABLE);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(100);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	intel_de_write(dev_priv, reg, temp & ~FDI_RX_PLL_ENABLE);
+
+	/* Wait for the clocks to turn off. */
+	intel_de_posting_read(dev_priv, reg);
+	udelay(100);
+}
+
+void ilk_fdi_disable(struct intel_crtc *crtc)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	enum pipe pipe = crtc->pipe;
+	i915_reg_t reg;
+	u32 temp;
+
+	/* disable CPU FDI tx and PCH FDI rx */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	intel_de_write(dev_priv, reg, temp & ~FDI_TX_ENABLE);
+	intel_de_posting_read(dev_priv, reg);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~(0x7 << 16);
+	temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
+	intel_de_write(dev_priv, reg, temp & ~FDI_RX_ENABLE);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(100);
+
+	/* Ironlake workaround, disable clock pointer after downing FDI */
+	if (HAS_PCH_IBX(dev_priv))
+		intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
+			       FDI_RX_PHASE_SYNC_POINTER_OVR);
+
+	/* still set train pattern 1 */
+	reg = FDI_TX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_1;
+	intel_de_write(dev_priv, reg, temp);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = intel_de_read(dev_priv, reg);
+	if (HAS_PCH_CPT(dev_priv)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_1;
+	}
+	/* BPC in FDI rx is consistent with that in PIPECONF */
+	temp &= ~(0x07 << 16);
+	temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
+	intel_de_write(dev_priv, reg, temp);
+
+	intel_de_posting_read(dev_priv, reg);
+	udelay(100);
+}
+
+void
+intel_init_fdi_hook(struct drm_i915_private *dev_priv)
+{
+	if (IS_GEN(dev_priv, 5)) {
+		dev_priv->display.fdi_link_train = ilk_fdi_link_train;
+	} else if (IS_GEN(dev_priv, 6)) {
+		dev_priv->display.fdi_link_train = gen6_fdi_link_train;
+	} else if (IS_IVYBRIDGE(dev_priv)) {
+		/* FIXME: detect B0+ stepping and use auto training */
+		dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
+	}
+}
-- 
2.27.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c
  2020-12-09  4:21 [Intel-gfx] [rfc] start slimming down intel_display.c Dave Airlie
                   ` (3 preceding siblings ...)
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 4/4] drm/i915: split fdi code out from intel_display.c Dave Airlie
@ 2020-12-09  4:56 ` Patchwork
  2020-12-09  5:26 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
  2020-12-09  6:41 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork
  6 siblings, 0 replies; 13+ messages in thread
From: Patchwork @ 2020-12-09  4:56 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c
URL   : https://patchwork.freedesktop.org/series/84712/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
b87be3dc234f drm/i915: refactor cursor code out of i915_display.c
-:24: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#24: 
new file mode 100644

-:534: WARNING:UNSPECIFIED_INT: Prefer 'unsigned int' to bare use of 'unsigned'
#534: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:506:
+		unsigned width = drm_rect_width(&plane_state->uapi.dst);

-:535: WARNING:UNSPECIFIED_INT: Prefer 'unsigned int' to bare use of 'unsigned'
#535: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:507:
+		unsigned height = drm_rect_height(&plane_state->uapi.dst);

-:564: WARNING:REPEATED_WORD: Possible repeated word: 'by'
#564: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:536:
+	 * The other registers are armed by by the CURBASE write

-:791: CHECK:SPACING: No space is necessary after a cast
#791: FILE: drivers/gpu/drm/i915/display/intel_cursor.c:763:
+	cursor->i9xx_plane = (enum i9xx_plane_id) pipe;

total: 0 errors, 4 warnings, 1 checks, 1692 lines checked
f86b532a437f drm/i915: refactor some crtc code out of intel display.
-:26: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#26: 
new file mode 100644

-:601: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#601: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:571:
+		return 32*1024;
 		         ^

-:604: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#604: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:574:
+			return 16*1024;
 			         ^

-:606: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#606: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:576:
+			return 32*1024;
 			         ^

-:609: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#609: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:579:
+			return 8*1024;
 			        ^

-:611: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#611: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:581:
+			return 16*1024;
 			         ^

-:614: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#614: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:584:
+			return 4*1024;
 			        ^

-:616: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#616: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:586:
+			return 8*1024;
 			        ^

-:663: CHECK:SPACING: No space is necessary after a cast
#663: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:633:
+		plane->i9xx_plane = (enum i9xx_plane_id) !pipe;

-:665: CHECK:SPACING: No space is necessary after a cast
#665: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:635:
+		plane->i9xx_plane = (enum i9xx_plane_id) pipe;

-:952: WARNING:AVOID_BUG: Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()
#952: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:922:
+	BUG_ON(pipe >= ARRAY_SIZE(dev_priv->pipe_to_crtc_mapping) ||

-:953: CHECK:COMPARISON_TO_NULL: Comparison to NULL could be written "dev_priv->pipe_to_crtc_mapping[pipe]"
#953: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:923:
+	       dev_priv->pipe_to_crtc_mapping[pipe] != NULL);

-:959: WARNING:AVOID_BUG: Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()
#959: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:929:
+		BUG_ON(i9xx_plane >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||

-:960: CHECK:COMPARISON_TO_NULL: Comparison to NULL could be written "dev_priv->plane_to_crtc_mapping[i9xx_plane]"
#960: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:930:
+		       dev_priv->plane_to_crtc_mapping[i9xx_plane] != NULL);

-:966: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#966: FILE: drivers/gpu/drm/i915/display/intel_crtc.c:936:
+		drm_crtc_create_scaling_filter_property(&crtc->base,
+						BIT(DRM_SCALING_FILTER_DEFAULT) |

total: 0 errors, 3 warnings, 12 checks, 1969 lines checked
b45ec2e66b7d drm/i915: refactor pll code out into intel_clock.c
-:30: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#30: 
new file mode 100644

-:50: CHECK:LOGICAL_CONTINUATIONS: Logical continuations should be on the previous line
#50: FILE: drivers/gpu/drm/i915/display/intel_clock.c:16:
+	return dev_priv->vbt.lvds_use_ssc
+		&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);

-:63: CHECK:LINE_SPACING: Please use a blank line after function/struct/union/enum declarations
#63: FILE: drivers/gpu/drm/i915/display/intel_clock.c:29:
+};
+static const struct intel_limit intel_limits_i8xx_dac = {

-:128: CHECK:LINE_SPACING: Please don't use multiple blank lines
#128: FILE: drivers/gpu/drm/i915/display/intel_clock.c:94:
+
+

-:700: WARNING:LONG_LINE: line length of 103 exceeds 100 columns
#700: FILE: drivers/gpu/drm/i915/display/intel_clock.c:666:
+				for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {

-:771: CHECK:SPACING: spaces preferred around that '/' (ctx:VxV)
#771: FILE: drivers/gpu/drm/i915/display/intel_clock.c:737:
+			if (m2 > INT_MAX/clock.m1)
 			                ^

-:868: CHECK:BRACES: braces {} should be used on all arms of this statement
#868: FILE: drivers/gpu/drm/i915/display/intel_clock.c:834:
+	if (IS_PINEVIEW(dev_priv))
[...]
+	else {
[...]

-:870: CHECK:BRACES: Unbalanced braces around else statement
#870: FILE: drivers/gpu/drm/i915/display/intel_clock.c:836:
+	else {

-:988: CHECK:LINE_SPACING: Please don't use multiple blank lines
#988: FILE: drivers/gpu/drm/i915/display/intel_clock.c:954:
+
+

total: 0 errors, 2 warnings, 7 checks, 2895 lines checked
a10cb379b7b4 drm/i915: split fdi code out from intel_display.c
-:785: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#785: 
new file mode 100644

-:880: WARNING:AVOID_BUG: Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()
#880: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:91:
+		BUG();

-:885: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#885: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:96:
+int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
+				  struct intel_crtc_state *pipe_config)

-:917: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#917: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:128:
+	if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
 	                                               ^

-:918: CHECK:SPACING: spaces preferred around that '*' (ctx:VxV)
#918: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:129:
+		pipe_config->pipe_bpp -= 2*3;
 		                          ^

-:967: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#967: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:178:
+	udelay(1000);

-:972: WARNING:LONG_LINE: line length of 103 exceeds 100 columns
#972: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:183:
+			       intel_de_read(dev_priv, reg) | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);

-:989: WARNING:BLOCK_COMMENT_STYLE: Block comments use * on subsequent lines
#989: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:200:
+	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+	   for train result */

-:989: WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line
#989: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:200:
+	   for train result */

-:996: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#996: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:207:
+	udelay(150);

-:1014: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1014: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:225:
+	udelay(150);

-:1050: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1050: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:261:
+	udelay(150);

-:1069: CHECK:BRACES: Blank lines aren't necessary before a close brace '}'
#1069: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:280:
+
+}

-:1089: WARNING:BLOCK_COMMENT_STYLE: Block comments use * on subsequent lines
#1089: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:300:
+	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+	   for train result */

-:1089: WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line
#1089: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:300:
+	   for train result */

-:1097: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1097: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:308:
+	udelay(150);

-:1126: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1126: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:337:
+	udelay(150);

-:1136: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1136: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:347:
+		udelay(500);

-:1149: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1149: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:360:
+			udelay(50);

-:1181: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1181: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:392:
+	udelay(150);

-:1191: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1191: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:402:
+		udelay(500);

-:1204: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1204: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:415:
+			udelay(50);

-:1226: WARNING:BLOCK_COMMENT_STYLE: Block comments use * on subsequent lines
#1226: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:437:
+	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+	   for train result */

-:1226: WARNING:BLOCK_COMMENT_STYLE: Block comments use a trailing */ on a separate line
#1226: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:437:
+	   for train result */

-:1234: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1234: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:445:
+	udelay(150);

-:1262: CHECK:SPACING: spaces preferred around that '/' (ctx:VxV)
#1262: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:473:
+		temp |= snb_b_fdi_train_param[j/2];
 		                               ^

-:1358: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1358: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:569:
+	udelay(200);

-:1365: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1365: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:576:
+	udelay(200);

-:1374: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1374: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:585:
+		udelay(100);

-:1397: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1397: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:608:
+	udelay(100);

-:1405: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1405: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:616:
+	udelay(100);

-:1428: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1428: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:639:
+	udelay(100);

-:1457: CHECK:USLEEP_RANGE: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst
#1457: FILE: drivers/gpu/drm/i915/display/intel_fdi.c:668:
+	udelay(100);

total: 0 errors, 9 warnings, 24 checks, 1432 lines checked


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Intel-gfx] ✓ Fi.CI.BAT: success for series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c
  2020-12-09  4:21 [Intel-gfx] [rfc] start slimming down intel_display.c Dave Airlie
                   ` (4 preceding siblings ...)
  2020-12-09  4:56 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c Patchwork
@ 2020-12-09  5:26 ` Patchwork
  2020-12-09  6:41 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork
  6 siblings, 0 replies; 13+ messages in thread
From: Patchwork @ 2020-12-09  5:26 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 3675 bytes --]

== Series Details ==

Series: series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c
URL   : https://patchwork.freedesktop.org/series/84712/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_9463 -> Patchwork_19086
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/index.html

New tests
---------

  New tests have been introduced between CI_DRM_9463 and Patchwork_19086:

### New CI tests (1) ###

  * boot:
    - Statuses : 1 fail(s) 39 pass(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in Patchwork_19086 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@amdgpu/amd_basic@semaphore:
    - fi-icl-y:           NOTRUN -> [SKIP][1] ([fdo#109315]) +17 similar issues
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/fi-icl-y/igt@amdgpu/amd_basic@semaphore.html

  * igt@core_hotunplug@unbind-rebind:
    - fi-kbl-7500u:       [PASS][2] -> [DMESG-WARN][3] ([i915#2605])
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-kbl-7500u/igt@core_hotunplug@unbind-rebind.html
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/fi-kbl-7500u/igt@core_hotunplug@unbind-rebind.html

  * igt@prime_vgem@basic-userptr:
    - fi-tgl-y:           [PASS][4] -> [DMESG-WARN][5] ([i915#402]) +2 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-tgl-y/igt@prime_vgem@basic-userptr.html
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/fi-tgl-y/igt@prime_vgem@basic-userptr.html

  
#### Possible fixes ####

  * igt@gem_flink_basic@double-flink:
    - fi-tgl-y:           [DMESG-WARN][6] ([i915#402]) -> [PASS][7] +1 similar issue
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-tgl-y/igt@gem_flink_basic@double-flink.html
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/fi-tgl-y/igt@gem_flink_basic@double-flink.html

  * igt@i915_selftest@live@execlists:
    - fi-icl-y:           [INCOMPLETE][8] ([i915#1037] / [i915#2276]) -> [PASS][9]
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/fi-icl-y/igt@i915_selftest@live@execlists.html
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/fi-icl-y/igt@i915_selftest@live@execlists.html

  
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [i915#1037]: https://gitlab.freedesktop.org/drm/intel/issues/1037
  [i915#2276]: https://gitlab.freedesktop.org/drm/intel/issues/2276
  [i915#2605]: https://gitlab.freedesktop.org/drm/intel/issues/2605
  [i915#402]: https://gitlab.freedesktop.org/drm/intel/issues/402


Participating hosts (43 -> 40)
------------------------------

  Missing    (3): fi-ilk-m540 fi-bdw-samus fi-hsw-4200u 


Build changes
-------------

  * Linux: CI_DRM_9463 -> Patchwork_19086

  CI-20190529: 20190529
  CI_DRM_9463: 1c64d5d72bcd4e6ccf2d0ba6e6ab3644497846b5 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_5885: d99f644b1868b9c92435b05ebfafa230721cd677 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_19086: a10cb379b7b484c1440dfadc8f815447c5ebfb6d @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

a10cb379b7b4 drm/i915: split fdi code out from intel_display.c
b45ec2e66b7d drm/i915: refactor pll code out into intel_clock.c
f86b532a437f drm/i915: refactor some crtc code out of intel display.
b87be3dc234f drm/i915: refactor cursor code out of i915_display.c

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/index.html

[-- Attachment #1.2: Type: text/html, Size: 4509 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [Intel-gfx] ✓ Fi.CI.IGT: success for series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c
  2020-12-09  4:21 [Intel-gfx] [rfc] start slimming down intel_display.c Dave Airlie
                   ` (5 preceding siblings ...)
  2020-12-09  5:26 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
@ 2020-12-09  6:41 ` Patchwork
  6 siblings, 0 replies; 13+ messages in thread
From: Patchwork @ 2020-12-09  6:41 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 17554 bytes --]

== Series Details ==

Series: series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c
URL   : https://patchwork.freedesktop.org/series/84712/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_9463_full -> Patchwork_19086_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  

New tests
---------

  New tests have been introduced between CI_DRM_9463_full and Patchwork_19086_full:

### New CI tests (1) ###

  * boot:
    - Statuses : 200 pass(s)
    - Exec time: [0.0] s

  

Known issues
------------

  Here are the changes found in Patchwork_19086_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_exec_reloc@basic-many-active@vcs1:
    - shard-iclb:         NOTRUN -> [FAIL][1] ([i915#2389])
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb1/igt@gem_exec_reloc@basic-many-active@vcs1.html

  * igt@i915_pm_rpm@cursor:
    - shard-glk:          [PASS][2] -> [DMESG-WARN][3] ([i915#118] / [i915#95])
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-glk1/igt@i915_pm_rpm@cursor.html
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-glk3/igt@i915_pm_rpm@cursor.html

  * igt@i915_pm_rpm@gem-execbuf-stress-pc8:
    - shard-hsw:          NOTRUN -> [SKIP][4] ([fdo#109271]) +53 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-hsw6/igt@i915_pm_rpm@gem-execbuf-stress-pc8.html

  * igt@i915_selftest@live@gt_heartbeat:
    - shard-skl:          [PASS][5] -> [DMESG-FAIL][6] ([i915#2291] / [i915#541])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl8/igt@i915_selftest@live@gt_heartbeat.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl1/igt@i915_selftest@live@gt_heartbeat.html

  * igt@kms_async_flips@test-time-stamp:
    - shard-tglb:         [PASS][7] -> [FAIL][8] ([i915#2597])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-tglb5/igt@kms_async_flips@test-time-stamp.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-tglb2/igt@kms_async_flips@test-time-stamp.html

  * igt@kms_chamelium@hdmi-crc-nonplanar-formats:
    - shard-hsw:          NOTRUN -> [SKIP][9] ([fdo#109271] / [fdo#111827]) +2 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-hsw6/igt@kms_chamelium@hdmi-crc-nonplanar-formats.html

  * igt@kms_color_chamelium@pipe-a-gamma:
    - shard-skl:          NOTRUN -> [SKIP][10] ([fdo#109271] / [fdo#111827])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl4/igt@kms_color_chamelium@pipe-a-gamma.html

  * igt@kms_cursor_crc@pipe-c-cursor-128x42-onscreen:
    - shard-skl:          [PASS][11] -> [FAIL][12] ([i915#54])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl2/igt@kms_cursor_crc@pipe-c-cursor-128x42-onscreen.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl9/igt@kms_cursor_crc@pipe-c-cursor-128x42-onscreen.html

  * igt@kms_cursor_legacy@2x-long-cursor-vs-flip-legacy:
    - shard-hsw:          NOTRUN -> [FAIL][13] ([i915#96])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-hsw6/igt@kms_cursor_legacy@2x-long-cursor-vs-flip-legacy.html

  * igt@kms_draw_crc@draw-method-xrgb8888-pwrite-ytiled:
    - shard-glk:          [PASS][14] -> [FAIL][15] ([i915#52] / [i915#54])
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-glk1/igt@kms_draw_crc@draw-method-xrgb8888-pwrite-ytiled.html
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-glk3/igt@kms_draw_crc@draw-method-xrgb8888-pwrite-ytiled.html

  * igt@kms_flip@flip-vs-expired-vblank@a-edp1:
    - shard-tglb:         [PASS][16] -> [FAIL][17] ([i915#2598])
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-tglb6/igt@kms_flip@flip-vs-expired-vblank@a-edp1.html
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-tglb2/igt@kms_flip@flip-vs-expired-vblank@a-edp1.html

  * igt@kms_flip@plain-flip-fb-recreate-interruptible@b-edp1:
    - shard-skl:          [PASS][18] -> [FAIL][19] ([i915#2122]) +1 similar issue
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl3/igt@kms_flip@plain-flip-fb-recreate-interruptible@b-edp1.html
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl2/igt@kms_flip@plain-flip-fb-recreate-interruptible@b-edp1.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs:
    - shard-skl:          NOTRUN -> [SKIP][20] ([fdo#109271] / [i915#2672])
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl5/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-render:
    - shard-skl:          NOTRUN -> [SKIP][21] ([fdo#109271]) +23 similar issues
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl8/igt@kms_frontbuffer_tracking@fbcpsr-1p-offscren-pri-indfb-draw-render.html

  * igt@kms_hdr@bpc-switch-dpms:
    - shard-skl:          [PASS][22] -> [FAIL][23] ([i915#1188])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl2/igt@kms_hdr@bpc-switch-dpms.html
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl9/igt@kms_hdr@bpc-switch-dpms.html

  * igt@kms_plane_alpha_blend@pipe-b-alpha-7efc:
    - shard-skl:          NOTRUN -> [FAIL][24] ([fdo#108145] / [i915#265])
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl5/igt@kms_plane_alpha_blend@pipe-b-alpha-7efc.html

  * igt@kms_plane_alpha_blend@pipe-c-coverage-7efc:
    - shard-skl:          [PASS][25] -> [FAIL][26] ([fdo#108145] / [i915#265]) +2 similar issues
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl2/igt@kms_plane_alpha_blend@pipe-c-coverage-7efc.html
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl9/igt@kms_plane_alpha_blend@pipe-c-coverage-7efc.html

  * igt@kms_psr@psr2_cursor_mmap_cpu:
    - shard-iclb:         [PASS][27] -> [SKIP][28] ([fdo#109441]) +1 similar issue
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-iclb2/igt@kms_psr@psr2_cursor_mmap_cpu.html
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb8/igt@kms_psr@psr2_cursor_mmap_cpu.html

  * igt@perf@enable-disable:
    - shard-skl:          [PASS][29] -> [FAIL][30] ([i915#1352])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl2/igt@perf@enable-disable.html
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl2/igt@perf@enable-disable.html

  * igt@perf@polling-parameterized:
    - shard-skl:          [PASS][31] -> [FAIL][32] ([i915#1542])
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl2/igt@perf@polling-parameterized.html
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl9/igt@perf@polling-parameterized.html
    - shard-tglb:         [PASS][33] -> [FAIL][34] ([i915#1542])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-tglb8/igt@perf@polling-parameterized.html
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-tglb8/igt@perf@polling-parameterized.html

  
#### Possible fixes ####

  * igt@gem_exec_whisper@basic-contexts:
    - shard-glk:          [DMESG-WARN][35] ([i915#118] / [i915#95]) -> [PASS][36]
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-glk3/igt@gem_exec_whisper@basic-contexts.html
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-glk5/igt@gem_exec_whisper@basic-contexts.html

  * igt@gem_userptr_blits@huge-split:
    - shard-hsw:          [FAIL][37] -> [PASS][38]
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-hsw2/igt@gem_userptr_blits@huge-split.html
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-hsw6/igt@gem_userptr_blits@huge-split.html

  * igt@kms_cursor_crc@pipe-a-cursor-128x42-onscreen:
    - shard-skl:          [FAIL][39] ([i915#54]) -> [PASS][40] +2 similar issues
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl4/igt@kms_cursor_crc@pipe-a-cursor-128x42-onscreen.html
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl9/igt@kms_cursor_crc@pipe-a-cursor-128x42-onscreen.html

  * igt@kms_cursor_legacy@2x-long-cursor-vs-flip-atomic:
    - shard-hsw:          [FAIL][41] ([i915#96]) -> [PASS][42]
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-hsw8/igt@kms_cursor_legacy@2x-long-cursor-vs-flip-atomic.html
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-hsw2/igt@kms_cursor_legacy@2x-long-cursor-vs-flip-atomic.html

  * igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size:
    - shard-skl:          [FAIL][43] ([i915#2346] / [i915#533]) -> [PASS][44]
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl8/igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size.html
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl4/igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size.html

  * igt@kms_flip@2x-flip-vs-expired-vblank@ab-hdmi-a1-hdmi-a2:
    - shard-glk:          [FAIL][45] ([i915#79]) -> [PASS][46]
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-glk6/igt@kms_flip@2x-flip-vs-expired-vblank@ab-hdmi-a1-hdmi-a2.html
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-glk5/igt@kms_flip@2x-flip-vs-expired-vblank@ab-hdmi-a1-hdmi-a2.html

  * igt@kms_flip@2x-plain-flip-fb-recreate-interruptible@ab-vga1-hdmi-a1:
    - shard-hsw:          [FAIL][47] ([i915#2122]) -> [PASS][48]
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-hsw6/igt@kms_flip@2x-plain-flip-fb-recreate-interruptible@ab-vga1-hdmi-a1.html
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-hsw4/igt@kms_flip@2x-plain-flip-fb-recreate-interruptible@ab-vga1-hdmi-a1.html

  * igt@kms_hdr@bpc-switch-suspend:
    - shard-skl:          [FAIL][49] ([i915#1188]) -> [PASS][50]
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl10/igt@kms_hdr@bpc-switch-suspend.html
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl5/igt@kms_hdr@bpc-switch-suspend.html

  * igt@kms_plane@plane-panning-bottom-right-suspend-pipe-b-planes:
    - shard-skl:          [INCOMPLETE][51] ([i915#198]) -> [PASS][52]
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl9/igt@kms_plane@plane-panning-bottom-right-suspend-pipe-b-planes.html
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl5/igt@kms_plane@plane-panning-bottom-right-suspend-pipe-b-planes.html

  * igt@kms_plane_alpha_blend@pipe-a-constant-alpha-min:
    - shard-skl:          [FAIL][53] ([fdo#108145] / [i915#265]) -> [PASS][54]
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-skl8/igt@kms_plane_alpha_blend@pipe-a-constant-alpha-min.html
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-skl4/igt@kms_plane_alpha_blend@pipe-a-constant-alpha-min.html

  * igt@kms_psr@psr2_cursor_plane_move:
    - shard-iclb:         [SKIP][55] ([fdo#109441]) -> [PASS][56] +1 similar issue
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-iclb3/igt@kms_psr@psr2_cursor_plane_move.html
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb2/igt@kms_psr@psr2_cursor_plane_move.html

  
#### Warnings ####

  * igt@i915_pm_dc@dc3co-vpb-simulation:
    - shard-iclb:         [SKIP][57] ([i915#588]) -> [SKIP][58] ([i915#658])
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-iclb2/igt@i915_pm_dc@dc3co-vpb-simulation.html
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb3/igt@i915_pm_dc@dc3co-vpb-simulation.html

  * igt@i915_pm_rc6_residency@rc6-fence:
    - shard-iclb:         [WARN][59] ([i915#2681] / [i915#2684]) -> [WARN][60] ([i915#2684])
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-iclb1/igt@i915_pm_rc6_residency@rc6-fence.html
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb5/igt@i915_pm_rc6_residency@rc6-fence.html

  * igt@i915_pm_rc6_residency@rc6-idle:
    - shard-iclb:         [WARN][61] ([i915#1804] / [i915#2684]) -> [WARN][62] ([i915#2684])
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-iclb6/igt@i915_pm_rc6_residency@rc6-idle.html
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb5/igt@i915_pm_rc6_residency@rc6-idle.html

  * igt@kms_dp_dsc@basic-dsc-enable-edp:
    - shard-iclb:         [DMESG-WARN][63] ([i915#1226]) -> [SKIP][64] ([fdo#109349])
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-iclb2/igt@kms_dp_dsc@basic-dsc-enable-edp.html
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb8/igt@kms_dp_dsc@basic-dsc-enable-edp.html

  * igt@runner@aborted:
    - shard-iclb:         ([FAIL][65], [FAIL][66]) ([i915#1814] / [i915#2295] / [i915#2722] / [i915#483]) -> ([FAIL][67], [FAIL][68]) ([i915#1814] / [i915#2295] / [i915#2722] / [i915#2724] / [i915#483])
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-iclb1/igt@runner@aborted.html
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-iclb3/igt@runner@aborted.html
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb5/igt@runner@aborted.html
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-iclb2/igt@runner@aborted.html
    - shard-glk:          ([FAIL][69], [FAIL][70]) ([i915#1814] / [i915#2295] / [i915#2722] / [i915#483] / [k.org#202321]) -> ([FAIL][71], [FAIL][72]) ([i915#1814] / [i915#2295] / [i915#2722] / [k.org#202321])
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-glk2/igt@runner@aborted.html
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9463/shard-glk3/igt@runner@aborted.html
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-glk8/igt@runner@aborted.html
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/shard-glk5/igt@runner@aborted.html

  
  [fdo#108145]: https://bugs.freedesktop.org/show_bug.cgi?id=108145
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109349]: https://bugs.freedesktop.org/show_bug.cgi?id=109349
  [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [fdo#111827]: https://bugs.freedesktop.org/show_bug.cgi?id=111827
  [i915#118]: https://gitlab.freedesktop.org/drm/intel/issues/118
  [i915#1188]: https://gitlab.freedesktop.org/drm/intel/issues/1188
  [i915#1226]: https://gitlab.freedesktop.org/drm/intel/issues/1226
  [i915#1352]: https://gitlab.freedesktop.org/drm/intel/issues/1352
  [i915#1542]: https://gitlab.freedesktop.org/drm/intel/issues/1542
  [i915#1804]: https://gitlab.freedesktop.org/drm/intel/issues/1804
  [i915#1814]: https://gitlab.freedesktop.org/drm/intel/issues/1814
  [i915#198]: https://gitlab.freedesktop.org/drm/intel/issues/198
  [i915#2122]: https://gitlab.freedesktop.org/drm/intel/issues/2122
  [i915#2291]: https://gitlab.freedesktop.org/drm/intel/issues/2291
  [i915#2295]: https://gitlab.freedesktop.org/drm/intel/issues/2295
  [i915#2346]: https://gitlab.freedesktop.org/drm/intel/issues/2346
  [i915#2389]: https://gitlab.freedesktop.org/drm/intel/issues/2389
  [i915#2597]: https://gitlab.freedesktop.org/drm/intel/issues/2597
  [i915#2598]: https://gitlab.freedesktop.org/drm/intel/issues/2598
  [i915#265]: https://gitlab.freedesktop.org/drm/intel/issues/265
  [i915#2672]: https://gitlab.freedesktop.org/drm/intel/issues/2672
  [i915#2681]: https://gitlab.freedesktop.org/drm/intel/issues/2681
  [i915#2684]: https://gitlab.freedesktop.org/drm/intel/issues/2684
  [i915#2722]: https://gitlab.freedesktop.org/drm/intel/issues/2722
  [i915#2724]: https://gitlab.freedesktop.org/drm/intel/issues/2724
  [i915#483]: https://gitlab.freedesktop.org/drm/intel/issues/483
  [i915#52]: https://gitlab.freedesktop.org/drm/intel/issues/52
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533
  [i915#54]: https://gitlab.freedesktop.org/drm/intel/issues/54
  [i915#541]: https://gitlab.freedesktop.org/drm/intel/issues/541
  [i915#588]: https://gitlab.freedesktop.org/drm/intel/issues/588
  [i915#658]: https://gitlab.freedesktop.org/drm/intel/issues/658
  [i915#79]: https://gitlab.freedesktop.org/drm/intel/issues/79
  [i915#95]: https://gitlab.freedesktop.org/drm/intel/issues/95
  [i915#96]: https://gitlab.freedesktop.org/drm/intel/issues/96
  [k.org#202321]: https://bugzilla.kernel.org/show_bug.cgi?id=202321


Participating hosts (10 -> 10)
------------------------------

  No changes in participating hosts


Build changes
-------------

  * Linux: CI_DRM_9463 -> Patchwork_19086

  CI-20190529: 20190529
  CI_DRM_9463: 1c64d5d72bcd4e6ccf2d0ba6e6ab3644497846b5 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_5885: d99f644b1868b9c92435b05ebfafa230721cd677 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_19086: a10cb379b7b484c1440dfadc8f815447c5ebfb6d @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_19086/index.html

[-- Attachment #1.2: Type: text/html, Size: 21540 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Intel-gfx] [PATCH 4/4] drm/i915: split fdi code out from intel_display.c
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 4/4] drm/i915: split fdi code out from intel_display.c Dave Airlie
@ 2020-12-09 10:48   ` Daniel Vetter
  2020-12-10  1:32     ` Dave Airlie
  0 siblings, 1 reply; 13+ messages in thread
From: Daniel Vetter @ 2020-12-09 10:48 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx

On Wed, Dec 9, 2020 at 5:22 AM Dave Airlie <airlied@gmail.com> wrote:
>
> From: Dave Airlie <airlied@redhat.com>
>
> This just refactors out the fdi code to a separate file.
>
> Signed-off-by: Dave Airlie <airlied@redhat.com>

There's also hsw_fdi_link_train from intel_ddi.c (another fairly big
file), I think that also belongs in here. It's not in the vtable
because it's directly called from the hsw crt encoder. With that this
looks reasonable to me.
-Daniel

> ---
>  drivers/gpu/drm/i915/Makefile                 |   1 +
>  drivers/gpu/drm/i915/display/intel_display.c  | 684 +-----------------
>  drivers/gpu/drm/i915/display/intel_display.h  |  10 +
>  .../drm/i915/display/intel_display_types.h    |   9 +
>  drivers/gpu/drm/i915/display/intel_fdi.c      | 682 +++++++++++++++++
>  5 files changed, 704 insertions(+), 682 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/display/intel_fdi.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 8b357c212ae2..f74b7c13ffbd 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -206,6 +206,7 @@ i915-y += \
>         display/intel_dpll_mgr.o \
>         display/intel_dsb.o \
>         display/intel_fbc.o \
> +       display/intel_fdi.o \
>         display/intel_fifo_underrun.o \
>         display/intel_frontbuffer.o \
>         display/intel_global_state.o \
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 788b1def61ee..5119a0040e36 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -170,16 +170,6 @@ static void intel_update_czclk(struct drm_i915_private *dev_priv)
>                 dev_priv->czclk_freq);
>  }
>
> -/* units of 100MHz */
> -static u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
> -                              const struct intel_crtc_state *pipe_config)
> -{
> -       if (HAS_DDI(dev_priv))
> -               return pipe_config->port_clock; /* SPLL */
> -       else
> -               return dev_priv->fdi_pll_freq;
> -}
> -
>  /* WA Display #0827: Gen9:all */
>  static void
>  skl_wa_827(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable)
> @@ -3776,532 +3766,6 @@ static void icl_set_pipe_chicken(struct intel_crtc *crtc)
>         intel_de_write(dev_priv, PIPE_CHICKEN(pipe), tmp);
>  }
>
> -static void intel_fdi_normal_train(struct intel_crtc *crtc)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       enum pipe pipe = crtc->pipe;
> -       i915_reg_t reg;
> -       u32 temp;
> -
> -       /* enable normal train */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       if (IS_IVYBRIDGE(dev_priv)) {
> -               temp &= ~FDI_LINK_TRAIN_NONE_IVB;
> -               temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
> -       } else {
> -               temp &= ~FDI_LINK_TRAIN_NONE;
> -               temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
> -       }
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       if (HAS_PCH_CPT(dev_priv)) {
> -               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> -               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
> -       } else {
> -               temp &= ~FDI_LINK_TRAIN_NONE;
> -               temp |= FDI_LINK_TRAIN_NONE;
> -       }
> -       intel_de_write(dev_priv, reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
> -
> -       /* wait one idle pattern time */
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(1000);
> -
> -       /* IVB wants error correction enabled */
> -       if (IS_IVYBRIDGE(dev_priv))
> -               intel_de_write(dev_priv, reg,
> -                              intel_de_read(dev_priv, reg) | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
> -}
> -
> -/* The FDI link training functions for ILK/Ibexpeak. */
> -static void ilk_fdi_link_train(struct intel_crtc *crtc,
> -                              const struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       enum pipe pipe = crtc->pipe;
> -       i915_reg_t reg;
> -       u32 temp, tries;
> -
> -       /* FDI needs bits from pipe first */
> -       assert_pipe_enabled(dev_priv, crtc_state->cpu_transcoder);
> -
> -       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
> -          for train result */
> -       reg = FDI_RX_IMR(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_RX_SYMBOL_LOCK;
> -       temp &= ~FDI_RX_BIT_LOCK;
> -       intel_de_write(dev_priv, reg, temp);
> -       intel_de_read(dev_priv, reg);
> -       udelay(150);
> -
> -       /* enable CPU FDI TX and PCH FDI RX */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_DP_PORT_WIDTH_MASK;
> -       temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
> -       temp &= ~FDI_LINK_TRAIN_NONE;
> -       temp |= FDI_LINK_TRAIN_PATTERN_1;
> -       intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
> -
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_LINK_TRAIN_NONE;
> -       temp |= FDI_LINK_TRAIN_PATTERN_1;
> -       intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(150);
> -
> -       /* Ironlake workaround, enable clock pointer after FDI enable*/
> -       intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
> -                      FDI_RX_PHASE_SYNC_POINTER_OVR);
> -       intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
> -                      FDI_RX_PHASE_SYNC_POINTER_OVR | FDI_RX_PHASE_SYNC_POINTER_EN);
> -
> -       reg = FDI_RX_IIR(pipe);
> -       for (tries = 0; tries < 5; tries++) {
> -               temp = intel_de_read(dev_priv, reg);
> -               drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> -
> -               if ((temp & FDI_RX_BIT_LOCK)) {
> -                       drm_dbg_kms(&dev_priv->drm, "FDI train 1 done.\n");
> -                       intel_de_write(dev_priv, reg, temp | FDI_RX_BIT_LOCK);
> -                       break;
> -               }
> -       }
> -       if (tries == 5)
> -               drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
> -
> -       /* Train 2 */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_LINK_TRAIN_NONE;
> -       temp |= FDI_LINK_TRAIN_PATTERN_2;
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_LINK_TRAIN_NONE;
> -       temp |= FDI_LINK_TRAIN_PATTERN_2;
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(150);
> -
> -       reg = FDI_RX_IIR(pipe);
> -       for (tries = 0; tries < 5; tries++) {
> -               temp = intel_de_read(dev_priv, reg);
> -               drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> -
> -               if (temp & FDI_RX_SYMBOL_LOCK) {
> -                       intel_de_write(dev_priv, reg,
> -                                      temp | FDI_RX_SYMBOL_LOCK);
> -                       drm_dbg_kms(&dev_priv->drm, "FDI train 2 done.\n");
> -                       break;
> -               }
> -       }
> -       if (tries == 5)
> -               drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
> -
> -       drm_dbg_kms(&dev_priv->drm, "FDI train done\n");
> -
> -}
> -
> -static const int snb_b_fdi_train_param[] = {
> -       FDI_LINK_TRAIN_400MV_0DB_SNB_B,
> -       FDI_LINK_TRAIN_400MV_6DB_SNB_B,
> -       FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
> -       FDI_LINK_TRAIN_800MV_0DB_SNB_B,
> -};
> -
> -/* The FDI link training functions for SNB/Cougarpoint. */
> -static void gen6_fdi_link_train(struct intel_crtc *crtc,
> -                               const struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       enum pipe pipe = crtc->pipe;
> -       i915_reg_t reg;
> -       u32 temp, i, retry;
> -
> -       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
> -          for train result */
> -       reg = FDI_RX_IMR(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_RX_SYMBOL_LOCK;
> -       temp &= ~FDI_RX_BIT_LOCK;
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(150);
> -
> -       /* enable CPU FDI TX and PCH FDI RX */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_DP_PORT_WIDTH_MASK;
> -       temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
> -       temp &= ~FDI_LINK_TRAIN_NONE;
> -       temp |= FDI_LINK_TRAIN_PATTERN_1;
> -       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> -       /* SNB-B */
> -       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
> -       intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
> -
> -       intel_de_write(dev_priv, FDI_RX_MISC(pipe),
> -                      FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
> -
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       if (HAS_PCH_CPT(dev_priv)) {
> -               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> -               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
> -       } else {
> -               temp &= ~FDI_LINK_TRAIN_NONE;
> -               temp |= FDI_LINK_TRAIN_PATTERN_1;
> -       }
> -       intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(150);
> -
> -       for (i = 0; i < 4; i++) {
> -               reg = FDI_TX_CTL(pipe);
> -               temp = intel_de_read(dev_priv, reg);
> -               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> -               temp |= snb_b_fdi_train_param[i];
> -               intel_de_write(dev_priv, reg, temp);
> -
> -               intel_de_posting_read(dev_priv, reg);
> -               udelay(500);
> -
> -               for (retry = 0; retry < 5; retry++) {
> -                       reg = FDI_RX_IIR(pipe);
> -                       temp = intel_de_read(dev_priv, reg);
> -                       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> -                       if (temp & FDI_RX_BIT_LOCK) {
> -                               intel_de_write(dev_priv, reg,
> -                                              temp | FDI_RX_BIT_LOCK);
> -                               drm_dbg_kms(&dev_priv->drm,
> -                                           "FDI train 1 done.\n");
> -                               break;
> -                       }
> -                       udelay(50);
> -               }
> -               if (retry < 5)
> -                       break;
> -       }
> -       if (i == 4)
> -               drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
> -
> -       /* Train 2 */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_LINK_TRAIN_NONE;
> -       temp |= FDI_LINK_TRAIN_PATTERN_2;
> -       if (IS_GEN(dev_priv, 6)) {
> -               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> -               /* SNB-B */
> -               temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
> -       }
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       if (HAS_PCH_CPT(dev_priv)) {
> -               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> -               temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
> -       } else {
> -               temp &= ~FDI_LINK_TRAIN_NONE;
> -               temp |= FDI_LINK_TRAIN_PATTERN_2;
> -       }
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(150);
> -
> -       for (i = 0; i < 4; i++) {
> -               reg = FDI_TX_CTL(pipe);
> -               temp = intel_de_read(dev_priv, reg);
> -               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> -               temp |= snb_b_fdi_train_param[i];
> -               intel_de_write(dev_priv, reg, temp);
> -
> -               intel_de_posting_read(dev_priv, reg);
> -               udelay(500);
> -
> -               for (retry = 0; retry < 5; retry++) {
> -                       reg = FDI_RX_IIR(pipe);
> -                       temp = intel_de_read(dev_priv, reg);
> -                       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> -                       if (temp & FDI_RX_SYMBOL_LOCK) {
> -                               intel_de_write(dev_priv, reg,
> -                                              temp | FDI_RX_SYMBOL_LOCK);
> -                               drm_dbg_kms(&dev_priv->drm,
> -                                           "FDI train 2 done.\n");
> -                               break;
> -                       }
> -                       udelay(50);
> -               }
> -               if (retry < 5)
> -                       break;
> -       }
> -       if (i == 4)
> -               drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
> -
> -       drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
> -}
> -
> -/* Manual link training for Ivy Bridge A0 parts */
> -static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
> -                                     const struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       enum pipe pipe = crtc->pipe;
> -       i915_reg_t reg;
> -       u32 temp, i, j;
> -
> -       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
> -          for train result */
> -       reg = FDI_RX_IMR(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_RX_SYMBOL_LOCK;
> -       temp &= ~FDI_RX_BIT_LOCK;
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(150);
> -
> -       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR before link train 0x%x\n",
> -                   intel_de_read(dev_priv, FDI_RX_IIR(pipe)));
> -
> -       /* Try each vswing and preemphasis setting twice before moving on */
> -       for (j = 0; j < ARRAY_SIZE(snb_b_fdi_train_param) * 2; j++) {
> -               /* disable first in case we need to retry */
> -               reg = FDI_TX_CTL(pipe);
> -               temp = intel_de_read(dev_priv, reg);
> -               temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
> -               temp &= ~FDI_TX_ENABLE;
> -               intel_de_write(dev_priv, reg, temp);
> -
> -               reg = FDI_RX_CTL(pipe);
> -               temp = intel_de_read(dev_priv, reg);
> -               temp &= ~FDI_LINK_TRAIN_AUTO;
> -               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> -               temp &= ~FDI_RX_ENABLE;
> -               intel_de_write(dev_priv, reg, temp);
> -
> -               /* enable CPU FDI TX and PCH FDI RX */
> -               reg = FDI_TX_CTL(pipe);
> -               temp = intel_de_read(dev_priv, reg);
> -               temp &= ~FDI_DP_PORT_WIDTH_MASK;
> -               temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
> -               temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
> -               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> -               temp |= snb_b_fdi_train_param[j/2];
> -               temp |= FDI_COMPOSITE_SYNC;
> -               intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
> -
> -               intel_de_write(dev_priv, FDI_RX_MISC(pipe),
> -                              FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
> -
> -               reg = FDI_RX_CTL(pipe);
> -               temp = intel_de_read(dev_priv, reg);
> -               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
> -               temp |= FDI_COMPOSITE_SYNC;
> -               intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
> -
> -               intel_de_posting_read(dev_priv, reg);
> -               udelay(1); /* should be 0.5us */
> -
> -               for (i = 0; i < 4; i++) {
> -                       reg = FDI_RX_IIR(pipe);
> -                       temp = intel_de_read(dev_priv, reg);
> -                       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> -
> -                       if (temp & FDI_RX_BIT_LOCK ||
> -                           (intel_de_read(dev_priv, reg) & FDI_RX_BIT_LOCK)) {
> -                               intel_de_write(dev_priv, reg,
> -                                              temp | FDI_RX_BIT_LOCK);
> -                               drm_dbg_kms(&dev_priv->drm,
> -                                           "FDI train 1 done, level %i.\n",
> -                                           i);
> -                               break;
> -                       }
> -                       udelay(1); /* should be 0.5us */
> -               }
> -               if (i == 4) {
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "FDI train 1 fail on vswing %d\n", j / 2);
> -                       continue;
> -               }
> -
> -               /* Train 2 */
> -               reg = FDI_TX_CTL(pipe);
> -               temp = intel_de_read(dev_priv, reg);
> -               temp &= ~FDI_LINK_TRAIN_NONE_IVB;
> -               temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
> -               intel_de_write(dev_priv, reg, temp);
> -
> -               reg = FDI_RX_CTL(pipe);
> -               temp = intel_de_read(dev_priv, reg);
> -               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> -               temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
> -               intel_de_write(dev_priv, reg, temp);
> -
> -               intel_de_posting_read(dev_priv, reg);
> -               udelay(2); /* should be 1.5us */
> -
> -               for (i = 0; i < 4; i++) {
> -                       reg = FDI_RX_IIR(pipe);
> -                       temp = intel_de_read(dev_priv, reg);
> -                       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> -
> -                       if (temp & FDI_RX_SYMBOL_LOCK ||
> -                           (intel_de_read(dev_priv, reg) & FDI_RX_SYMBOL_LOCK)) {
> -                               intel_de_write(dev_priv, reg,
> -                                              temp | FDI_RX_SYMBOL_LOCK);
> -                               drm_dbg_kms(&dev_priv->drm,
> -                                           "FDI train 2 done, level %i.\n",
> -                                           i);
> -                               goto train_done;
> -                       }
> -                       udelay(2); /* should be 1.5us */
> -               }
> -               if (i == 4)
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "FDI train 2 fail on vswing %d\n", j / 2);
> -       }
> -
> -train_done:
> -       drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
> -}
> -
> -static void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state)
> -{
> -       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
> -       enum pipe pipe = intel_crtc->pipe;
> -       i915_reg_t reg;
> -       u32 temp;
> -
> -       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
> -       temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
> -       temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
> -       intel_de_write(dev_priv, reg, temp | FDI_RX_PLL_ENABLE);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(200);
> -
> -       /* Switch from Rawclk to PCDclk */
> -       temp = intel_de_read(dev_priv, reg);
> -       intel_de_write(dev_priv, reg, temp | FDI_PCDCLK);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(200);
> -
> -       /* Enable CPU FDI TX PLL, always on for Ironlake */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
> -               intel_de_write(dev_priv, reg, temp | FDI_TX_PLL_ENABLE);
> -
> -               intel_de_posting_read(dev_priv, reg);
> -               udelay(100);
> -       }
> -}
> -
> -static void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc)
> -{
> -       struct drm_device *dev = intel_crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       enum pipe pipe = intel_crtc->pipe;
> -       i915_reg_t reg;
> -       u32 temp;
> -
> -       /* Switch from PCDclk to Rawclk */
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       intel_de_write(dev_priv, reg, temp & ~FDI_PCDCLK);
> -
> -       /* Disable CPU FDI TX PLL */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       intel_de_write(dev_priv, reg, temp & ~FDI_TX_PLL_ENABLE);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(100);
> -
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       intel_de_write(dev_priv, reg, temp & ~FDI_RX_PLL_ENABLE);
> -
> -       /* Wait for the clocks to turn off. */
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(100);
> -}
> -
> -static void ilk_fdi_disable(struct intel_crtc *crtc)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       enum pipe pipe = crtc->pipe;
> -       i915_reg_t reg;
> -       u32 temp;
> -
> -       /* disable CPU FDI tx and PCH FDI rx */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       intel_de_write(dev_priv, reg, temp & ~FDI_TX_ENABLE);
> -       intel_de_posting_read(dev_priv, reg);
> -
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~(0x7 << 16);
> -       temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
> -       intel_de_write(dev_priv, reg, temp & ~FDI_RX_ENABLE);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(100);
> -
> -       /* Ironlake workaround, disable clock pointer after downing FDI */
> -       if (HAS_PCH_IBX(dev_priv))
> -               intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
> -                              FDI_RX_PHASE_SYNC_POINTER_OVR);
> -
> -       /* still set train pattern 1 */
> -       reg = FDI_TX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       temp &= ~FDI_LINK_TRAIN_NONE;
> -       temp |= FDI_LINK_TRAIN_PATTERN_1;
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       reg = FDI_RX_CTL(pipe);
> -       temp = intel_de_read(dev_priv, reg);
> -       if (HAS_PCH_CPT(dev_priv)) {
> -               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> -               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
> -       } else {
> -               temp &= ~FDI_LINK_TRAIN_NONE;
> -               temp |= FDI_LINK_TRAIN_PATTERN_1;
> -       }
> -       /* BPC in FDI rx is consistent with that in PIPECONF */
> -       temp &= ~(0x07 << 16);
> -       temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
> -       intel_de_write(dev_priv, reg, temp);
> -
> -       intel_de_posting_read(dev_priv, reg);
> -       udelay(100);
> -}
> -
>  bool intel_has_pending_fb_unpin(struct drm_i915_private *dev_priv)
>  {
>         struct drm_crtc *crtc;
> @@ -6708,143 +6172,6 @@ static void intel_connector_verify_state(struct intel_crtc_state *crtc_state,
>         }
>  }
>
> -static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
> -{
> -       if (crtc_state->hw.enable && crtc_state->has_pch_encoder)
> -               return crtc_state->fdi_lanes;
> -
> -       return 0;
> -}
> -
> -static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
> -                              struct intel_crtc_state *pipe_config)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       struct drm_atomic_state *state = pipe_config->uapi.state;
> -       struct intel_crtc *other_crtc;
> -       struct intel_crtc_state *other_crtc_state;
> -
> -       drm_dbg_kms(&dev_priv->drm,
> -                   "checking fdi config on pipe %c, lanes %i\n",
> -                   pipe_name(pipe), pipe_config->fdi_lanes);
> -       if (pipe_config->fdi_lanes > 4) {
> -               drm_dbg_kms(&dev_priv->drm,
> -                           "invalid fdi lane config on pipe %c: %i lanes\n",
> -                           pipe_name(pipe), pipe_config->fdi_lanes);
> -               return -EINVAL;
> -       }
> -
> -       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
> -               if (pipe_config->fdi_lanes > 2) {
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "only 2 lanes on haswell, required: %i lanes\n",
> -                                   pipe_config->fdi_lanes);
> -                       return -EINVAL;
> -               } else {
> -                       return 0;
> -               }
> -       }
> -
> -       if (INTEL_NUM_PIPES(dev_priv) == 2)
> -               return 0;
> -
> -       /* Ivybridge 3 pipe is really complicated */
> -       switch (pipe) {
> -       case PIPE_A:
> -               return 0;
> -       case PIPE_B:
> -               if (pipe_config->fdi_lanes <= 2)
> -                       return 0;
> -
> -               other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_C);
> -               other_crtc_state =
> -                       intel_atomic_get_crtc_state(state, other_crtc);
> -               if (IS_ERR(other_crtc_state))
> -                       return PTR_ERR(other_crtc_state);
> -
> -               if (pipe_required_fdi_lanes(other_crtc_state) > 0) {
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "invalid shared fdi lane config on pipe %c: %i lanes\n",
> -                                   pipe_name(pipe), pipe_config->fdi_lanes);
> -                       return -EINVAL;
> -               }
> -               return 0;
> -       case PIPE_C:
> -               if (pipe_config->fdi_lanes > 2) {
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "only 2 lanes on pipe %c: required %i lanes\n",
> -                                   pipe_name(pipe), pipe_config->fdi_lanes);
> -                       return -EINVAL;
> -               }
> -
> -               other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_B);
> -               other_crtc_state =
> -                       intel_atomic_get_crtc_state(state, other_crtc);
> -               if (IS_ERR(other_crtc_state))
> -                       return PTR_ERR(other_crtc_state);
> -
> -               if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "fdi link B uses too many lanes to enable link C\n");
> -                       return -EINVAL;
> -               }
> -               return 0;
> -       default:
> -               BUG();
> -       }
> -}
> -
> -#define RETRY 1
> -static int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
> -                                 struct intel_crtc_state *pipe_config)
> -{
> -       struct drm_device *dev = intel_crtc->base.dev;
> -       struct drm_i915_private *i915 = to_i915(dev);
> -       const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
> -       int lane, link_bw, fdi_dotclock, ret;
> -       bool needs_recompute = false;
> -
> -retry:
> -       /* FDI is a binary signal running at ~2.7GHz, encoding
> -        * each output octet as 10 bits. The actual frequency
> -        * is stored as a divider into a 100MHz clock, and the
> -        * mode pixel clock is stored in units of 1KHz.
> -        * Hence the bw of each lane in terms of the mode signal
> -        * is:
> -        */
> -       link_bw = intel_fdi_link_freq(i915, pipe_config);
> -
> -       fdi_dotclock = adjusted_mode->crtc_clock;
> -
> -       lane = ilk_get_lanes_required(fdi_dotclock, link_bw,
> -                                     pipe_config->pipe_bpp);
> -
> -       pipe_config->fdi_lanes = lane;
> -
> -       intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
> -                              link_bw, &pipe_config->fdi_m_n, false, false);
> -
> -       ret = ilk_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
> -       if (ret == -EDEADLK)
> -               return ret;
> -
> -       if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
> -               pipe_config->pipe_bpp -= 2*3;
> -               drm_dbg_kms(&i915->drm,
> -                           "fdi link bw constraint, reducing pipe bpp to %i\n",
> -                           pipe_config->pipe_bpp);
> -               needs_recompute = true;
> -               pipe_config->bw_constrained = true;
> -
> -               goto retry;
> -       }
> -
> -       if (needs_recompute)
> -               return RETRY;
> -
> -       return ret;
> -}
> -
>  bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state)
>  {
>         struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> @@ -11379,7 +10706,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state,
>                 return ret;
>         }
>
> -       if (ret == RETRY) {
> +       if (ret == I915_DISPLAY_CONFIG_RETRY) {
>                 if (drm_WARN(&i915->drm, !retry,
>                              "loop in pipe configuration computation\n"))
>                         return -EINVAL;
> @@ -15178,14 +14505,7 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
>                 dev_priv->display.crtc_disable = i9xx_crtc_disable;
>         }
>
> -       if (IS_GEN(dev_priv, 5)) {
> -               dev_priv->display.fdi_link_train = ilk_fdi_link_train;
> -       } else if (IS_GEN(dev_priv, 6)) {
> -               dev_priv->display.fdi_link_train = gen6_fdi_link_train;
> -       } else if (IS_IVYBRIDGE(dev_priv)) {
> -               /* FIXME: detect B0+ stepping and use auto training */
> -               dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
> -       }
> +       intel_init_fdi_hook(dev_priv);
>
>         if (INTEL_GEN(dev_priv) >= 9) {
>                 dev_priv->display.commit_modeset_enables = skl_commit_modeset_enables;
> diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
> index f1e36cca86c1..731ea6f7777a 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.h
> +++ b/drivers/gpu/drm/i915/display/intel_display.h
> @@ -677,6 +677,16 @@ void vlv_compute_dpll(struct intel_crtc *crtc,
>  void chv_compute_dpll(struct intel_crtc *crtc,
>                       struct intel_crtc_state *pipe_config);
>
> +/* fdi */
> +#define I915_DISPLAY_CONFIG_RETRY 1
> +int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
> +                          struct intel_crtc_state *pipe_config);
> +void intel_fdi_normal_train(struct intel_crtc *crtc);
> +void ilk_fdi_disable(struct intel_crtc *crtc);
> +void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc);
> +void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state);
> +void intel_init_fdi_hook(struct drm_i915_private *dev_priv);
> +
>  /* modesetting */
>  void intel_modeset_init_hw(struct drm_i915_private *i915);
>  int intel_modeset_init_noirq(struct drm_i915_private *i915);
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 823083b231bc..9c684552903c 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1804,4 +1804,13 @@ static inline u32 i9xx_dpll_compute_fp(struct dpll *dpll)
>         return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
>  }
>
> +static inline u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
> +                                     const struct intel_crtc_state *pipe_config)
> +{
> +       if (HAS_DDI(dev_priv))
> +               return pipe_config->port_clock; /* SPLL */
> +       else
> +               return dev_priv->fdi_pll_freq;
> +}
> +
>  #endif /*  __INTEL_DISPLAY_TYPES_H__ */
> diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c
> new file mode 100644
> index 000000000000..bf4ef84686ef
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_fdi.c
> @@ -0,0 +1,682 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2020 Intel Corporation
> + */
> +#include "intel_atomic.h"
> +#include "intel_display_types.h"
> +
> +/* units of 100MHz */
> +static int pipe_required_fdi_lanes(struct intel_crtc_state *crtc_state)
> +{
> +       if (crtc_state->hw.enable && crtc_state->has_pch_encoder)
> +               return crtc_state->fdi_lanes;
> +
> +       return 0;
> +}
> +
> +static int ilk_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
> +                              struct intel_crtc_state *pipe_config)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       struct drm_atomic_state *state = pipe_config->uapi.state;
> +       struct intel_crtc *other_crtc;
> +       struct intel_crtc_state *other_crtc_state;
> +
> +       drm_dbg_kms(&dev_priv->drm,
> +                   "checking fdi config on pipe %c, lanes %i\n",
> +                   pipe_name(pipe), pipe_config->fdi_lanes);
> +       if (pipe_config->fdi_lanes > 4) {
> +               drm_dbg_kms(&dev_priv->drm,
> +                           "invalid fdi lane config on pipe %c: %i lanes\n",
> +                           pipe_name(pipe), pipe_config->fdi_lanes);
> +               return -EINVAL;
> +       }
> +
> +       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
> +               if (pipe_config->fdi_lanes > 2) {
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "only 2 lanes on haswell, required: %i lanes\n",
> +                                   pipe_config->fdi_lanes);
> +                       return -EINVAL;
> +               } else {
> +                       return 0;
> +               }
> +       }
> +
> +       if (INTEL_NUM_PIPES(dev_priv) == 2)
> +               return 0;
> +
> +       /* Ivybridge 3 pipe is really complicated */
> +       switch (pipe) {
> +       case PIPE_A:
> +               return 0;
> +       case PIPE_B:
> +               if (pipe_config->fdi_lanes <= 2)
> +                       return 0;
> +
> +               other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_C);
> +               other_crtc_state =
> +                       intel_atomic_get_crtc_state(state, other_crtc);
> +               if (IS_ERR(other_crtc_state))
> +                       return PTR_ERR(other_crtc_state);
> +
> +               if (pipe_required_fdi_lanes(other_crtc_state) > 0) {
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "invalid shared fdi lane config on pipe %c: %i lanes\n",
> +                                   pipe_name(pipe), pipe_config->fdi_lanes);
> +                       return -EINVAL;
> +               }
> +               return 0;
> +       case PIPE_C:
> +               if (pipe_config->fdi_lanes > 2) {
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "only 2 lanes on pipe %c: required %i lanes\n",
> +                                   pipe_name(pipe), pipe_config->fdi_lanes);
> +                       return -EINVAL;
> +               }
> +
> +               other_crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_B);
> +               other_crtc_state =
> +                       intel_atomic_get_crtc_state(state, other_crtc);
> +               if (IS_ERR(other_crtc_state))
> +                       return PTR_ERR(other_crtc_state);
> +
> +               if (pipe_required_fdi_lanes(other_crtc_state) > 2) {
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "fdi link B uses too many lanes to enable link C\n");
> +                       return -EINVAL;
> +               }
> +               return 0;
> +       default:
> +               BUG();
> +       }
> +}
> +
> +int ilk_fdi_compute_config(struct intel_crtc *intel_crtc,
> +                                 struct intel_crtc_state *pipe_config)
> +{
> +       struct drm_device *dev = intel_crtc->base.dev;
> +       struct drm_i915_private *i915 = to_i915(dev);
> +       const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
> +       int lane, link_bw, fdi_dotclock, ret;
> +       bool needs_recompute = false;
> +
> +retry:
> +       /* FDI is a binary signal running at ~2.7GHz, encoding
> +        * each output octet as 10 bits. The actual frequency
> +        * is stored as a divider into a 100MHz clock, and the
> +        * mode pixel clock is stored in units of 1KHz.
> +        * Hence the bw of each lane in terms of the mode signal
> +        * is:
> +        */
> +       link_bw = intel_fdi_link_freq(i915, pipe_config);
> +
> +       fdi_dotclock = adjusted_mode->crtc_clock;
> +
> +       lane = ilk_get_lanes_required(fdi_dotclock, link_bw,
> +                                     pipe_config->pipe_bpp);
> +
> +       pipe_config->fdi_lanes = lane;
> +
> +       intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
> +                              link_bw, &pipe_config->fdi_m_n, false, false);
> +
> +       ret = ilk_check_fdi_lanes(dev, intel_crtc->pipe, pipe_config);
> +       if (ret == -EDEADLK)
> +               return ret;
> +
> +       if (ret == -EINVAL && pipe_config->pipe_bpp > 6*3) {
> +               pipe_config->pipe_bpp -= 2*3;
> +               drm_dbg_kms(&i915->drm,
> +                           "fdi link bw constraint, reducing pipe bpp to %i\n",
> +                           pipe_config->pipe_bpp);
> +               needs_recompute = true;
> +               pipe_config->bw_constrained = true;
> +
> +               goto retry;
> +       }
> +
> +       if (needs_recompute)
> +               return I915_DISPLAY_CONFIG_RETRY;
> +
> +       return ret;
> +}
> +
> +void intel_fdi_normal_train(struct intel_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       enum pipe pipe = crtc->pipe;
> +       i915_reg_t reg;
> +       u32 temp;
> +
> +       /* enable normal train */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       if (IS_IVYBRIDGE(dev_priv)) {
> +               temp &= ~FDI_LINK_TRAIN_NONE_IVB;
> +               temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
> +       } else {
> +               temp &= ~FDI_LINK_TRAIN_NONE;
> +               temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
> +       }
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       if (HAS_PCH_CPT(dev_priv)) {
> +               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> +               temp |= FDI_LINK_TRAIN_NORMAL_CPT;
> +       } else {
> +               temp &= ~FDI_LINK_TRAIN_NONE;
> +               temp |= FDI_LINK_TRAIN_NONE;
> +       }
> +       intel_de_write(dev_priv, reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
> +
> +       /* wait one idle pattern time */
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(1000);
> +
> +       /* IVB wants error correction enabled */
> +       if (IS_IVYBRIDGE(dev_priv))
> +               intel_de_write(dev_priv, reg,
> +                              intel_de_read(dev_priv, reg) | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE);
> +}
> +
> +/* The FDI link training functions for ILK/Ibexpeak. */
> +static void ilk_fdi_link_train(struct intel_crtc *crtc,
> +                              const struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       enum pipe pipe = crtc->pipe;
> +       i915_reg_t reg;
> +       u32 temp, tries;
> +
> +       /* FDI needs bits from pipe first */
> +       assert_pipe_enabled(dev_priv, crtc_state->cpu_transcoder);
> +
> +       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
> +          for train result */
> +       reg = FDI_RX_IMR(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_RX_SYMBOL_LOCK;
> +       temp &= ~FDI_RX_BIT_LOCK;
> +       intel_de_write(dev_priv, reg, temp);
> +       intel_de_read(dev_priv, reg);
> +       udelay(150);
> +
> +       /* enable CPU FDI TX and PCH FDI RX */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_DP_PORT_WIDTH_MASK;
> +       temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
> +       temp &= ~FDI_LINK_TRAIN_NONE;
> +       temp |= FDI_LINK_TRAIN_PATTERN_1;
> +       intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
> +
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_LINK_TRAIN_NONE;
> +       temp |= FDI_LINK_TRAIN_PATTERN_1;
> +       intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(150);
> +
> +       /* Ironlake workaround, enable clock pointer after FDI enable*/
> +       intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
> +                      FDI_RX_PHASE_SYNC_POINTER_OVR);
> +       intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
> +                      FDI_RX_PHASE_SYNC_POINTER_OVR | FDI_RX_PHASE_SYNC_POINTER_EN);
> +
> +       reg = FDI_RX_IIR(pipe);
> +       for (tries = 0; tries < 5; tries++) {
> +               temp = intel_de_read(dev_priv, reg);
> +               drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> +
> +               if ((temp & FDI_RX_BIT_LOCK)) {
> +                       drm_dbg_kms(&dev_priv->drm, "FDI train 1 done.\n");
> +                       intel_de_write(dev_priv, reg, temp | FDI_RX_BIT_LOCK);
> +                       break;
> +               }
> +       }
> +       if (tries == 5)
> +               drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
> +
> +       /* Train 2 */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_LINK_TRAIN_NONE;
> +       temp |= FDI_LINK_TRAIN_PATTERN_2;
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_LINK_TRAIN_NONE;
> +       temp |= FDI_LINK_TRAIN_PATTERN_2;
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(150);
> +
> +       reg = FDI_RX_IIR(pipe);
> +       for (tries = 0; tries < 5; tries++) {
> +               temp = intel_de_read(dev_priv, reg);
> +               drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> +
> +               if (temp & FDI_RX_SYMBOL_LOCK) {
> +                       intel_de_write(dev_priv, reg,
> +                                      temp | FDI_RX_SYMBOL_LOCK);
> +                       drm_dbg_kms(&dev_priv->drm, "FDI train 2 done.\n");
> +                       break;
> +               }
> +       }
> +       if (tries == 5)
> +               drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
> +
> +       drm_dbg_kms(&dev_priv->drm, "FDI train done\n");
> +
> +}
> +
> +static const int snb_b_fdi_train_param[] = {
> +       FDI_LINK_TRAIN_400MV_0DB_SNB_B,
> +       FDI_LINK_TRAIN_400MV_6DB_SNB_B,
> +       FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
> +       FDI_LINK_TRAIN_800MV_0DB_SNB_B,
> +};
> +
> +/* The FDI link training functions for SNB/Cougarpoint. */
> +static void gen6_fdi_link_train(struct intel_crtc *crtc,
> +                               const struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       enum pipe pipe = crtc->pipe;
> +       i915_reg_t reg;
> +       u32 temp, i, retry;
> +
> +       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
> +          for train result */
> +       reg = FDI_RX_IMR(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_RX_SYMBOL_LOCK;
> +       temp &= ~FDI_RX_BIT_LOCK;
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(150);
> +
> +       /* enable CPU FDI TX and PCH FDI RX */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_DP_PORT_WIDTH_MASK;
> +       temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
> +       temp &= ~FDI_LINK_TRAIN_NONE;
> +       temp |= FDI_LINK_TRAIN_PATTERN_1;
> +       temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> +       /* SNB-B */
> +       temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
> +       intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
> +
> +       intel_de_write(dev_priv, FDI_RX_MISC(pipe),
> +                      FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
> +
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       if (HAS_PCH_CPT(dev_priv)) {
> +               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> +               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
> +       } else {
> +               temp &= ~FDI_LINK_TRAIN_NONE;
> +               temp |= FDI_LINK_TRAIN_PATTERN_1;
> +       }
> +       intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(150);
> +
> +       for (i = 0; i < 4; i++) {
> +               reg = FDI_TX_CTL(pipe);
> +               temp = intel_de_read(dev_priv, reg);
> +               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> +               temp |= snb_b_fdi_train_param[i];
> +               intel_de_write(dev_priv, reg, temp);
> +
> +               intel_de_posting_read(dev_priv, reg);
> +               udelay(500);
> +
> +               for (retry = 0; retry < 5; retry++) {
> +                       reg = FDI_RX_IIR(pipe);
> +                       temp = intel_de_read(dev_priv, reg);
> +                       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> +                       if (temp & FDI_RX_BIT_LOCK) {
> +                               intel_de_write(dev_priv, reg,
> +                                              temp | FDI_RX_BIT_LOCK);
> +                               drm_dbg_kms(&dev_priv->drm,
> +                                           "FDI train 1 done.\n");
> +                               break;
> +                       }
> +                       udelay(50);
> +               }
> +               if (retry < 5)
> +                       break;
> +       }
> +       if (i == 4)
> +               drm_err(&dev_priv->drm, "FDI train 1 fail!\n");
> +
> +       /* Train 2 */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_LINK_TRAIN_NONE;
> +       temp |= FDI_LINK_TRAIN_PATTERN_2;
> +       if (IS_GEN(dev_priv, 6)) {
> +               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> +               /* SNB-B */
> +               temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
> +       }
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       if (HAS_PCH_CPT(dev_priv)) {
> +               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> +               temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
> +       } else {
> +               temp &= ~FDI_LINK_TRAIN_NONE;
> +               temp |= FDI_LINK_TRAIN_PATTERN_2;
> +       }
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(150);
> +
> +       for (i = 0; i < 4; i++) {
> +               reg = FDI_TX_CTL(pipe);
> +               temp = intel_de_read(dev_priv, reg);
> +               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> +               temp |= snb_b_fdi_train_param[i];
> +               intel_de_write(dev_priv, reg, temp);
> +
> +               intel_de_posting_read(dev_priv, reg);
> +               udelay(500);
> +
> +               for (retry = 0; retry < 5; retry++) {
> +                       reg = FDI_RX_IIR(pipe);
> +                       temp = intel_de_read(dev_priv, reg);
> +                       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> +                       if (temp & FDI_RX_SYMBOL_LOCK) {
> +                               intel_de_write(dev_priv, reg,
> +                                              temp | FDI_RX_SYMBOL_LOCK);
> +                               drm_dbg_kms(&dev_priv->drm,
> +                                           "FDI train 2 done.\n");
> +                               break;
> +                       }
> +                       udelay(50);
> +               }
> +               if (retry < 5)
> +                       break;
> +       }
> +       if (i == 4)
> +               drm_err(&dev_priv->drm, "FDI train 2 fail!\n");
> +
> +       drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
> +}
> +
> +/* Manual link training for Ivy Bridge A0 parts */
> +static void ivb_manual_fdi_link_train(struct intel_crtc *crtc,
> +                                     const struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       enum pipe pipe = crtc->pipe;
> +       i915_reg_t reg;
> +       u32 temp, i, j;
> +
> +       /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
> +          for train result */
> +       reg = FDI_RX_IMR(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_RX_SYMBOL_LOCK;
> +       temp &= ~FDI_RX_BIT_LOCK;
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(150);
> +
> +       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR before link train 0x%x\n",
> +                   intel_de_read(dev_priv, FDI_RX_IIR(pipe)));
> +
> +       /* Try each vswing and preemphasis setting twice before moving on */
> +       for (j = 0; j < ARRAY_SIZE(snb_b_fdi_train_param) * 2; j++) {
> +               /* disable first in case we need to retry */
> +               reg = FDI_TX_CTL(pipe);
> +               temp = intel_de_read(dev_priv, reg);
> +               temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
> +               temp &= ~FDI_TX_ENABLE;
> +               intel_de_write(dev_priv, reg, temp);
> +
> +               reg = FDI_RX_CTL(pipe);
> +               temp = intel_de_read(dev_priv, reg);
> +               temp &= ~FDI_LINK_TRAIN_AUTO;
> +               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> +               temp &= ~FDI_RX_ENABLE;
> +               intel_de_write(dev_priv, reg, temp);
> +
> +               /* enable CPU FDI TX and PCH FDI RX */
> +               reg = FDI_TX_CTL(pipe);
> +               temp = intel_de_read(dev_priv, reg);
> +               temp &= ~FDI_DP_PORT_WIDTH_MASK;
> +               temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
> +               temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
> +               temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
> +               temp |= snb_b_fdi_train_param[j/2];
> +               temp |= FDI_COMPOSITE_SYNC;
> +               intel_de_write(dev_priv, reg, temp | FDI_TX_ENABLE);
> +
> +               intel_de_write(dev_priv, FDI_RX_MISC(pipe),
> +                              FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
> +
> +               reg = FDI_RX_CTL(pipe);
> +               temp = intel_de_read(dev_priv, reg);
> +               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
> +               temp |= FDI_COMPOSITE_SYNC;
> +               intel_de_write(dev_priv, reg, temp | FDI_RX_ENABLE);
> +
> +               intel_de_posting_read(dev_priv, reg);
> +               udelay(1); /* should be 0.5us */
> +
> +               for (i = 0; i < 4; i++) {
> +                       reg = FDI_RX_IIR(pipe);
> +                       temp = intel_de_read(dev_priv, reg);
> +                       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> +
> +                       if (temp & FDI_RX_BIT_LOCK ||
> +                           (intel_de_read(dev_priv, reg) & FDI_RX_BIT_LOCK)) {
> +                               intel_de_write(dev_priv, reg,
> +                                              temp | FDI_RX_BIT_LOCK);
> +                               drm_dbg_kms(&dev_priv->drm,
> +                                           "FDI train 1 done, level %i.\n",
> +                                           i);
> +                               break;
> +                       }
> +                       udelay(1); /* should be 0.5us */
> +               }
> +               if (i == 4) {
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "FDI train 1 fail on vswing %d\n", j / 2);
> +                       continue;
> +               }
> +
> +               /* Train 2 */
> +               reg = FDI_TX_CTL(pipe);
> +               temp = intel_de_read(dev_priv, reg);
> +               temp &= ~FDI_LINK_TRAIN_NONE_IVB;
> +               temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
> +               intel_de_write(dev_priv, reg, temp);
> +
> +               reg = FDI_RX_CTL(pipe);
> +               temp = intel_de_read(dev_priv, reg);
> +               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> +               temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
> +               intel_de_write(dev_priv, reg, temp);
> +
> +               intel_de_posting_read(dev_priv, reg);
> +               udelay(2); /* should be 1.5us */
> +
> +               for (i = 0; i < 4; i++) {
> +                       reg = FDI_RX_IIR(pipe);
> +                       temp = intel_de_read(dev_priv, reg);
> +                       drm_dbg_kms(&dev_priv->drm, "FDI_RX_IIR 0x%x\n", temp);
> +
> +                       if (temp & FDI_RX_SYMBOL_LOCK ||
> +                           (intel_de_read(dev_priv, reg) & FDI_RX_SYMBOL_LOCK)) {
> +                               intel_de_write(dev_priv, reg,
> +                                              temp | FDI_RX_SYMBOL_LOCK);
> +                               drm_dbg_kms(&dev_priv->drm,
> +                                           "FDI train 2 done, level %i.\n",
> +                                           i);
> +                               goto train_done;
> +                       }
> +                       udelay(2); /* should be 1.5us */
> +               }
> +               if (i == 4)
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "FDI train 2 fail on vswing %d\n", j / 2);
> +       }
> +
> +train_done:
> +       drm_dbg_kms(&dev_priv->drm, "FDI train done.\n");
> +}
> +
> +void ilk_fdi_pll_enable(const struct intel_crtc_state *crtc_state)
> +{
> +       struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +       struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
> +       enum pipe pipe = intel_crtc->pipe;
> +       i915_reg_t reg;
> +       u32 temp;
> +
> +       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
> +       temp |= FDI_DP_PORT_WIDTH(crtc_state->fdi_lanes);
> +       temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
> +       intel_de_write(dev_priv, reg, temp | FDI_RX_PLL_ENABLE);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(200);
> +
> +       /* Switch from Rawclk to PCDclk */
> +       temp = intel_de_read(dev_priv, reg);
> +       intel_de_write(dev_priv, reg, temp | FDI_PCDCLK);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(200);
> +
> +       /* Enable CPU FDI TX PLL, always on for Ironlake */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
> +               intel_de_write(dev_priv, reg, temp | FDI_TX_PLL_ENABLE);
> +
> +               intel_de_posting_read(dev_priv, reg);
> +               udelay(100);
> +       }
> +}
> +
> +void ilk_fdi_pll_disable(struct intel_crtc *intel_crtc)
> +{
> +       struct drm_device *dev = intel_crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       enum pipe pipe = intel_crtc->pipe;
> +       i915_reg_t reg;
> +       u32 temp;
> +
> +       /* Switch from PCDclk to Rawclk */
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       intel_de_write(dev_priv, reg, temp & ~FDI_PCDCLK);
> +
> +       /* Disable CPU FDI TX PLL */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       intel_de_write(dev_priv, reg, temp & ~FDI_TX_PLL_ENABLE);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(100);
> +
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       intel_de_write(dev_priv, reg, temp & ~FDI_RX_PLL_ENABLE);
> +
> +       /* Wait for the clocks to turn off. */
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(100);
> +}
> +
> +void ilk_fdi_disable(struct intel_crtc *crtc)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       enum pipe pipe = crtc->pipe;
> +       i915_reg_t reg;
> +       u32 temp;
> +
> +       /* disable CPU FDI tx and PCH FDI rx */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       intel_de_write(dev_priv, reg, temp & ~FDI_TX_ENABLE);
> +       intel_de_posting_read(dev_priv, reg);
> +
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~(0x7 << 16);
> +       temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
> +       intel_de_write(dev_priv, reg, temp & ~FDI_RX_ENABLE);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(100);
> +
> +       /* Ironlake workaround, disable clock pointer after downing FDI */
> +       if (HAS_PCH_IBX(dev_priv))
> +               intel_de_write(dev_priv, FDI_RX_CHICKEN(pipe),
> +                              FDI_RX_PHASE_SYNC_POINTER_OVR);
> +
> +       /* still set train pattern 1 */
> +       reg = FDI_TX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       temp &= ~FDI_LINK_TRAIN_NONE;
> +       temp |= FDI_LINK_TRAIN_PATTERN_1;
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       reg = FDI_RX_CTL(pipe);
> +       temp = intel_de_read(dev_priv, reg);
> +       if (HAS_PCH_CPT(dev_priv)) {
> +               temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
> +               temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
> +       } else {
> +               temp &= ~FDI_LINK_TRAIN_NONE;
> +               temp |= FDI_LINK_TRAIN_PATTERN_1;
> +       }
> +       /* BPC in FDI rx is consistent with that in PIPECONF */
> +       temp &= ~(0x07 << 16);
> +       temp |= (intel_de_read(dev_priv, PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
> +       intel_de_write(dev_priv, reg, temp);
> +
> +       intel_de_posting_read(dev_priv, reg);
> +       udelay(100);
> +}
> +
> +void
> +intel_init_fdi_hook(struct drm_i915_private *dev_priv)
> +{
> +       if (IS_GEN(dev_priv, 5)) {
> +               dev_priv->display.fdi_link_train = ilk_fdi_link_train;
> +       } else if (IS_GEN(dev_priv, 6)) {
> +               dev_priv->display.fdi_link_train = gen6_fdi_link_train;
> +       } else if (IS_IVYBRIDGE(dev_priv)) {
> +               /* FIXME: detect B0+ stepping and use auto training */
> +               dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
> +       }
> +}
> --
> 2.27.0
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Intel-gfx] [PATCH 3/4] drm/i915: refactor pll code out into intel_clock.c
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 3/4] drm/i915: refactor pll code out into intel_clock.c Dave Airlie
@ 2020-12-09 10:55   ` Daniel Vetter
  0 siblings, 0 replies; 13+ messages in thread
From: Daniel Vetter @ 2020-12-09 10:55 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx

On Wed, Dec 9, 2020 at 5:22 AM Dave Airlie <airlied@gmail.com> wrote:
>
> From: Dave Airlie <airlied@redhat.com>
>
> This pulls a large chunk of the pll calculation code out of
> intel_display.c to a new file.
>
> One function makse sense to be an inline, otherwise this
> is pretty much a straight copy cover. also all the
> remaining hooks for g45 and older end up the same now.
>
> Fixed one , instead of ; error in chv_find_best_dpll.

Maybe split that one out?

> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
>  drivers/gpu/drm/i915/Makefile                 |    1 +
>  drivers/gpu/drm/i915/display/intel_clock.c    | 1370 ++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_display.c  | 1392 +----------------
>  drivers/gpu/drm/i915/display/intel_display.h  |   13 +-
>  .../drm/i915/display/intel_display_types.h    |    5 +
>  5 files changed, 1398 insertions(+), 1383 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/display/intel_clock.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index ffec257702af..8b357c212ae2 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -193,6 +193,7 @@ i915-y += \
>         display/intel_bios.o \
>         display/intel_bw.o \
>         display/intel_cdclk.o \
> +       display/intel_clock.o \

I'd call this intel_dpll_legacy.c, to be more in line with the new
generation stuff which is in intel_dpll_mgr.c which is where all the
new code since hsw hangs out (except for chv, that's still derived
from the old ones).

Aside from the repaint looks reasonable to me.
-Daniel

>         display/intel_color.o \
>         display/intel_combo_phy.o \
>         display/intel_connector.o \
> diff --git a/drivers/gpu/drm/i915/display/intel_clock.c b/drivers/gpu/drm/i915/display/intel_clock.c
> new file mode 100644
> index 000000000000..75819c1da039
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_clock.c
> @@ -0,0 +1,1370 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2020 Intel Corporation
> + */
> +#include <linux/kernel.h>
> +#include "intel_display_types.h"
> +#include "intel_display.h"
> +#include "intel_lvds.h"
> +#include "intel_panel.h"
> +
> +static bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
> +{
> +       if (dev_priv->params.panel_use_ssc >= 0)
> +               return dev_priv->params.panel_use_ssc != 0;
> +       return dev_priv->vbt.lvds_use_ssc
> +               && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
> +}
> +
> +struct intel_limit {
> +       struct {
> +               int min, max;
> +       } dot, vco, n, m, m1, m2, p, p1;
> +
> +       struct {
> +               int dot_limit;
> +               int p2_slow, p2_fast;
> +       } p2;
> +};
> +static const struct intel_limit intel_limits_i8xx_dac = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 908000, .max = 1512000 },
> +       .n = { .min = 2, .max = 16 },
> +       .m = { .min = 96, .max = 140 },
> +       .m1 = { .min = 18, .max = 26 },
> +       .m2 = { .min = 6, .max = 16 },
> +       .p = { .min = 4, .max = 128 },
> +       .p1 = { .min = 2, .max = 33 },
> +       .p2 = { .dot_limit = 165000,
> +               .p2_slow = 4, .p2_fast = 2 },
> +};
> +
> +static const struct intel_limit intel_limits_i8xx_dvo = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 908000, .max = 1512000 },
> +       .n = { .min = 2, .max = 16 },
> +       .m = { .min = 96, .max = 140 },
> +       .m1 = { .min = 18, .max = 26 },
> +       .m2 = { .min = 6, .max = 16 },
> +       .p = { .min = 4, .max = 128 },
> +       .p1 = { .min = 2, .max = 33 },
> +       .p2 = { .dot_limit = 165000,
> +               .p2_slow = 4, .p2_fast = 4 },
> +};
> +
> +static const struct intel_limit intel_limits_i8xx_lvds = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 908000, .max = 1512000 },
> +       .n = { .min = 2, .max = 16 },
> +       .m = { .min = 96, .max = 140 },
> +       .m1 = { .min = 18, .max = 26 },
> +       .m2 = { .min = 6, .max = 16 },
> +       .p = { .min = 4, .max = 128 },
> +       .p1 = { .min = 1, .max = 6 },
> +       .p2 = { .dot_limit = 165000,
> +               .p2_slow = 14, .p2_fast = 7 },
> +};
> +
> +static const struct intel_limit intel_limits_i9xx_sdvo = {
> +       .dot = { .min = 20000, .max = 400000 },
> +       .vco = { .min = 1400000, .max = 2800000 },
> +       .n = { .min = 1, .max = 6 },
> +       .m = { .min = 70, .max = 120 },
> +       .m1 = { .min = 8, .max = 18 },
> +       .m2 = { .min = 3, .max = 7 },
> +       .p = { .min = 5, .max = 80 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 200000,
> +               .p2_slow = 10, .p2_fast = 5 },
> +};
> +
> +static const struct intel_limit intel_limits_i9xx_lvds = {
> +       .dot = { .min = 20000, .max = 400000 },
> +       .vco = { .min = 1400000, .max = 2800000 },
> +       .n = { .min = 1, .max = 6 },
> +       .m = { .min = 70, .max = 120 },
> +       .m1 = { .min = 8, .max = 18 },
> +       .m2 = { .min = 3, .max = 7 },
> +       .p = { .min = 7, .max = 98 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 112000,
> +               .p2_slow = 14, .p2_fast = 7 },
> +};
> +
> +
> +static const struct intel_limit intel_limits_g4x_sdvo = {
> +       .dot = { .min = 25000, .max = 270000 },
> +       .vco = { .min = 1750000, .max = 3500000},
> +       .n = { .min = 1, .max = 4 },
> +       .m = { .min = 104, .max = 138 },
> +       .m1 = { .min = 17, .max = 23 },
> +       .m2 = { .min = 5, .max = 11 },
> +       .p = { .min = 10, .max = 30 },
> +       .p1 = { .min = 1, .max = 3},
> +       .p2 = { .dot_limit = 270000,
> +               .p2_slow = 10,
> +               .p2_fast = 10
> +       },
> +};
> +
> +static const struct intel_limit intel_limits_g4x_hdmi = {
> +       .dot = { .min = 22000, .max = 400000 },
> +       .vco = { .min = 1750000, .max = 3500000},
> +       .n = { .min = 1, .max = 4 },
> +       .m = { .min = 104, .max = 138 },
> +       .m1 = { .min = 16, .max = 23 },
> +       .m2 = { .min = 5, .max = 11 },
> +       .p = { .min = 5, .max = 80 },
> +       .p1 = { .min = 1, .max = 8},
> +       .p2 = { .dot_limit = 165000,
> +               .p2_slow = 10, .p2_fast = 5 },
> +};
> +
> +static const struct intel_limit intel_limits_g4x_single_channel_lvds = {
> +       .dot = { .min = 20000, .max = 115000 },
> +       .vco = { .min = 1750000, .max = 3500000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 104, .max = 138 },
> +       .m1 = { .min = 17, .max = 23 },
> +       .m2 = { .min = 5, .max = 11 },
> +       .p = { .min = 28, .max = 112 },
> +       .p1 = { .min = 2, .max = 8 },
> +       .p2 = { .dot_limit = 0,
> +               .p2_slow = 14, .p2_fast = 14
> +       },
> +};
> +
> +static const struct intel_limit intel_limits_g4x_dual_channel_lvds = {
> +       .dot = { .min = 80000, .max = 224000 },
> +       .vco = { .min = 1750000, .max = 3500000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 104, .max = 138 },
> +       .m1 = { .min = 17, .max = 23 },
> +       .m2 = { .min = 5, .max = 11 },
> +       .p = { .min = 14, .max = 42 },
> +       .p1 = { .min = 2, .max = 6 },
> +       .p2 = { .dot_limit = 0,
> +               .p2_slow = 7, .p2_fast = 7
> +       },
> +};
> +
> +static const struct intel_limit pnv_limits_sdvo = {
> +       .dot = { .min = 20000, .max = 400000},
> +       .vco = { .min = 1700000, .max = 3500000 },
> +       /* Pineview's Ncounter is a ring counter */
> +       .n = { .min = 3, .max = 6 },
> +       .m = { .min = 2, .max = 256 },
> +       /* Pineview only has one combined m divider, which we treat as m2. */
> +       .m1 = { .min = 0, .max = 0 },
> +       .m2 = { .min = 0, .max = 254 },
> +       .p = { .min = 5, .max = 80 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 200000,
> +               .p2_slow = 10, .p2_fast = 5 },
> +};
> +
> +static const struct intel_limit pnv_limits_lvds = {
> +       .dot = { .min = 20000, .max = 400000 },
> +       .vco = { .min = 1700000, .max = 3500000 },
> +       .n = { .min = 3, .max = 6 },
> +       .m = { .min = 2, .max = 256 },
> +       .m1 = { .min = 0, .max = 0 },
> +       .m2 = { .min = 0, .max = 254 },
> +       .p = { .min = 7, .max = 112 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 112000,
> +               .p2_slow = 14, .p2_fast = 14 },
> +};
> +
> +/* Ironlake / Sandybridge
> + *
> + * We calculate clock using (register_value + 2) for N/M1/M2, so here
> + * the range value for them is (actual_value - 2).
> + */
> +static const struct intel_limit ilk_limits_dac = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 5 },
> +       .m = { .min = 79, .max = 127 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 5, .max = 80 },
> +       .p1 = { .min = 1, .max = 8 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 10, .p2_fast = 5 },
> +};
> +
> +static const struct intel_limit ilk_limits_single_lvds = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 79, .max = 118 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 28, .max = 112 },
> +       .p1 = { .min = 2, .max = 8 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 14, .p2_fast = 14 },
> +};
> +
> +static const struct intel_limit ilk_limits_dual_lvds = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 79, .max = 127 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 14, .max = 56 },
> +       .p1 = { .min = 2, .max = 8 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 7, .p2_fast = 7 },
> +};
> +
> +/* LVDS 100mhz refclk limits. */
> +static const struct intel_limit ilk_limits_single_lvds_100m = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 2 },
> +       .m = { .min = 79, .max = 126 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 28, .max = 112 },
> +       .p1 = { .min = 2, .max = 8 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 14, .p2_fast = 14 },
> +};
> +
> +static const struct intel_limit ilk_limits_dual_lvds_100m = {
> +       .dot = { .min = 25000, .max = 350000 },
> +       .vco = { .min = 1760000, .max = 3510000 },
> +       .n = { .min = 1, .max = 3 },
> +       .m = { .min = 79, .max = 126 },
> +       .m1 = { .min = 12, .max = 22 },
> +       .m2 = { .min = 5, .max = 9 },
> +       .p = { .min = 14, .max = 42 },
> +       .p1 = { .min = 2, .max = 6 },
> +       .p2 = { .dot_limit = 225000,
> +               .p2_slow = 7, .p2_fast = 7 },
> +};
> +
> +static const struct intel_limit intel_limits_vlv = {
> +        /*
> +         * These are the data rate limits (measured in fast clocks)
> +         * since those are the strictest limits we have. The fast
> +         * clock and actual rate limits are more relaxed, so checking
> +         * them would make no difference.
> +         */
> +       .dot = { .min = 25000 * 5, .max = 270000 * 5 },
> +       .vco = { .min = 4000000, .max = 6000000 },
> +       .n = { .min = 1, .max = 7 },
> +       .m1 = { .min = 2, .max = 3 },
> +       .m2 = { .min = 11, .max = 156 },
> +       .p1 = { .min = 2, .max = 3 },
> +       .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */
> +};
> +
> +static const struct intel_limit intel_limits_chv = {
> +       /*
> +        * These are the data rate limits (measured in fast clocks)
> +        * since those are the strictest limits we have.  The fast
> +        * clock and actual rate limits are more relaxed, so checking
> +        * them would make no difference.
> +        */
> +       .dot = { .min = 25000 * 5, .max = 540000 * 5},
> +       .vco = { .min = 4800000, .max = 6480000 },
> +       .n = { .min = 1, .max = 1 },
> +       .m1 = { .min = 2, .max = 2 },
> +       .m2 = { .min = 24 << 22, .max = 175 << 22 },
> +       .p1 = { .min = 2, .max = 4 },
> +       .p2 = { .p2_slow = 1, .p2_fast = 14 },
> +};
> +
> +static const struct intel_limit intel_limits_bxt = {
> +       /* FIXME: find real dot limits */
> +       .dot = { .min = 0, .max = INT_MAX },
> +       .vco = { .min = 4800000, .max = 6700000 },
> +       .n = { .min = 1, .max = 1 },
> +       .m1 = { .min = 2, .max = 2 },
> +       /* FIXME: find real m2 limits */
> +       .m2 = { .min = 2 << 22, .max = 255 << 22 },
> +       .p1 = { .min = 2, .max = 4 },
> +       .p2 = { .p2_slow = 1, .p2_fast = 20 },
> +};
> +
> +/*
> + * Platform specific helpers to calculate the port PLL loopback- (clock.m),
> + * and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast
> + * (clock.dot) clock rates. This fast dot clock is fed to the port's IO logic.
> + * The helpers' return value is the rate of the clock that is fed to the
> + * display engine's pipe which can be the above fast dot clock rate or a
> + * divided-down version of it.
> + */
> +/* m1 is reserved as 0 in Pineview, n is a ring counter */
> +int pnv_calc_dpll_params(int refclk, struct dpll *clock)
> +{
> +       clock->m = clock->m2 + 2;
> +       clock->p = clock->p1 * clock->p2;
> +       if (WARN_ON(clock->n == 0 || clock->p == 0))
> +               return 0;
> +       clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
> +       clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
> +
> +       return clock->dot;
> +}
> +
> +static u32 i9xx_dpll_compute_m(struct dpll *dpll)
> +{
> +       return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
> +}
> +
> +int i9xx_calc_dpll_params(int refclk, struct dpll *clock)
> +{
> +       clock->m = i9xx_dpll_compute_m(clock);
> +       clock->p = clock->p1 * clock->p2;
> +       if (WARN_ON(clock->n + 2 == 0 || clock->p == 0))
> +               return 0;
> +       clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2);
> +       clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
> +
> +       return clock->dot;
> +}
> +
> +int vlv_calc_dpll_params(int refclk, struct dpll *clock)
> +{
> +       clock->m = clock->m1 * clock->m2;
> +       clock->p = clock->p1 * clock->p2;
> +       if (WARN_ON(clock->n == 0 || clock->p == 0))
> +               return 0;
> +       clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
> +       clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
> +
> +       return clock->dot / 5;
> +}
> +
> +int chv_calc_dpll_params(int refclk, struct dpll *clock)
> +{
> +       clock->m = clock->m1 * clock->m2;
> +       clock->p = clock->p1 * clock->p2;
> +       if (WARN_ON(clock->n == 0 || clock->p == 0))
> +               return 0;
> +       clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
> +                                          clock->n << 22);
> +       clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
> +
> +       return clock->dot / 5;
> +}
> +
> +/*
> + * Returns whether the given set of divisors are valid for a given refclk with
> + * the given connectors.
> + */
> +static bool intel_pll_is_valid(struct drm_i915_private *dev_priv,
> +                              const struct intel_limit *limit,
> +                              const struct dpll *clock)
> +{
> +       if (clock->n < limit->n.min || limit->n.max < clock->n)
> +               return false;
> +       if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
> +               return false;
> +       if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2)
> +               return false;
> +       if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
> +               return false;
> +
> +       if (!IS_PINEVIEW(dev_priv) && !IS_VALLEYVIEW(dev_priv) &&
> +           !IS_CHERRYVIEW(dev_priv) && !IS_GEN9_LP(dev_priv))
> +               if (clock->m1 <= clock->m2)
> +                       return false;
> +
> +       if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
> +           !IS_GEN9_LP(dev_priv)) {
> +               if (clock->p < limit->p.min || limit->p.max < clock->p)
> +                       return false;
> +               if (clock->m < limit->m.min || limit->m.max < clock->m)
> +                       return false;
> +       }
> +
> +       if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
> +               return false;
> +       /* XXX: We may need to be checking "Dot clock" depending on the multiplier,
> +        * connector, etc., rather than just a single range.
> +        */
> +       if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
> +               return false;
> +
> +       return true;
> +}
> +
> +static int
> +i9xx_select_p2_div(const struct intel_limit *limit,
> +                  const struct intel_crtc_state *crtc_state,
> +                  int target)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> +               /*
> +                * For LVDS just rely on its current settings for dual-channel.
> +                * We haven't figured out how to reliably set up different
> +                * single/dual channel state, if we even can.
> +                */
> +               if (intel_is_dual_link_lvds(dev_priv))
> +                       return limit->p2.p2_fast;
> +               else
> +                       return limit->p2.p2_slow;
> +       } else {
> +               if (target < limit->p2.dot_limit)
> +                       return limit->p2.p2_slow;
> +               else
> +                       return limit->p2.p2_fast;
> +       }
> +}
> +
> +/*
> + * Returns a set of divisors for the desired target clock with the given
> + * refclk, or FALSE.  The returned values represent the clock equation:
> + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> + *
> + * Target and reference clocks are specified in kHz.
> + *
> + * If match_clock is provided, then best_clock P divider must match the P
> + * divider from @match_clock used for LVDS downclocking.
> + */
> +static bool
> +i9xx_find_best_dpll(const struct intel_limit *limit,
> +                   struct intel_crtc_state *crtc_state,
> +                   int target, int refclk, struct dpll *match_clock,
> +                   struct dpll *best_clock)
> +{
> +       struct drm_device *dev = crtc_state->uapi.crtc->dev;
> +       struct dpll clock;
> +       int err = target;
> +
> +       memset(best_clock, 0, sizeof(*best_clock));
> +
> +       clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
> +
> +       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
> +            clock.m1++) {
> +               for (clock.m2 = limit->m2.min;
> +                    clock.m2 <= limit->m2.max; clock.m2++) {
> +                       if (clock.m2 >= clock.m1)
> +                               break;
> +                       for (clock.n = limit->n.min;
> +                            clock.n <= limit->n.max; clock.n++) {
> +                               for (clock.p1 = limit->p1.min;
> +                                       clock.p1 <= limit->p1.max; clock.p1++) {
> +                                       int this_err;
> +
> +                                       i9xx_calc_dpll_params(refclk, &clock);
> +                                       if (!intel_pll_is_valid(to_i915(dev),
> +                                                               limit,
> +                                                               &clock))
> +                                               continue;
> +                                       if (match_clock &&
> +                                           clock.p != match_clock->p)
> +                                               continue;
> +
> +                                       this_err = abs(clock.dot - target);
> +                                       if (this_err < err) {
> +                                               *best_clock = clock;
> +                                               err = this_err;
> +                                       }
> +                               }
> +                       }
> +               }
> +       }
> +
> +       return (err != target);
> +}
> +
> +/*
> + * Returns a set of divisors for the desired target clock with the given
> + * refclk, or FALSE.  The returned values represent the clock equation:
> + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> + *
> + * Target and reference clocks are specified in kHz.
> + *
> + * If match_clock is provided, then best_clock P divider must match the P
> + * divider from @match_clock used for LVDS downclocking.
> + */
> +static bool
> +pnv_find_best_dpll(const struct intel_limit *limit,
> +                  struct intel_crtc_state *crtc_state,
> +                  int target, int refclk, struct dpll *match_clock,
> +                  struct dpll *best_clock)
> +{
> +       struct drm_device *dev = crtc_state->uapi.crtc->dev;
> +       struct dpll clock;
> +       int err = target;
> +
> +       memset(best_clock, 0, sizeof(*best_clock));
> +
> +       clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
> +
> +       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
> +            clock.m1++) {
> +               for (clock.m2 = limit->m2.min;
> +                    clock.m2 <= limit->m2.max; clock.m2++) {
> +                       for (clock.n = limit->n.min;
> +                            clock.n <= limit->n.max; clock.n++) {
> +                               for (clock.p1 = limit->p1.min;
> +                                       clock.p1 <= limit->p1.max; clock.p1++) {
> +                                       int this_err;
> +
> +                                       pnv_calc_dpll_params(refclk, &clock);
> +                                       if (!intel_pll_is_valid(to_i915(dev),
> +                                                               limit,
> +                                                               &clock))
> +                                               continue;
> +                                       if (match_clock &&
> +                                           clock.p != match_clock->p)
> +                                               continue;
> +
> +                                       this_err = abs(clock.dot - target);
> +                                       if (this_err < err) {
> +                                               *best_clock = clock;
> +                                               err = this_err;
> +                                       }
> +                               }
> +                       }
> +               }
> +       }
> +
> +       return (err != target);
> +}
> +
> +/*
> + * Returns a set of divisors for the desired target clock with the given
> + * refclk, or FALSE.  The returned values represent the clock equation:
> + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> + *
> + * Target and reference clocks are specified in kHz.
> + *
> + * If match_clock is provided, then best_clock P divider must match the P
> + * divider from @match_clock used for LVDS downclocking.
> + */
> +static bool
> +g4x_find_best_dpll(const struct intel_limit *limit,
> +                  struct intel_crtc_state *crtc_state,
> +                  int target, int refclk, struct dpll *match_clock,
> +                  struct dpll *best_clock)
> +{
> +       struct drm_device *dev = crtc_state->uapi.crtc->dev;
> +       struct dpll clock;
> +       int max_n;
> +       bool found = false;
> +       /* approximately equals target * 0.00585 */
> +       int err_most = (target >> 8) + (target >> 9);
> +
> +       memset(best_clock, 0, sizeof(*best_clock));
> +
> +       clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
> +
> +       max_n = limit->n.max;
> +       /* based on hardware requirement, prefer smaller n to precision */
> +       for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
> +               /* based on hardware requirement, prefere larger m1,m2 */
> +               for (clock.m1 = limit->m1.max;
> +                    clock.m1 >= limit->m1.min; clock.m1--) {
> +                       for (clock.m2 = limit->m2.max;
> +                            clock.m2 >= limit->m2.min; clock.m2--) {
> +                               for (clock.p1 = limit->p1.max;
> +                                    clock.p1 >= limit->p1.min; clock.p1--) {
> +                                       int this_err;
> +
> +                                       i9xx_calc_dpll_params(refclk, &clock);
> +                                       if (!intel_pll_is_valid(to_i915(dev),
> +                                                               limit,
> +                                                               &clock))
> +                                               continue;
> +
> +                                       this_err = abs(clock.dot - target);
> +                                       if (this_err < err_most) {
> +                                               *best_clock = clock;
> +                                               err_most = this_err;
> +                                               max_n = clock.n;
> +                                               found = true;
> +                                       }
> +                               }
> +                       }
> +               }
> +       }
> +       return found;
> +}
> +
> +/*
> + * Check if the calculated PLL configuration is more optimal compared to the
> + * best configuration and error found so far. Return the calculated error.
> + */
> +static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
> +                              const struct dpll *calculated_clock,
> +                              const struct dpll *best_clock,
> +                              unsigned int best_error_ppm,
> +                              unsigned int *error_ppm)
> +{
> +       /*
> +        * For CHV ignore the error and consider only the P value.
> +        * Prefer a bigger P value based on HW requirements.
> +        */
> +       if (IS_CHERRYVIEW(to_i915(dev))) {
> +               *error_ppm = 0;
> +
> +               return calculated_clock->p > best_clock->p;
> +       }
> +
> +       if (drm_WARN_ON_ONCE(dev, !target_freq))
> +               return false;
> +
> +       *error_ppm = div_u64(1000000ULL *
> +                               abs(target_freq - calculated_clock->dot),
> +                            target_freq);
> +       /*
> +        * Prefer a better P value over a better (smaller) error if the error
> +        * is small. Ensure this preference for future configurations too by
> +        * setting the error to 0.
> +        */
> +       if (*error_ppm < 100 && calculated_clock->p > best_clock->p) {
> +               *error_ppm = 0;
> +
> +               return true;
> +       }
> +
> +       return *error_ppm + 10 < best_error_ppm;
> +}
> +
> +/*
> + * Returns a set of divisors for the desired target clock with the given
> + * refclk, or FALSE.  The returned values represent the clock equation:
> + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> + */
> +static bool
> +vlv_find_best_dpll(const struct intel_limit *limit,
> +                  struct intel_crtc_state *crtc_state,
> +                  int target, int refclk, struct dpll *match_clock,
> +                  struct dpll *best_clock)
> +{
> +       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +       struct drm_device *dev = crtc->base.dev;
> +       struct dpll clock;
> +       unsigned int bestppm = 1000000;
> +       /* min update 19.2 MHz */
> +       int max_n = min(limit->n.max, refclk / 19200);
> +       bool found = false;
> +
> +       target *= 5; /* fast clock */
> +
> +       memset(best_clock, 0, sizeof(*best_clock));
> +
> +       /* based on hardware requirement, prefer smaller n to precision */
> +       for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
> +               for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
> +                       for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow;
> +                            clock.p2 -= clock.p2 > 10 ? 2 : 1) {
> +                               clock.p = clock.p1 * clock.p2;
> +                               /* based on hardware requirement, prefer bigger m1,m2 values */
> +                               for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
> +                                       unsigned int ppm;
> +
> +                                       clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n,
> +                                                                    refclk * clock.m1);
> +
> +                                       vlv_calc_dpll_params(refclk, &clock);
> +
> +                                       if (!intel_pll_is_valid(to_i915(dev),
> +                                                               limit,
> +                                                               &clock))
> +                                               continue;
> +
> +                                       if (!vlv_PLL_is_optimal(dev, target,
> +                                                               &clock,
> +                                                               best_clock,
> +                                                               bestppm, &ppm))
> +                                               continue;
> +
> +                                       *best_clock = clock;
> +                                       bestppm = ppm;
> +                                       found = true;
> +                               }
> +                       }
> +               }
> +       }
> +
> +       return found;
> +}
> +
> +/*
> + * Returns a set of divisors for the desired target clock with the given
> + * refclk, or FALSE.  The returned values represent the clock equation:
> + * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> + */
> +static bool
> +chv_find_best_dpll(const struct intel_limit *limit,
> +                  struct intel_crtc_state *crtc_state,
> +                  int target, int refclk, struct dpll *match_clock,
> +                  struct dpll *best_clock)
> +{
> +       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +       struct drm_device *dev = crtc->base.dev;
> +       unsigned int best_error_ppm;
> +       struct dpll clock;
> +       u64 m2;
> +       int found = false;
> +
> +       memset(best_clock, 0, sizeof(*best_clock));
> +       best_error_ppm = 1000000;
> +
> +       /*
> +        * Based on hardware doc, the n always set to 1, and m1 always
> +        * set to 2.  If requires to support 200Mhz refclk, we need to
> +        * revisit this because n may not 1 anymore.
> +        */
> +       clock.n = 1;
> +       clock.m1 = 2;
> +       target *= 5;    /* fast clock */
> +
> +       for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
> +               for (clock.p2 = limit->p2.p2_fast;
> +                               clock.p2 >= limit->p2.p2_slow;
> +                               clock.p2 -= clock.p2 > 10 ? 2 : 1) {
> +                       unsigned int error_ppm;
> +
> +                       clock.p = clock.p1 * clock.p2;
> +
> +                       m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
> +                                                  refclk * clock.m1);
> +
> +                       if (m2 > INT_MAX/clock.m1)
> +                               continue;
> +
> +                       clock.m2 = m2;
> +
> +                       chv_calc_dpll_params(refclk, &clock);
> +
> +                       if (!intel_pll_is_valid(to_i915(dev), limit, &clock))
> +                               continue;
> +
> +                       if (!vlv_PLL_is_optimal(dev, target, &clock, best_clock,
> +                                               best_error_ppm, &error_ppm))
> +                               continue;
> +
> +                       *best_clock = clock;
> +                       best_error_ppm = error_ppm;
> +                       found = true;
> +               }
> +       }
> +
> +       return found;
> +}
> +
> +bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
> +                       struct dpll *best_clock)
> +{
> +       int refclk = 100000;
> +       const struct intel_limit *limit = &intel_limits_bxt;
> +
> +       return chv_find_best_dpll(limit, crtc_state,
> +                                 crtc_state->port_clock, refclk,
> +                                 NULL, best_clock);
> +}
> +
> +static u32 pnv_dpll_compute_fp(struct dpll *dpll)
> +{
> +       return (1 << dpll->n) << 16 | dpll->m2;
> +}
> +
> +static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
> +                                    struct intel_crtc_state *crtc_state,
> +                                    struct dpll *reduced_clock)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       u32 fp, fp2 = 0;
> +
> +       if (IS_PINEVIEW(dev_priv)) {
> +               fp = pnv_dpll_compute_fp(&crtc_state->dpll);
> +               if (reduced_clock)
> +                       fp2 = pnv_dpll_compute_fp(reduced_clock);
> +       } else {
> +               fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
> +               if (reduced_clock)
> +                       fp2 = i9xx_dpll_compute_fp(reduced_clock);
> +       }
> +
> +       crtc_state->dpll_hw_state.fp0 = fp;
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
> +           reduced_clock) {
> +               crtc_state->dpll_hw_state.fp1 = fp2;
> +       } else {
> +               crtc_state->dpll_hw_state.fp1 = fp;
> +       }
> +}
> +
> +static void i9xx_compute_dpll(struct intel_crtc *crtc,
> +                             struct intel_crtc_state *crtc_state,
> +                             struct dpll *reduced_clock)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       u32 dpll;
> +       struct dpll *clock = &crtc_state->dpll;
> +
> +       i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
> +
> +       dpll = DPLL_VGA_MODE_DIS;
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
> +               dpll |= DPLLB_MODE_LVDS;
> +       else
> +               dpll |= DPLLB_MODE_DAC_SERIAL;
> +
> +       if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
> +           IS_G33(dev_priv) || IS_PINEVIEW(dev_priv)) {
> +               dpll |= (crtc_state->pixel_multiplier - 1)
> +                       << SDVO_MULTIPLIER_SHIFT_HIRES;
> +       }
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
> +           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
> +               dpll |= DPLL_SDVO_HIGH_SPEED;
> +
> +       if (intel_crtc_has_dp_encoder(crtc_state))
> +               dpll |= DPLL_SDVO_HIGH_SPEED;
> +
> +       /* compute bitmask from p1 value */
> +       if (IS_PINEVIEW(dev_priv))
> +               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
> +       else {
> +               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
> +               if (IS_G4X(dev_priv) && reduced_clock)
> +                       dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
> +       }
> +       switch (clock->p2) {
> +       case 5:
> +               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
> +               break;
> +       case 7:
> +               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
> +               break;
> +       case 10:
> +               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
> +               break;
> +       case 14:
> +               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
> +               break;
> +       }
> +       if (INTEL_GEN(dev_priv) >= 4)
> +               dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
> +
> +       if (crtc_state->sdvo_tv_clock)
> +               dpll |= PLL_REF_INPUT_TVCLKINBC;
> +       else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
> +                intel_panel_use_ssc(dev_priv))
> +               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
> +       else
> +               dpll |= PLL_REF_INPUT_DREFCLK;
> +
> +       dpll |= DPLL_VCO_ENABLE;
> +       crtc_state->dpll_hw_state.dpll = dpll;
> +
> +       if (INTEL_GEN(dev_priv) >= 4) {
> +               u32 dpll_md = (crtc_state->pixel_multiplier - 1)
> +                       << DPLL_MD_UDI_MULTIPLIER_SHIFT;
> +               crtc_state->dpll_hw_state.dpll_md = dpll_md;
> +       }
> +}
> +
> +static void i8xx_compute_dpll(struct intel_crtc *crtc,
> +                             struct intel_crtc_state *crtc_state,
> +                             struct dpll *reduced_clock)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       u32 dpll;
> +       struct dpll *clock = &crtc_state->dpll;
> +
> +       i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
> +
> +       dpll = DPLL_VGA_MODE_DIS;
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> +               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
> +       } else {
> +               if (clock->p1 == 2)
> +                       dpll |= PLL_P1_DIVIDE_BY_TWO;
> +               else
> +                       dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
> +               if (clock->p2 == 4)
> +                       dpll |= PLL_P2_DIVIDE_BY_4;
> +       }
> +
> +       /*
> +        * Bspec:
> +        * "[Almador Errata}: For the correct operation of the muxed DVO pins
> +        *  (GDEVSELB/I2Cdata, GIRDBY/I2CClk) and (GFRAMEB/DVI_Data,
> +        *  GTRDYB/DVI_Clk): Bit 31 (DPLL VCO Enable) and Bit 30 (2X Clock
> +        *  Enable) must be set to “1” in both the DPLL A Control Register
> +        *  (06014h-06017h) and DPLL B Control Register (06018h-0601Bh)."
> +        *
> +        * For simplicity We simply keep both bits always enabled in
> +        * both DPLLS. The spec says we should disable the DVO 2X clock
> +        * when not needed, but this seems to work fine in practice.
> +        */
> +       if (IS_I830(dev_priv) ||
> +           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO))
> +               dpll |= DPLL_DVO_2X_MODE;
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
> +           intel_panel_use_ssc(dev_priv))
> +               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
> +       else
> +               dpll |= PLL_REF_INPUT_DREFCLK;
> +
> +       dpll |= DPLL_VCO_ENABLE;
> +       crtc_state->dpll_hw_state.dpll = dpll;
> +}
> +
> +static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
> +                                 struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       struct intel_atomic_state *state =
> +               to_intel_atomic_state(crtc_state->uapi.state);
> +
> +       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) ||
> +           INTEL_GEN(dev_priv) >= 11) {
> +               struct intel_encoder *encoder =
> +                       intel_get_crtc_new_encoder(state, crtc_state);
> +
> +               if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "failed to find PLL for pipe %c\n",
> +                                   pipe_name(crtc->pipe));
> +                       return -EINVAL;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static bool ilk_needs_fb_cb_tune(struct dpll *dpll, int factor)
> +{
> +       return i9xx_dpll_compute_m(dpll) < factor * dpll->n;
> +}
> +
> +
> +static void ilk_compute_dpll(struct intel_crtc *crtc,
> +                            struct intel_crtc_state *crtc_state,
> +                            struct dpll *reduced_clock)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       u32 dpll, fp, fp2;
> +       int factor;
> +
> +       /* Enable autotuning of the PLL clock (if permissible) */
> +       factor = 21;
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> +               if ((intel_panel_use_ssc(dev_priv) &&
> +                    dev_priv->vbt.lvds_ssc_freq == 100000) ||
> +                   (HAS_PCH_IBX(dev_priv) &&
> +                    intel_is_dual_link_lvds(dev_priv)))
> +                       factor = 25;
> +       } else if (crtc_state->sdvo_tv_clock) {
> +               factor = 20;
> +       }
> +
> +       fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
> +
> +       if (ilk_needs_fb_cb_tune(&crtc_state->dpll, factor))
> +               fp |= FP_CB_TUNE;
> +
> +       if (reduced_clock) {
> +               fp2 = i9xx_dpll_compute_fp(reduced_clock);
> +
> +               if (reduced_clock->m < factor * reduced_clock->n)
> +                       fp2 |= FP_CB_TUNE;
> +       } else {
> +               fp2 = fp;
> +       }
> +
> +       dpll = 0;
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
> +               dpll |= DPLLB_MODE_LVDS;
> +       else
> +               dpll |= DPLLB_MODE_DAC_SERIAL;
> +
> +       dpll |= (crtc_state->pixel_multiplier - 1)
> +               << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
> +           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
> +               dpll |= DPLL_SDVO_HIGH_SPEED;
> +
> +       if (intel_crtc_has_dp_encoder(crtc_state))
> +               dpll |= DPLL_SDVO_HIGH_SPEED;
> +
> +       /*
> +        * The high speed IO clock is only really required for
> +        * SDVO/HDMI/DP, but we also enable it for CRT to make it
> +        * possible to share the DPLL between CRT and HDMI. Enabling
> +        * the clock needlessly does no real harm, except use up a
> +        * bit of power potentially.
> +        *
> +        * We'll limit this to IVB with 3 pipes, since it has only two
> +        * DPLLs and so DPLL sharing is the only way to get three pipes
> +        * driving PCH ports at the same time. On SNB we could do this,
> +        * and potentially avoid enabling the second DPLL, but it's not
> +        * clear if it''s a win or loss power wise. No point in doing
> +        * this on ILK at all since it has a fixed DPLL<->pipe mapping.
> +        */
> +       if (INTEL_NUM_PIPES(dev_priv) == 3 &&
> +           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
> +               dpll |= DPLL_SDVO_HIGH_SPEED;
> +
> +       /* compute bitmask from p1 value */
> +       dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
> +       /* also FPA1 */
> +       dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
> +
> +       switch (crtc_state->dpll.p2) {
> +       case 5:
> +               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
> +               break;
> +       case 7:
> +               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
> +               break;
> +       case 10:
> +               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
> +               break;
> +       case 14:
> +               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
> +               break;
> +       }
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
> +           intel_panel_use_ssc(dev_priv))
> +               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
> +       else
> +               dpll |= PLL_REF_INPUT_DREFCLK;
> +
> +       dpll |= DPLL_VCO_ENABLE;
> +
> +       crtc_state->dpll_hw_state.dpll = dpll;
> +       crtc_state->dpll_hw_state.fp0 = fp;
> +       crtc_state->dpll_hw_state.fp1 = fp2;
> +}
> +
> +static int ilk_crtc_compute_clock(struct intel_crtc *crtc,
> +                                 struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       struct intel_atomic_state *state =
> +               to_intel_atomic_state(crtc_state->uapi.state);
> +       const struct intel_limit *limit;
> +       int refclk = 120000;
> +
> +       memset(&crtc_state->dpll_hw_state, 0,
> +              sizeof(crtc_state->dpll_hw_state));
> +
> +       /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
> +       if (!crtc_state->has_pch_encoder)
> +               return 0;
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> +               if (intel_panel_use_ssc(dev_priv)) {
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "using SSC reference clock of %d kHz\n",
> +                                   dev_priv->vbt.lvds_ssc_freq);
> +                       refclk = dev_priv->vbt.lvds_ssc_freq;
> +               }
> +
> +               if (intel_is_dual_link_lvds(dev_priv)) {
> +                       if (refclk == 100000)
> +                               limit = &ilk_limits_dual_lvds_100m;
> +                       else
> +                               limit = &ilk_limits_dual_lvds;
> +               } else {
> +                       if (refclk == 100000)
> +                               limit = &ilk_limits_single_lvds_100m;
> +                       else
> +                               limit = &ilk_limits_single_lvds;
> +               }
> +       } else {
> +               limit = &ilk_limits_dac;
> +       }
> +
> +       if (!crtc_state->clock_set &&
> +           !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> +                               refclk, NULL, &crtc_state->dpll)) {
> +               drm_err(&dev_priv->drm,
> +                       "Couldn't find PLL settings for mode!\n");
> +               return -EINVAL;
> +       }
> +
> +       ilk_compute_dpll(crtc, crtc_state, NULL);
> +
> +       if (!intel_reserve_shared_dplls(state, crtc, NULL)) {
> +               drm_dbg_kms(&dev_priv->drm,
> +                           "failed to find PLL for pipe %c\n",
> +                           pipe_name(crtc->pipe));
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +void vlv_compute_dpll(struct intel_crtc *crtc,
> +                     struct intel_crtc_state *pipe_config)
> +{
> +       pipe_config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV |
> +               DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
> +       if (crtc->pipe != PIPE_A)
> +               pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
> +
> +       /* DPLL not used with DSI, but still need the rest set up */
> +       if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
> +               pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE |
> +                       DPLL_EXT_BUFFER_ENABLE_VLV;
> +
> +       pipe_config->dpll_hw_state.dpll_md =
> +               (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
> +}
> +
> +void chv_compute_dpll(struct intel_crtc *crtc,
> +                     struct intel_crtc_state *pipe_config)
> +{
> +       pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV |
> +               DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
> +       if (crtc->pipe != PIPE_A)
> +               pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
> +
> +       /* DPLL not used with DSI, but still need the rest set up */
> +       if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
> +               pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE;
> +
> +       pipe_config->dpll_hw_state.dpll_md =
> +               (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
> +}
> +
> +static int chv_crtc_compute_clock(struct intel_crtc *crtc,
> +                                 struct intel_crtc_state *crtc_state)
> +{
> +       int refclk = 100000;
> +       const struct intel_limit *limit = &intel_limits_chv;
> +       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> +
> +       memset(&crtc_state->dpll_hw_state, 0,
> +              sizeof(crtc_state->dpll_hw_state));
> +
> +       if (!crtc_state->clock_set &&
> +           !chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> +                               refclk, NULL, &crtc_state->dpll)) {
> +               drm_err(&i915->drm, "Couldn't find PLL settings for mode!\n");
> +               return -EINVAL;
> +       }
> +
> +       chv_compute_dpll(crtc, crtc_state);
> +
> +       return 0;
> +}
> +
> +static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
> +                                 struct intel_crtc_state *crtc_state)
> +{
> +       int refclk = 100000;
> +       const struct intel_limit *limit = &intel_limits_vlv;
> +       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> +
> +       memset(&crtc_state->dpll_hw_state, 0,
> +              sizeof(crtc_state->dpll_hw_state));
> +
> +       if (!crtc_state->clock_set &&
> +           !vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> +                               refclk, NULL, &crtc_state->dpll)) {
> +               drm_err(&i915->drm,  "Couldn't find PLL settings for mode!\n");
> +               return -EINVAL;
> +       }
> +
> +       vlv_compute_dpll(crtc, crtc_state);
> +
> +       return 0;
> +}
> +
> +static int g4x_crtc_compute_clock(struct intel_crtc *crtc,
> +                                 struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       const struct intel_limit *limit;
> +       int refclk = 96000;
> +
> +       memset(&crtc_state->dpll_hw_state, 0,
> +              sizeof(crtc_state->dpll_hw_state));
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> +               if (intel_panel_use_ssc(dev_priv)) {
> +                       refclk = dev_priv->vbt.lvds_ssc_freq;
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "using SSC reference clock of %d kHz\n",
> +                                   refclk);
> +               }
> +
> +               if (intel_is_dual_link_lvds(dev_priv))
> +                       limit = &intel_limits_g4x_dual_channel_lvds;
> +               else
> +                       limit = &intel_limits_g4x_single_channel_lvds;
> +       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
> +                  intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
> +               limit = &intel_limits_g4x_hdmi;
> +       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO)) {
> +               limit = &intel_limits_g4x_sdvo;
> +       } else {
> +               /* The option is for other outputs */
> +               limit = &intel_limits_i9xx_sdvo;
> +       }
> +
> +       if (!crtc_state->clock_set &&
> +           !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> +                               refclk, NULL, &crtc_state->dpll)) {
> +               drm_err(&dev_priv->drm,
> +                       "Couldn't find PLL settings for mode!\n");
> +               return -EINVAL;
> +       }
> +
> +       i9xx_compute_dpll(crtc, crtc_state, NULL);
> +
> +       return 0;
> +}
> +
> +static int pnv_crtc_compute_clock(struct intel_crtc *crtc,
> +                                 struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       const struct intel_limit *limit;
> +       int refclk = 96000;
> +
> +       memset(&crtc_state->dpll_hw_state, 0,
> +              sizeof(crtc_state->dpll_hw_state));
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> +               if (intel_panel_use_ssc(dev_priv)) {
> +                       refclk = dev_priv->vbt.lvds_ssc_freq;
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "using SSC reference clock of %d kHz\n",
> +                                   refclk);
> +               }
> +
> +               limit = &pnv_limits_lvds;
> +       } else {
> +               limit = &pnv_limits_sdvo;
> +       }
> +
> +       if (!crtc_state->clock_set &&
> +           !pnv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> +                               refclk, NULL, &crtc_state->dpll)) {
> +               drm_err(&dev_priv->drm,
> +                       "Couldn't find PLL settings for mode!\n");
> +               return -EINVAL;
> +       }
> +
> +       i9xx_compute_dpll(crtc, crtc_state, NULL);
> +
> +       return 0;
> +}
> +
> +static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
> +                                  struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       const struct intel_limit *limit;
> +       int refclk = 96000;
> +
> +       memset(&crtc_state->dpll_hw_state, 0,
> +              sizeof(crtc_state->dpll_hw_state));
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> +               if (intel_panel_use_ssc(dev_priv)) {
> +                       refclk = dev_priv->vbt.lvds_ssc_freq;
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "using SSC reference clock of %d kHz\n",
> +                                   refclk);
> +               }
> +
> +               limit = &intel_limits_i9xx_lvds;
> +       } else {
> +               limit = &intel_limits_i9xx_sdvo;
> +       }
> +
> +       if (!crtc_state->clock_set &&
> +           !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> +                                refclk, NULL, &crtc_state->dpll)) {
> +               drm_err(&dev_priv->drm,
> +                       "Couldn't find PLL settings for mode!\n");
> +               return -EINVAL;
> +       }
> +
> +       i9xx_compute_dpll(crtc, crtc_state, NULL);
> +
> +       return 0;
> +}
> +
> +static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
> +                                  struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       const struct intel_limit *limit;
> +       int refclk = 48000;
> +
> +       memset(&crtc_state->dpll_hw_state, 0,
> +              sizeof(crtc_state->dpll_hw_state));
> +
> +       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> +               if (intel_panel_use_ssc(dev_priv)) {
> +                       refclk = dev_priv->vbt.lvds_ssc_freq;
> +                       drm_dbg_kms(&dev_priv->drm,
> +                                   "using SSC reference clock of %d kHz\n",
> +                                   refclk);
> +               }
> +
> +               limit = &intel_limits_i8xx_lvds;
> +       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO)) {
> +               limit = &intel_limits_i8xx_dvo;
> +       } else {
> +               limit = &intel_limits_i8xx_dac;
> +       }
> +
> +       if (!crtc_state->clock_set &&
> +           !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> +                                refclk, NULL, &crtc_state->dpll)) {
> +               drm_err(&dev_priv->drm,
> +                       "Couldn't find PLL settings for mode!\n");
> +               return -EINVAL;
> +       }
> +
> +       i8xx_compute_dpll(crtc, crtc_state, NULL);
> +
> +       return 0;
> +}
> +
> +void
> +intel_init_clock_hook(struct drm_i915_private *dev_priv)
> +{
> +       if (INTEL_GEN(dev_priv) >= 9 || HAS_DDI(dev_priv))
> +               dev_priv->display.crtc_compute_clock = hsw_crtc_compute_clock;
> +       else if (HAS_PCH_SPLIT(dev_priv))
> +               dev_priv->display.crtc_compute_clock = ilk_crtc_compute_clock;
> +       else if (IS_CHERRYVIEW(dev_priv))
> +               dev_priv->display.crtc_compute_clock = chv_crtc_compute_clock;
> +       else if (IS_VALLEYVIEW(dev_priv))
> +               dev_priv->display.crtc_compute_clock = vlv_crtc_compute_clock;
> +       else if (IS_G4X(dev_priv))
> +               dev_priv->display.crtc_compute_clock = g4x_crtc_compute_clock;
> +       else if (IS_PINEVIEW(dev_priv))
> +               dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock;
> +       else if (!IS_GEN(dev_priv, 2))
> +               dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
> +       else
> +               dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock;
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index c6f30e4ec51e..788b1def61ee 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -113,17 +113,6 @@ static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state);
>  static void intel_modeset_setup_hw_state(struct drm_device *dev,
>                                          struct drm_modeset_acquire_ctx *ctx);
>
> -struct intel_limit {
> -       struct {
> -               int min, max;
> -       } dot, vco, n, m, m1, m2, p, p1;
> -
> -       struct {
> -               int dot_limit;
> -               int p2_slow, p2_fast;
> -       } p2;
> -};
> -
>  /* returns HPLL frequency in kHz */
>  int vlv_get_hpll_vco(struct drm_i915_private *dev_priv)
>  {
> @@ -191,271 +180,6 @@ static u32 intel_fdi_link_freq(struct drm_i915_private *dev_priv,
>                 return dev_priv->fdi_pll_freq;
>  }
>
> -static const struct intel_limit intel_limits_i8xx_dac = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 908000, .max = 1512000 },
> -       .n = { .min = 2, .max = 16 },
> -       .m = { .min = 96, .max = 140 },
> -       .m1 = { .min = 18, .max = 26 },
> -       .m2 = { .min = 6, .max = 16 },
> -       .p = { .min = 4, .max = 128 },
> -       .p1 = { .min = 2, .max = 33 },
> -       .p2 = { .dot_limit = 165000,
> -               .p2_slow = 4, .p2_fast = 2 },
> -};
> -
> -static const struct intel_limit intel_limits_i8xx_dvo = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 908000, .max = 1512000 },
> -       .n = { .min = 2, .max = 16 },
> -       .m = { .min = 96, .max = 140 },
> -       .m1 = { .min = 18, .max = 26 },
> -       .m2 = { .min = 6, .max = 16 },
> -       .p = { .min = 4, .max = 128 },
> -       .p1 = { .min = 2, .max = 33 },
> -       .p2 = { .dot_limit = 165000,
> -               .p2_slow = 4, .p2_fast = 4 },
> -};
> -
> -static const struct intel_limit intel_limits_i8xx_lvds = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 908000, .max = 1512000 },
> -       .n = { .min = 2, .max = 16 },
> -       .m = { .min = 96, .max = 140 },
> -       .m1 = { .min = 18, .max = 26 },
> -       .m2 = { .min = 6, .max = 16 },
> -       .p = { .min = 4, .max = 128 },
> -       .p1 = { .min = 1, .max = 6 },
> -       .p2 = { .dot_limit = 165000,
> -               .p2_slow = 14, .p2_fast = 7 },
> -};
> -
> -static const struct intel_limit intel_limits_i9xx_sdvo = {
> -       .dot = { .min = 20000, .max = 400000 },
> -       .vco = { .min = 1400000, .max = 2800000 },
> -       .n = { .min = 1, .max = 6 },
> -       .m = { .min = 70, .max = 120 },
> -       .m1 = { .min = 8, .max = 18 },
> -       .m2 = { .min = 3, .max = 7 },
> -       .p = { .min = 5, .max = 80 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 200000,
> -               .p2_slow = 10, .p2_fast = 5 },
> -};
> -
> -static const struct intel_limit intel_limits_i9xx_lvds = {
> -       .dot = { .min = 20000, .max = 400000 },
> -       .vco = { .min = 1400000, .max = 2800000 },
> -       .n = { .min = 1, .max = 6 },
> -       .m = { .min = 70, .max = 120 },
> -       .m1 = { .min = 8, .max = 18 },
> -       .m2 = { .min = 3, .max = 7 },
> -       .p = { .min = 7, .max = 98 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 112000,
> -               .p2_slow = 14, .p2_fast = 7 },
> -};
> -
> -
> -static const struct intel_limit intel_limits_g4x_sdvo = {
> -       .dot = { .min = 25000, .max = 270000 },
> -       .vco = { .min = 1750000, .max = 3500000},
> -       .n = { .min = 1, .max = 4 },
> -       .m = { .min = 104, .max = 138 },
> -       .m1 = { .min = 17, .max = 23 },
> -       .m2 = { .min = 5, .max = 11 },
> -       .p = { .min = 10, .max = 30 },
> -       .p1 = { .min = 1, .max = 3},
> -       .p2 = { .dot_limit = 270000,
> -               .p2_slow = 10,
> -               .p2_fast = 10
> -       },
> -};
> -
> -static const struct intel_limit intel_limits_g4x_hdmi = {
> -       .dot = { .min = 22000, .max = 400000 },
> -       .vco = { .min = 1750000, .max = 3500000},
> -       .n = { .min = 1, .max = 4 },
> -       .m = { .min = 104, .max = 138 },
> -       .m1 = { .min = 16, .max = 23 },
> -       .m2 = { .min = 5, .max = 11 },
> -       .p = { .min = 5, .max = 80 },
> -       .p1 = { .min = 1, .max = 8},
> -       .p2 = { .dot_limit = 165000,
> -               .p2_slow = 10, .p2_fast = 5 },
> -};
> -
> -static const struct intel_limit intel_limits_g4x_single_channel_lvds = {
> -       .dot = { .min = 20000, .max = 115000 },
> -       .vco = { .min = 1750000, .max = 3500000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 104, .max = 138 },
> -       .m1 = { .min = 17, .max = 23 },
> -       .m2 = { .min = 5, .max = 11 },
> -       .p = { .min = 28, .max = 112 },
> -       .p1 = { .min = 2, .max = 8 },
> -       .p2 = { .dot_limit = 0,
> -               .p2_slow = 14, .p2_fast = 14
> -       },
> -};
> -
> -static const struct intel_limit intel_limits_g4x_dual_channel_lvds = {
> -       .dot = { .min = 80000, .max = 224000 },
> -       .vco = { .min = 1750000, .max = 3500000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 104, .max = 138 },
> -       .m1 = { .min = 17, .max = 23 },
> -       .m2 = { .min = 5, .max = 11 },
> -       .p = { .min = 14, .max = 42 },
> -       .p1 = { .min = 2, .max = 6 },
> -       .p2 = { .dot_limit = 0,
> -               .p2_slow = 7, .p2_fast = 7
> -       },
> -};
> -
> -static const struct intel_limit pnv_limits_sdvo = {
> -       .dot = { .min = 20000, .max = 400000},
> -       .vco = { .min = 1700000, .max = 3500000 },
> -       /* Pineview's Ncounter is a ring counter */
> -       .n = { .min = 3, .max = 6 },
> -       .m = { .min = 2, .max = 256 },
> -       /* Pineview only has one combined m divider, which we treat as m2. */
> -       .m1 = { .min = 0, .max = 0 },
> -       .m2 = { .min = 0, .max = 254 },
> -       .p = { .min = 5, .max = 80 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 200000,
> -               .p2_slow = 10, .p2_fast = 5 },
> -};
> -
> -static const struct intel_limit pnv_limits_lvds = {
> -       .dot = { .min = 20000, .max = 400000 },
> -       .vco = { .min = 1700000, .max = 3500000 },
> -       .n = { .min = 3, .max = 6 },
> -       .m = { .min = 2, .max = 256 },
> -       .m1 = { .min = 0, .max = 0 },
> -       .m2 = { .min = 0, .max = 254 },
> -       .p = { .min = 7, .max = 112 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 112000,
> -               .p2_slow = 14, .p2_fast = 14 },
> -};
> -
> -/* Ironlake / Sandybridge
> - *
> - * We calculate clock using (register_value + 2) for N/M1/M2, so here
> - * the range value for them is (actual_value - 2).
> - */
> -static const struct intel_limit ilk_limits_dac = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 5 },
> -       .m = { .min = 79, .max = 127 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 5, .max = 80 },
> -       .p1 = { .min = 1, .max = 8 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 10, .p2_fast = 5 },
> -};
> -
> -static const struct intel_limit ilk_limits_single_lvds = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 79, .max = 118 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 28, .max = 112 },
> -       .p1 = { .min = 2, .max = 8 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 14, .p2_fast = 14 },
> -};
> -
> -static const struct intel_limit ilk_limits_dual_lvds = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 79, .max = 127 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 14, .max = 56 },
> -       .p1 = { .min = 2, .max = 8 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 7, .p2_fast = 7 },
> -};
> -
> -/* LVDS 100mhz refclk limits. */
> -static const struct intel_limit ilk_limits_single_lvds_100m = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 2 },
> -       .m = { .min = 79, .max = 126 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 28, .max = 112 },
> -       .p1 = { .min = 2, .max = 8 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 14, .p2_fast = 14 },
> -};
> -
> -static const struct intel_limit ilk_limits_dual_lvds_100m = {
> -       .dot = { .min = 25000, .max = 350000 },
> -       .vco = { .min = 1760000, .max = 3510000 },
> -       .n = { .min = 1, .max = 3 },
> -       .m = { .min = 79, .max = 126 },
> -       .m1 = { .min = 12, .max = 22 },
> -       .m2 = { .min = 5, .max = 9 },
> -       .p = { .min = 14, .max = 42 },
> -       .p1 = { .min = 2, .max = 6 },
> -       .p2 = { .dot_limit = 225000,
> -               .p2_slow = 7, .p2_fast = 7 },
> -};
> -
> -static const struct intel_limit intel_limits_vlv = {
> -        /*
> -         * These are the data rate limits (measured in fast clocks)
> -         * since those are the strictest limits we have. The fast
> -         * clock and actual rate limits are more relaxed, so checking
> -         * them would make no difference.
> -         */
> -       .dot = { .min = 25000 * 5, .max = 270000 * 5 },
> -       .vco = { .min = 4000000, .max = 6000000 },
> -       .n = { .min = 1, .max = 7 },
> -       .m1 = { .min = 2, .max = 3 },
> -       .m2 = { .min = 11, .max = 156 },
> -       .p1 = { .min = 2, .max = 3 },
> -       .p2 = { .p2_slow = 2, .p2_fast = 20 }, /* slow=min, fast=max */
> -};
> -
> -static const struct intel_limit intel_limits_chv = {
> -       /*
> -        * These are the data rate limits (measured in fast clocks)
> -        * since those are the strictest limits we have.  The fast
> -        * clock and actual rate limits are more relaxed, so checking
> -        * them would make no difference.
> -        */
> -       .dot = { .min = 25000 * 5, .max = 540000 * 5},
> -       .vco = { .min = 4800000, .max = 6480000 },
> -       .n = { .min = 1, .max = 1 },
> -       .m1 = { .min = 2, .max = 2 },
> -       .m2 = { .min = 24 << 22, .max = 175 << 22 },
> -       .p1 = { .min = 2, .max = 4 },
> -       .p2 = { .p2_slow = 1, .p2_fast = 14 },
> -};
> -
> -static const struct intel_limit intel_limits_bxt = {
> -       /* FIXME: find real dot limits */
> -       .dot = { .min = 0, .max = INT_MAX },
> -       .vco = { .min = 4800000, .max = 6700000 },
> -       .n = { .min = 1, .max = 1 },
> -       .m1 = { .min = 2, .max = 2 },
> -       /* FIXME: find real m2 limits */
> -       .m2 = { .min = 2 << 22, .max = 255 << 22 },
> -       .p1 = { .min = 2, .max = 4 },
> -       .p2 = { .p2_slow = 1, .p2_fast = 20 },
> -};
> -
>  /* WA Display #0827: Gen9:all */
>  static void
>  skl_wa_827(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable)
> @@ -506,482 +230,6 @@ is_trans_port_sync_mode(const struct intel_crtc_state *crtc_state)
>                 is_trans_port_sync_slave(crtc_state);
>  }
>
> -/*
> - * Platform specific helpers to calculate the port PLL loopback- (clock.m),
> - * and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast
> - * (clock.dot) clock rates. This fast dot clock is fed to the port's IO logic.
> - * The helpers' return value is the rate of the clock that is fed to the
> - * display engine's pipe which can be the above fast dot clock rate or a
> - * divided-down version of it.
> - */
> -/* m1 is reserved as 0 in Pineview, n is a ring counter */
> -static int pnv_calc_dpll_params(int refclk, struct dpll *clock)
> -{
> -       clock->m = clock->m2 + 2;
> -       clock->p = clock->p1 * clock->p2;
> -       if (WARN_ON(clock->n == 0 || clock->p == 0))
> -               return 0;
> -       clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
> -       clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
> -
> -       return clock->dot;
> -}
> -
> -static u32 i9xx_dpll_compute_m(struct dpll *dpll)
> -{
> -       return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
> -}
> -
> -static int i9xx_calc_dpll_params(int refclk, struct dpll *clock)
> -{
> -       clock->m = i9xx_dpll_compute_m(clock);
> -       clock->p = clock->p1 * clock->p2;
> -       if (WARN_ON(clock->n + 2 == 0 || clock->p == 0))
> -               return 0;
> -       clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2);
> -       clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
> -
> -       return clock->dot;
> -}
> -
> -static int vlv_calc_dpll_params(int refclk, struct dpll *clock)
> -{
> -       clock->m = clock->m1 * clock->m2;
> -       clock->p = clock->p1 * clock->p2;
> -       if (WARN_ON(clock->n == 0 || clock->p == 0))
> -               return 0;
> -       clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
> -       clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
> -
> -       return clock->dot / 5;
> -}
> -
> -int chv_calc_dpll_params(int refclk, struct dpll *clock)
> -{
> -       clock->m = clock->m1 * clock->m2;
> -       clock->p = clock->p1 * clock->p2;
> -       if (WARN_ON(clock->n == 0 || clock->p == 0))
> -               return 0;
> -       clock->vco = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(refclk, clock->m),
> -                                          clock->n << 22);
> -       clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
> -
> -       return clock->dot / 5;
> -}
> -
> -/*
> - * Returns whether the given set of divisors are valid for a given refclk with
> - * the given connectors.
> - */
> -static bool intel_pll_is_valid(struct drm_i915_private *dev_priv,
> -                              const struct intel_limit *limit,
> -                              const struct dpll *clock)
> -{
> -       if (clock->n < limit->n.min || limit->n.max < clock->n)
> -               return false;
> -       if (clock->p1 < limit->p1.min || limit->p1.max < clock->p1)
> -               return false;
> -       if (clock->m2 < limit->m2.min || limit->m2.max < clock->m2)
> -               return false;
> -       if (clock->m1 < limit->m1.min || limit->m1.max < clock->m1)
> -               return false;
> -
> -       if (!IS_PINEVIEW(dev_priv) && !IS_VALLEYVIEW(dev_priv) &&
> -           !IS_CHERRYVIEW(dev_priv) && !IS_GEN9_LP(dev_priv))
> -               if (clock->m1 <= clock->m2)
> -                       return false;
> -
> -       if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv) &&
> -           !IS_GEN9_LP(dev_priv)) {
> -               if (clock->p < limit->p.min || limit->p.max < clock->p)
> -                       return false;
> -               if (clock->m < limit->m.min || limit->m.max < clock->m)
> -                       return false;
> -       }
> -
> -       if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
> -               return false;
> -       /* XXX: We may need to be checking "Dot clock" depending on the multiplier,
> -        * connector, etc., rather than just a single range.
> -        */
> -       if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
> -               return false;
> -
> -       return true;
> -}
> -
> -static int
> -i9xx_select_p2_div(const struct intel_limit *limit,
> -                  const struct intel_crtc_state *crtc_state,
> -                  int target)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> -               /*
> -                * For LVDS just rely on its current settings for dual-channel.
> -                * We haven't figured out how to reliably set up different
> -                * single/dual channel state, if we even can.
> -                */
> -               if (intel_is_dual_link_lvds(dev_priv))
> -                       return limit->p2.p2_fast;
> -               else
> -                       return limit->p2.p2_slow;
> -       } else {
> -               if (target < limit->p2.dot_limit)
> -                       return limit->p2.p2_slow;
> -               else
> -                       return limit->p2.p2_fast;
> -       }
> -}
> -
> -/*
> - * Returns a set of divisors for the desired target clock with the given
> - * refclk, or FALSE.  The returned values represent the clock equation:
> - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> - *
> - * Target and reference clocks are specified in kHz.
> - *
> - * If match_clock is provided, then best_clock P divider must match the P
> - * divider from @match_clock used for LVDS downclocking.
> - */
> -static bool
> -i9xx_find_best_dpll(const struct intel_limit *limit,
> -                   struct intel_crtc_state *crtc_state,
> -                   int target, int refclk, struct dpll *match_clock,
> -                   struct dpll *best_clock)
> -{
> -       struct drm_device *dev = crtc_state->uapi.crtc->dev;
> -       struct dpll clock;
> -       int err = target;
> -
> -       memset(best_clock, 0, sizeof(*best_clock));
> -
> -       clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
> -
> -       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
> -            clock.m1++) {
> -               for (clock.m2 = limit->m2.min;
> -                    clock.m2 <= limit->m2.max; clock.m2++) {
> -                       if (clock.m2 >= clock.m1)
> -                               break;
> -                       for (clock.n = limit->n.min;
> -                            clock.n <= limit->n.max; clock.n++) {
> -                               for (clock.p1 = limit->p1.min;
> -                                       clock.p1 <= limit->p1.max; clock.p1++) {
> -                                       int this_err;
> -
> -                                       i9xx_calc_dpll_params(refclk, &clock);
> -                                       if (!intel_pll_is_valid(to_i915(dev),
> -                                                               limit,
> -                                                               &clock))
> -                                               continue;
> -                                       if (match_clock &&
> -                                           clock.p != match_clock->p)
> -                                               continue;
> -
> -                                       this_err = abs(clock.dot - target);
> -                                       if (this_err < err) {
> -                                               *best_clock = clock;
> -                                               err = this_err;
> -                                       }
> -                               }
> -                       }
> -               }
> -       }
> -
> -       return (err != target);
> -}
> -
> -/*
> - * Returns a set of divisors for the desired target clock with the given
> - * refclk, or FALSE.  The returned values represent the clock equation:
> - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> - *
> - * Target and reference clocks are specified in kHz.
> - *
> - * If match_clock is provided, then best_clock P divider must match the P
> - * divider from @match_clock used for LVDS downclocking.
> - */
> -static bool
> -pnv_find_best_dpll(const struct intel_limit *limit,
> -                  struct intel_crtc_state *crtc_state,
> -                  int target, int refclk, struct dpll *match_clock,
> -                  struct dpll *best_clock)
> -{
> -       struct drm_device *dev = crtc_state->uapi.crtc->dev;
> -       struct dpll clock;
> -       int err = target;
> -
> -       memset(best_clock, 0, sizeof(*best_clock));
> -
> -       clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
> -
> -       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
> -            clock.m1++) {
> -               for (clock.m2 = limit->m2.min;
> -                    clock.m2 <= limit->m2.max; clock.m2++) {
> -                       for (clock.n = limit->n.min;
> -                            clock.n <= limit->n.max; clock.n++) {
> -                               for (clock.p1 = limit->p1.min;
> -                                       clock.p1 <= limit->p1.max; clock.p1++) {
> -                                       int this_err;
> -
> -                                       pnv_calc_dpll_params(refclk, &clock);
> -                                       if (!intel_pll_is_valid(to_i915(dev),
> -                                                               limit,
> -                                                               &clock))
> -                                               continue;
> -                                       if (match_clock &&
> -                                           clock.p != match_clock->p)
> -                                               continue;
> -
> -                                       this_err = abs(clock.dot - target);
> -                                       if (this_err < err) {
> -                                               *best_clock = clock;
> -                                               err = this_err;
> -                                       }
> -                               }
> -                       }
> -               }
> -       }
> -
> -       return (err != target);
> -}
> -
> -/*
> - * Returns a set of divisors for the desired target clock with the given
> - * refclk, or FALSE.  The returned values represent the clock equation:
> - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> - *
> - * Target and reference clocks are specified in kHz.
> - *
> - * If match_clock is provided, then best_clock P divider must match the P
> - * divider from @match_clock used for LVDS downclocking.
> - */
> -static bool
> -g4x_find_best_dpll(const struct intel_limit *limit,
> -                  struct intel_crtc_state *crtc_state,
> -                  int target, int refclk, struct dpll *match_clock,
> -                  struct dpll *best_clock)
> -{
> -       struct drm_device *dev = crtc_state->uapi.crtc->dev;
> -       struct dpll clock;
> -       int max_n;
> -       bool found = false;
> -       /* approximately equals target * 0.00585 */
> -       int err_most = (target >> 8) + (target >> 9);
> -
> -       memset(best_clock, 0, sizeof(*best_clock));
> -
> -       clock.p2 = i9xx_select_p2_div(limit, crtc_state, target);
> -
> -       max_n = limit->n.max;
> -       /* based on hardware requirement, prefer smaller n to precision */
> -       for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
> -               /* based on hardware requirement, prefere larger m1,m2 */
> -               for (clock.m1 = limit->m1.max;
> -                    clock.m1 >= limit->m1.min; clock.m1--) {
> -                       for (clock.m2 = limit->m2.max;
> -                            clock.m2 >= limit->m2.min; clock.m2--) {
> -                               for (clock.p1 = limit->p1.max;
> -                                    clock.p1 >= limit->p1.min; clock.p1--) {
> -                                       int this_err;
> -
> -                                       i9xx_calc_dpll_params(refclk, &clock);
> -                                       if (!intel_pll_is_valid(to_i915(dev),
> -                                                               limit,
> -                                                               &clock))
> -                                               continue;
> -
> -                                       this_err = abs(clock.dot - target);
> -                                       if (this_err < err_most) {
> -                                               *best_clock = clock;
> -                                               err_most = this_err;
> -                                               max_n = clock.n;
> -                                               found = true;
> -                                       }
> -                               }
> -                       }
> -               }
> -       }
> -       return found;
> -}
> -
> -/*
> - * Check if the calculated PLL configuration is more optimal compared to the
> - * best configuration and error found so far. Return the calculated error.
> - */
> -static bool vlv_PLL_is_optimal(struct drm_device *dev, int target_freq,
> -                              const struct dpll *calculated_clock,
> -                              const struct dpll *best_clock,
> -                              unsigned int best_error_ppm,
> -                              unsigned int *error_ppm)
> -{
> -       /*
> -        * For CHV ignore the error and consider only the P value.
> -        * Prefer a bigger P value based on HW requirements.
> -        */
> -       if (IS_CHERRYVIEW(to_i915(dev))) {
> -               *error_ppm = 0;
> -
> -               return calculated_clock->p > best_clock->p;
> -       }
> -
> -       if (drm_WARN_ON_ONCE(dev, !target_freq))
> -               return false;
> -
> -       *error_ppm = div_u64(1000000ULL *
> -                               abs(target_freq - calculated_clock->dot),
> -                            target_freq);
> -       /*
> -        * Prefer a better P value over a better (smaller) error if the error
> -        * is small. Ensure this preference for future configurations too by
> -        * setting the error to 0.
> -        */
> -       if (*error_ppm < 100 && calculated_clock->p > best_clock->p) {
> -               *error_ppm = 0;
> -
> -               return true;
> -       }
> -
> -       return *error_ppm + 10 < best_error_ppm;
> -}
> -
> -/*
> - * Returns a set of divisors for the desired target clock with the given
> - * refclk, or FALSE.  The returned values represent the clock equation:
> - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> - */
> -static bool
> -vlv_find_best_dpll(const struct intel_limit *limit,
> -                  struct intel_crtc_state *crtc_state,
> -                  int target, int refclk, struct dpll *match_clock,
> -                  struct dpll *best_clock)
> -{
> -       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -       struct drm_device *dev = crtc->base.dev;
> -       struct dpll clock;
> -       unsigned int bestppm = 1000000;
> -       /* min update 19.2 MHz */
> -       int max_n = min(limit->n.max, refclk / 19200);
> -       bool found = false;
> -
> -       target *= 5; /* fast clock */
> -
> -       memset(best_clock, 0, sizeof(*best_clock));
> -
> -       /* based on hardware requirement, prefer smaller n to precision */
> -       for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
> -               for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
> -                       for (clock.p2 = limit->p2.p2_fast; clock.p2 >= limit->p2.p2_slow;
> -                            clock.p2 -= clock.p2 > 10 ? 2 : 1) {
> -                               clock.p = clock.p1 * clock.p2;
> -                               /* based on hardware requirement, prefer bigger m1,m2 values */
> -                               for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
> -                                       unsigned int ppm;
> -
> -                                       clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n,
> -                                                                    refclk * clock.m1);
> -
> -                                       vlv_calc_dpll_params(refclk, &clock);
> -
> -                                       if (!intel_pll_is_valid(to_i915(dev),
> -                                                               limit,
> -                                                               &clock))
> -                                               continue;
> -
> -                                       if (!vlv_PLL_is_optimal(dev, target,
> -                                                               &clock,
> -                                                               best_clock,
> -                                                               bestppm, &ppm))
> -                                               continue;
> -
> -                                       *best_clock = clock;
> -                                       bestppm = ppm;
> -                                       found = true;
> -                               }
> -                       }
> -               }
> -       }
> -
> -       return found;
> -}
> -
> -/*
> - * Returns a set of divisors for the desired target clock with the given
> - * refclk, or FALSE.  The returned values represent the clock equation:
> - * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
> - */
> -static bool
> -chv_find_best_dpll(const struct intel_limit *limit,
> -                  struct intel_crtc_state *crtc_state,
> -                  int target, int refclk, struct dpll *match_clock,
> -                  struct dpll *best_clock)
> -{
> -       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -       struct drm_device *dev = crtc->base.dev;
> -       unsigned int best_error_ppm;
> -       struct dpll clock;
> -       u64 m2;
> -       int found = false;
> -
> -       memset(best_clock, 0, sizeof(*best_clock));
> -       best_error_ppm = 1000000;
> -
> -       /*
> -        * Based on hardware doc, the n always set to 1, and m1 always
> -        * set to 2.  If requires to support 200Mhz refclk, we need to
> -        * revisit this because n may not 1 anymore.
> -        */
> -       clock.n = 1, clock.m1 = 2;
> -       target *= 5;    /* fast clock */
> -
> -       for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
> -               for (clock.p2 = limit->p2.p2_fast;
> -                               clock.p2 >= limit->p2.p2_slow;
> -                               clock.p2 -= clock.p2 > 10 ? 2 : 1) {
> -                       unsigned int error_ppm;
> -
> -                       clock.p = clock.p1 * clock.p2;
> -
> -                       m2 = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(target, clock.p * clock.n) << 22,
> -                                                  refclk * clock.m1);
> -
> -                       if (m2 > INT_MAX/clock.m1)
> -                               continue;
> -
> -                       clock.m2 = m2;
> -
> -                       chv_calc_dpll_params(refclk, &clock);
> -
> -                       if (!intel_pll_is_valid(to_i915(dev), limit, &clock))
> -                               continue;
> -
> -                       if (!vlv_PLL_is_optimal(dev, target, &clock, best_clock,
> -                                               best_error_ppm, &error_ppm))
> -                               continue;
> -
> -                       *best_clock = clock;
> -                       best_error_ppm = error_ppm;
> -                       found = true;
> -               }
> -       }
> -
> -       return found;
> -}
> -
> -bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state,
> -                       struct dpll *best_clock)
> -{
> -       int refclk = 100000;
> -       const struct intel_limit *limit = &intel_limits_bxt;
> -
> -       return chv_find_best_dpll(limit, crtc_state,
> -                                 crtc_state->port_clock, refclk,
> -                                 NULL, best_clock);
> -}
> -
>  static bool pipe_scanline_is_moving(struct drm_i915_private *dev_priv,
>                                     enum pipe pipe)
>  {
> @@ -5284,7 +4532,7 @@ static void ivb_update_fdi_bc_bifurcation(const struct intel_crtc_state *crtc_st
>   * Finds the encoder associated with the given CRTC. This can only be
>   * used when we know that the CRTC isn't feeding multiple encoders!
>   */
> -static struct intel_encoder *
> +struct intel_encoder *
>  intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
>                            const struct intel_crtc_state *crtc_state)
>  {
> @@ -7960,43 +7208,6 @@ static bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
>                 && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
>  }
>
> -static u32 pnv_dpll_compute_fp(struct dpll *dpll)
> -{
> -       return (1 << dpll->n) << 16 | dpll->m2;
> -}
> -
> -static u32 i9xx_dpll_compute_fp(struct dpll *dpll)
> -{
> -       return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
> -}
> -
> -static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
> -                                    struct intel_crtc_state *crtc_state,
> -                                    struct dpll *reduced_clock)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       u32 fp, fp2 = 0;
> -
> -       if (IS_PINEVIEW(dev_priv)) {
> -               fp = pnv_dpll_compute_fp(&crtc_state->dpll);
> -               if (reduced_clock)
> -                       fp2 = pnv_dpll_compute_fp(reduced_clock);
> -       } else {
> -               fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
> -               if (reduced_clock)
> -                       fp2 = i9xx_dpll_compute_fp(reduced_clock);
> -       }
> -
> -       crtc_state->dpll_hw_state.fp0 = fp;
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
> -           reduced_clock) {
> -               crtc_state->dpll_hw_state.fp1 = fp2;
> -       } else {
> -               crtc_state->dpll_hw_state.fp1 = fp;
> -       }
> -}
> -
>  static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe
>                 pipe)
>  {
> @@ -8121,39 +7332,6 @@ void intel_dp_set_m_n(const struct intel_crtc_state *crtc_state, enum link_m_n_s
>                 intel_cpu_transcoder_set_m_n(crtc_state, dp_m_n, dp_m2_n2);
>  }
>
> -static void vlv_compute_dpll(struct intel_crtc *crtc,
> -                            struct intel_crtc_state *pipe_config)
> -{
> -       pipe_config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV |
> -               DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
> -       if (crtc->pipe != PIPE_A)
> -               pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
> -
> -       /* DPLL not used with DSI, but still need the rest set up */
> -       if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
> -               pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE |
> -                       DPLL_EXT_BUFFER_ENABLE_VLV;
> -
> -       pipe_config->dpll_hw_state.dpll_md =
> -               (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
> -}
> -
> -static void chv_compute_dpll(struct intel_crtc *crtc,
> -                            struct intel_crtc_state *pipe_config)
> -{
> -       pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV |
> -               DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
> -       if (crtc->pipe != PIPE_A)
> -               pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
> -
> -       /* DPLL not used with DSI, but still need the rest set up */
> -       if (!intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DSI))
> -               pipe_config->dpll_hw_state.dpll |= DPLL_VCO_ENABLE;
> -
> -       pipe_config->dpll_hw_state.dpll_md =
> -               (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
> -}
> -
>  static void vlv_prepare_pll(struct intel_crtc *crtc,
>                             const struct intel_crtc_state *pipe_config)
>  {
> @@ -8413,128 +7591,7 @@ void vlv_force_pll_off(struct drm_i915_private *dev_priv, enum pipe pipe)
>                 vlv_disable_pll(dev_priv, pipe);
>  }
>
> -static void i9xx_compute_dpll(struct intel_crtc *crtc,
> -                             struct intel_crtc_state *crtc_state,
> -                             struct dpll *reduced_clock)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       u32 dpll;
> -       struct dpll *clock = &crtc_state->dpll;
> -
> -       i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
> -
> -       dpll = DPLL_VGA_MODE_DIS;
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
> -               dpll |= DPLLB_MODE_LVDS;
> -       else
> -               dpll |= DPLLB_MODE_DAC_SERIAL;
> -
> -       if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
> -           IS_G33(dev_priv) || IS_PINEVIEW(dev_priv)) {
> -               dpll |= (crtc_state->pixel_multiplier - 1)
> -                       << SDVO_MULTIPLIER_SHIFT_HIRES;
> -       }
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
> -           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
> -               dpll |= DPLL_SDVO_HIGH_SPEED;
> -
> -       if (intel_crtc_has_dp_encoder(crtc_state))
> -               dpll |= DPLL_SDVO_HIGH_SPEED;
> -
> -       /* compute bitmask from p1 value */
> -       if (IS_PINEVIEW(dev_priv))
> -               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
> -       else {
> -               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
> -               if (IS_G4X(dev_priv) && reduced_clock)
> -                       dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
> -       }
> -       switch (clock->p2) {
> -       case 5:
> -               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
> -               break;
> -       case 7:
> -               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
> -               break;
> -       case 10:
> -               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
> -               break;
> -       case 14:
> -               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
> -               break;
> -       }
> -       if (INTEL_GEN(dev_priv) >= 4)
> -               dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
> -
> -       if (crtc_state->sdvo_tv_clock)
> -               dpll |= PLL_REF_INPUT_TVCLKINBC;
> -       else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
> -                intel_panel_use_ssc(dev_priv))
> -               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
> -       else
> -               dpll |= PLL_REF_INPUT_DREFCLK;
> -
> -       dpll |= DPLL_VCO_ENABLE;
> -       crtc_state->dpll_hw_state.dpll = dpll;
> -
> -       if (INTEL_GEN(dev_priv) >= 4) {
> -               u32 dpll_md = (crtc_state->pixel_multiplier - 1)
> -                       << DPLL_MD_UDI_MULTIPLIER_SHIFT;
> -               crtc_state->dpll_hw_state.dpll_md = dpll_md;
> -       }
> -}
> -
> -static void i8xx_compute_dpll(struct intel_crtc *crtc,
> -                             struct intel_crtc_state *crtc_state,
> -                             struct dpll *reduced_clock)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       u32 dpll;
> -       struct dpll *clock = &crtc_state->dpll;
> -
> -       i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
> -
> -       dpll = DPLL_VGA_MODE_DIS;
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> -               dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
> -       } else {
> -               if (clock->p1 == 2)
> -                       dpll |= PLL_P1_DIVIDE_BY_TWO;
> -               else
> -                       dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
> -               if (clock->p2 == 4)
> -                       dpll |= PLL_P2_DIVIDE_BY_4;
> -       }
> -
> -       /*
> -        * Bspec:
> -        * "[Almador Errata}: For the correct operation of the muxed DVO pins
> -        *  (GDEVSELB/I2Cdata, GIRDBY/I2CClk) and (GFRAMEB/DVI_Data,
> -        *  GTRDYB/DVI_Clk): Bit 31 (DPLL VCO Enable) and Bit 30 (2X Clock
> -        *  Enable) must be set to “1” in both the DPLL A Control Register
> -        *  (06014h-06017h) and DPLL B Control Register (06018h-0601Bh)."
> -        *
> -        * For simplicity We simply keep both bits always enabled in
> -        * both DPLLS. The spec says we should disable the DVO 2X clock
> -        * when not needed, but this seems to work fine in practice.
> -        */
> -       if (IS_I830(dev_priv) ||
> -           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO))
> -               dpll |= DPLL_DVO_2X_MODE;
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
> -           intel_panel_use_ssc(dev_priv))
> -               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
> -       else
> -               dpll |= PLL_REF_INPUT_DREFCLK;
>
> -       dpll |= DPLL_VCO_ENABLE;
> -       crtc_state->dpll_hw_state.dpll = dpll;
> -}
>
>  static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state)
>  {
> @@ -8740,207 +7797,6 @@ static void i9xx_set_pipeconf(const struct intel_crtc_state *crtc_state)
>         intel_de_posting_read(dev_priv, PIPECONF(crtc->pipe));
>  }
>
> -static int i8xx_crtc_compute_clock(struct intel_crtc *crtc,
> -                                  struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       const struct intel_limit *limit;
> -       int refclk = 48000;
> -
> -       memset(&crtc_state->dpll_hw_state, 0,
> -              sizeof(crtc_state->dpll_hw_state));
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> -               if (intel_panel_use_ssc(dev_priv)) {
> -                       refclk = dev_priv->vbt.lvds_ssc_freq;
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "using SSC reference clock of %d kHz\n",
> -                                   refclk);
> -               }
> -
> -               limit = &intel_limits_i8xx_lvds;
> -       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DVO)) {
> -               limit = &intel_limits_i8xx_dvo;
> -       } else {
> -               limit = &intel_limits_i8xx_dac;
> -       }
> -
> -       if (!crtc_state->clock_set &&
> -           !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> -                                refclk, NULL, &crtc_state->dpll)) {
> -               drm_err(&dev_priv->drm,
> -                       "Couldn't find PLL settings for mode!\n");
> -               return -EINVAL;
> -       }
> -
> -       i8xx_compute_dpll(crtc, crtc_state, NULL);
> -
> -       return 0;
> -}
> -
> -static int g4x_crtc_compute_clock(struct intel_crtc *crtc,
> -                                 struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       const struct intel_limit *limit;
> -       int refclk = 96000;
> -
> -       memset(&crtc_state->dpll_hw_state, 0,
> -              sizeof(crtc_state->dpll_hw_state));
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> -               if (intel_panel_use_ssc(dev_priv)) {
> -                       refclk = dev_priv->vbt.lvds_ssc_freq;
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "using SSC reference clock of %d kHz\n",
> -                                   refclk);
> -               }
> -
> -               if (intel_is_dual_link_lvds(dev_priv))
> -                       limit = &intel_limits_g4x_dual_channel_lvds;
> -               else
> -                       limit = &intel_limits_g4x_single_channel_lvds;
> -       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI) ||
> -                  intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG)) {
> -               limit = &intel_limits_g4x_hdmi;
> -       } else if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO)) {
> -               limit = &intel_limits_g4x_sdvo;
> -       } else {
> -               /* The option is for other outputs */
> -               limit = &intel_limits_i9xx_sdvo;
> -       }
> -
> -       if (!crtc_state->clock_set &&
> -           !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> -                               refclk, NULL, &crtc_state->dpll)) {
> -               drm_err(&dev_priv->drm,
> -                       "Couldn't find PLL settings for mode!\n");
> -               return -EINVAL;
> -       }
> -
> -       i9xx_compute_dpll(crtc, crtc_state, NULL);
> -
> -       return 0;
> -}
> -
> -static int pnv_crtc_compute_clock(struct intel_crtc *crtc,
> -                                 struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       const struct intel_limit *limit;
> -       int refclk = 96000;
> -
> -       memset(&crtc_state->dpll_hw_state, 0,
> -              sizeof(crtc_state->dpll_hw_state));
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> -               if (intel_panel_use_ssc(dev_priv)) {
> -                       refclk = dev_priv->vbt.lvds_ssc_freq;
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "using SSC reference clock of %d kHz\n",
> -                                   refclk);
> -               }
> -
> -               limit = &pnv_limits_lvds;
> -       } else {
> -               limit = &pnv_limits_sdvo;
> -       }
> -
> -       if (!crtc_state->clock_set &&
> -           !pnv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> -                               refclk, NULL, &crtc_state->dpll)) {
> -               drm_err(&dev_priv->drm,
> -                       "Couldn't find PLL settings for mode!\n");
> -               return -EINVAL;
> -       }
> -
> -       i9xx_compute_dpll(crtc, crtc_state, NULL);
> -
> -       return 0;
> -}
> -
> -static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
> -                                  struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_i915_private *dev_priv = to_i915(dev);
> -       const struct intel_limit *limit;
> -       int refclk = 96000;
> -
> -       memset(&crtc_state->dpll_hw_state, 0,
> -              sizeof(crtc_state->dpll_hw_state));
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> -               if (intel_panel_use_ssc(dev_priv)) {
> -                       refclk = dev_priv->vbt.lvds_ssc_freq;
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "using SSC reference clock of %d kHz\n",
> -                                   refclk);
> -               }
> -
> -               limit = &intel_limits_i9xx_lvds;
> -       } else {
> -               limit = &intel_limits_i9xx_sdvo;
> -       }
> -
> -       if (!crtc_state->clock_set &&
> -           !i9xx_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> -                                refclk, NULL, &crtc_state->dpll)) {
> -               drm_err(&dev_priv->drm,
> -                       "Couldn't find PLL settings for mode!\n");
> -               return -EINVAL;
> -       }
> -
> -       i9xx_compute_dpll(crtc, crtc_state, NULL);
> -
> -       return 0;
> -}
> -
> -static int chv_crtc_compute_clock(struct intel_crtc *crtc,
> -                                 struct intel_crtc_state *crtc_state)
> -{
> -       int refclk = 100000;
> -       const struct intel_limit *limit = &intel_limits_chv;
> -       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> -
> -       memset(&crtc_state->dpll_hw_state, 0,
> -              sizeof(crtc_state->dpll_hw_state));
> -
> -       if (!crtc_state->clock_set &&
> -           !chv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> -                               refclk, NULL, &crtc_state->dpll)) {
> -               drm_err(&i915->drm, "Couldn't find PLL settings for mode!\n");
> -               return -EINVAL;
> -       }
> -
> -       chv_compute_dpll(crtc, crtc_state);
> -
> -       return 0;
> -}
> -
> -static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
> -                                 struct intel_crtc_state *crtc_state)
> -{
> -       int refclk = 100000;
> -       const struct intel_limit *limit = &intel_limits_vlv;
> -       struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
> -
> -       memset(&crtc_state->dpll_hw_state, 0,
> -              sizeof(crtc_state->dpll_hw_state));
> -
> -       if (!crtc_state->clock_set &&
> -           !vlv_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> -                               refclk, NULL, &crtc_state->dpll)) {
> -               drm_err(&i915->drm,  "Couldn't find PLL settings for mode!\n");
> -               return -EINVAL;
> -       }
> -
> -       vlv_compute_dpll(crtc, crtc_state);
> -
> -       return 0;
> -}
>
>  static bool i9xx_has_pfit(struct drm_i915_private *dev_priv)
>  {
> @@ -9951,172 +8807,6 @@ int ilk_get_lanes_required(int target_clock, int link_bw, int bpp)
>         return DIV_ROUND_UP(bps, link_bw * 8);
>  }
>
> -static bool ilk_needs_fb_cb_tune(struct dpll *dpll, int factor)
> -{
> -       return i9xx_dpll_compute_m(dpll) < factor * dpll->n;
> -}
> -
> -static void ilk_compute_dpll(struct intel_crtc *crtc,
> -                            struct intel_crtc_state *crtc_state,
> -                            struct dpll *reduced_clock)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       u32 dpll, fp, fp2;
> -       int factor;
> -
> -       /* Enable autotuning of the PLL clock (if permissible) */
> -       factor = 21;
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> -               if ((intel_panel_use_ssc(dev_priv) &&
> -                    dev_priv->vbt.lvds_ssc_freq == 100000) ||
> -                   (HAS_PCH_IBX(dev_priv) &&
> -                    intel_is_dual_link_lvds(dev_priv)))
> -                       factor = 25;
> -       } else if (crtc_state->sdvo_tv_clock) {
> -               factor = 20;
> -       }
> -
> -       fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
> -
> -       if (ilk_needs_fb_cb_tune(&crtc_state->dpll, factor))
> -               fp |= FP_CB_TUNE;
> -
> -       if (reduced_clock) {
> -               fp2 = i9xx_dpll_compute_fp(reduced_clock);
> -
> -               if (reduced_clock->m < factor * reduced_clock->n)
> -                       fp2 |= FP_CB_TUNE;
> -       } else {
> -               fp2 = fp;
> -       }
> -
> -       dpll = 0;
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS))
> -               dpll |= DPLLB_MODE_LVDS;
> -       else
> -               dpll |= DPLLB_MODE_DAC_SERIAL;
> -
> -       dpll |= (crtc_state->pixel_multiplier - 1)
> -               << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_SDVO) ||
> -           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
> -               dpll |= DPLL_SDVO_HIGH_SPEED;
> -
> -       if (intel_crtc_has_dp_encoder(crtc_state))
> -               dpll |= DPLL_SDVO_HIGH_SPEED;
> -
> -       /*
> -        * The high speed IO clock is only really required for
> -        * SDVO/HDMI/DP, but we also enable it for CRT to make it
> -        * possible to share the DPLL between CRT and HDMI. Enabling
> -        * the clock needlessly does no real harm, except use up a
> -        * bit of power potentially.
> -        *
> -        * We'll limit this to IVB with 3 pipes, since it has only two
> -        * DPLLs and so DPLL sharing is the only way to get three pipes
> -        * driving PCH ports at the same time. On SNB we could do this,
> -        * and potentially avoid enabling the second DPLL, but it's not
> -        * clear if it''s a win or loss power wise. No point in doing
> -        * this on ILK at all since it has a fixed DPLL<->pipe mapping.
> -        */
> -       if (INTEL_NUM_PIPES(dev_priv) == 3 &&
> -           intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG))
> -               dpll |= DPLL_SDVO_HIGH_SPEED;
> -
> -       /* compute bitmask from p1 value */
> -       dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
> -       /* also FPA1 */
> -       dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
> -
> -       switch (crtc_state->dpll.p2) {
> -       case 5:
> -               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
> -               break;
> -       case 7:
> -               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
> -               break;
> -       case 10:
> -               dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
> -               break;
> -       case 14:
> -               dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
> -               break;
> -       }
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS) &&
> -           intel_panel_use_ssc(dev_priv))
> -               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
> -       else
> -               dpll |= PLL_REF_INPUT_DREFCLK;
> -
> -       dpll |= DPLL_VCO_ENABLE;
> -
> -       crtc_state->dpll_hw_state.dpll = dpll;
> -       crtc_state->dpll_hw_state.fp0 = fp;
> -       crtc_state->dpll_hw_state.fp1 = fp2;
> -}
> -
> -static int ilk_crtc_compute_clock(struct intel_crtc *crtc,
> -                                 struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       struct intel_atomic_state *state =
> -               to_intel_atomic_state(crtc_state->uapi.state);
> -       const struct intel_limit *limit;
> -       int refclk = 120000;
> -
> -       memset(&crtc_state->dpll_hw_state, 0,
> -              sizeof(crtc_state->dpll_hw_state));
> -
> -       /* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
> -       if (!crtc_state->has_pch_encoder)
> -               return 0;
> -
> -       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_LVDS)) {
> -               if (intel_panel_use_ssc(dev_priv)) {
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "using SSC reference clock of %d kHz\n",
> -                                   dev_priv->vbt.lvds_ssc_freq);
> -                       refclk = dev_priv->vbt.lvds_ssc_freq;
> -               }
> -
> -               if (intel_is_dual_link_lvds(dev_priv)) {
> -                       if (refclk == 100000)
> -                               limit = &ilk_limits_dual_lvds_100m;
> -                       else
> -                               limit = &ilk_limits_dual_lvds;
> -               } else {
> -                       if (refclk == 100000)
> -                               limit = &ilk_limits_single_lvds_100m;
> -                       else
> -                               limit = &ilk_limits_single_lvds;
> -               }
> -       } else {
> -               limit = &ilk_limits_dac;
> -       }
> -
> -       if (!crtc_state->clock_set &&
> -           !g4x_find_best_dpll(limit, crtc_state, crtc_state->port_clock,
> -                               refclk, NULL, &crtc_state->dpll)) {
> -               drm_err(&dev_priv->drm,
> -                       "Couldn't find PLL settings for mode!\n");
> -               return -EINVAL;
> -       }
> -
> -       ilk_compute_dpll(crtc, crtc_state, NULL);
> -
> -       if (!intel_reserve_shared_dplls(state, crtc, NULL)) {
> -               drm_dbg_kms(&dev_priv->drm,
> -                           "failed to find PLL for pipe %c\n",
> -                           pipe_name(crtc->pipe));
> -               return -EINVAL;
> -       }
> -
> -       return 0;
> -}
> -
>  static void intel_pch_transcoder_get_m_n(struct intel_crtc *crtc,
>                                          struct intel_link_m_n *m_n)
>  {
> @@ -10529,29 +9219,6 @@ static bool ilk_get_pipe_config(struct intel_crtc *crtc,
>         return ret;
>  }
>
> -static int hsw_crtc_compute_clock(struct intel_crtc *crtc,
> -                                 struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       struct intel_atomic_state *state =
> -               to_intel_atomic_state(crtc_state->uapi.state);
> -
> -       if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) ||
> -           INTEL_GEN(dev_priv) >= 11) {
> -               struct intel_encoder *encoder =
> -                       intel_get_crtc_new_encoder(state, crtc_state);
> -
> -               if (!intel_reserve_shared_dplls(state, crtc, encoder)) {
> -                       drm_dbg_kms(&dev_priv->drm,
> -                                   "failed to find PLL for pipe %c\n",
> -                                   pipe_name(crtc->pipe));
> -                       return -EINVAL;
> -               }
> -       }
> -
> -       return 0;
> -}
> -
>  static void dg1_get_ddi_pll(struct drm_i915_private *dev_priv, enum port port,
>                             struct intel_crtc_state *pipe_config)
>  {
> @@ -16486,69 +15153,27 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
>  {
>         intel_init_cdclk_hooks(dev_priv);
>
> +       intel_init_clock_hook(dev_priv);
> +
>         if (INTEL_GEN(dev_priv) >= 9) {
>                 dev_priv->display.get_pipe_config = hsw_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       skl_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock = hsw_crtc_compute_clock;
>                 dev_priv->display.crtc_enable = hsw_crtc_enable;
>                 dev_priv->display.crtc_disable = hsw_crtc_disable;
>         } else if (HAS_DDI(dev_priv)) {
>                 dev_priv->display.get_pipe_config = hsw_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       i9xx_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock =
> -                       hsw_crtc_compute_clock;
>                 dev_priv->display.crtc_enable = hsw_crtc_enable;
>                 dev_priv->display.crtc_disable = hsw_crtc_disable;
>         } else if (HAS_PCH_SPLIT(dev_priv)) {
>                 dev_priv->display.get_pipe_config = ilk_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       i9xx_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock =
> -                       ilk_crtc_compute_clock;
>                 dev_priv->display.crtc_enable = ilk_crtc_enable;
>                 dev_priv->display.crtc_disable = ilk_crtc_disable;
> -       } else if (IS_CHERRYVIEW(dev_priv)) {
> -               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       i9xx_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock = chv_crtc_compute_clock;
> -               dev_priv->display.crtc_enable = valleyview_crtc_enable;
> -               dev_priv->display.crtc_disable = i9xx_crtc_disable;
> -       } else if (IS_VALLEYVIEW(dev_priv)) {
> +       } else if (IS_CHERRYVIEW(dev_priv) ||
> +                  IS_VALLEYVIEW(dev_priv)) {
>                 dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       i9xx_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock = vlv_crtc_compute_clock;
>                 dev_priv->display.crtc_enable = valleyview_crtc_enable;
>                 dev_priv->display.crtc_disable = i9xx_crtc_disable;
> -       } else if (IS_G4X(dev_priv)) {
> -               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       i9xx_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock = g4x_crtc_compute_clock;
> -               dev_priv->display.crtc_enable = i9xx_crtc_enable;
> -               dev_priv->display.crtc_disable = i9xx_crtc_disable;
> -       } else if (IS_PINEVIEW(dev_priv)) {
> -               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       i9xx_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock = pnv_crtc_compute_clock;
> -               dev_priv->display.crtc_enable = i9xx_crtc_enable;
> -               dev_priv->display.crtc_disable = i9xx_crtc_disable;
> -       } else if (!IS_GEN(dev_priv, 2)) {
> -               dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       i9xx_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
> -               dev_priv->display.crtc_enable = i9xx_crtc_enable;
> -               dev_priv->display.crtc_disable = i9xx_crtc_disable;
>         } else {
>                 dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
> -               dev_priv->display.get_initial_plane_config =
> -                       i9xx_get_initial_plane_config;
> -               dev_priv->display.crtc_compute_clock = i8xx_crtc_compute_clock;
>                 dev_priv->display.crtc_enable = i9xx_crtc_enable;
>                 dev_priv->display.crtc_disable = i9xx_crtc_disable;
>         }
> @@ -16562,10 +15187,13 @@ void intel_init_display_hooks(struct drm_i915_private *dev_priv)
>                 dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
>         }
>
> -       if (INTEL_GEN(dev_priv) >= 9)
> +       if (INTEL_GEN(dev_priv) >= 9) {
>                 dev_priv->display.commit_modeset_enables = skl_commit_modeset_enables;
> -       else
> +               dev_priv->display.get_initial_plane_config = skl_get_initial_plane_config;
> +       } else {
>                 dev_priv->display.commit_modeset_enables = intel_commit_modeset_enables;
> +               dev_priv->display.get_initial_plane_config = i9xx_get_initial_plane_config;
> +       }
>
>  }
>
> diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
> index 0eba91d18e96..f1e36cca86c1 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.h
> +++ b/drivers/gpu/drm/i915/display/intel_display.h
> @@ -653,7 +653,9 @@ u32 intel_plane_compute_aligned_offset(int *x, int *y,
>                                        int color_plane);
>  int intel_plane_pin_fb(struct intel_plane_state *plane_state);
>  void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state);
> -
> +struct intel_encoder *
> +intel_get_crtc_new_encoder(const struct intel_atomic_state *state,
> +                          const struct intel_crtc_state *crtc_state);
>  /* cursor */
>  struct intel_plane *
>  intel_cursor_plane_create(struct drm_i915_private *dev_priv,
> @@ -665,6 +667,15 @@ int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe);
>  struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc);
>  void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
>                             struct intel_crtc *crtc);
> +/* clock */
> +void intel_init_clock_hook(struct drm_i915_private *dev_priv);
> +int vlv_calc_dpll_params(int refclk, struct dpll *clock);
> +int pnv_calc_dpll_params(int refclk, struct dpll *clock);
> +int i9xx_calc_dpll_params(int refclk, struct dpll *clock);
> +void vlv_compute_dpll(struct intel_crtc *crtc,
> +                     struct intel_crtc_state *pipe_config);
> +void chv_compute_dpll(struct intel_crtc *crtc,
> +                     struct intel_crtc_state *pipe_config);
>
>  /* modesetting */
>  void intel_modeset_init_hw(struct drm_i915_private *i915);
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index 5bc5bfbc4551..823083b231bc 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1799,4 +1799,9 @@ static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
>         return i915_ggtt_offset(state->vma);
>  }
>
> +static inline u32 i9xx_dpll_compute_fp(struct dpll *dpll)
> +{
> +       return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
> +}
> +
>  #endif /*  __INTEL_DISPLAY_TYPES_H__ */
> --
> 2.27.0
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Intel-gfx] [PATCH 2/4] drm/i915: refactor some crtc code out of intel display.
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 2/4] drm/i915: refactor some crtc code out of intel display Dave Airlie
@ 2020-12-09 11:03   ` Daniel Vetter
  0 siblings, 0 replies; 13+ messages in thread
From: Daniel Vetter @ 2020-12-09 11:03 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx

On Wed, Dec 9, 2020 at 5:21 AM Dave Airlie <airlied@gmail.com> wrote:
>
> From: Dave Airlie <airlied@redhat.com>
>
> There may be more crtc code that can be pulled out, but this
> is a good start.
>
> RFC: maybe call the new file something different

I think the only problem is that it also contains a bunch of plane
stuff. Which is split up in all kinds of funny ways. I think a good
way to resplit the plane stuff would be

intel_plane.c: cross platform plane stuff
intel_cursor.c: legacy cursor plane
intel_i9xx_plane.c: pre-gen9 primary plane
intel_sprite_plane.c: pre-gen9 sprite planes
intel_gen9_plane: gen9+ universal planes

atm these are wildly mixed all over between intel_sprite.c,
intel_display.c, intel_atomic_plane.c and maybe some other places I
missed.

Also this isn't all the crtc code, there's intel_pipe_update_start/end
which should also be here, plus probably intel_usecs_to_scanlines too.

Since it's such a mess moving some of the plane stuff with the crtc
doesn't seem too bad since it's not really making anything worse. But
at least all the crtc stuff should be collected here.
-Daniel


> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
>  drivers/gpu/drm/i915/Makefile                |   1 +
>  drivers/gpu/drm/i915/display/intel_crtc.c    | 951 +++++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_display.c | 932 ------------------
>  drivers/gpu/drm/i915/display/intel_display.h |   7 +
>  4 files changed, 959 insertions(+), 932 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/display/intel_crtc.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 98a35b939052..ffec257702af 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -196,6 +196,7 @@ i915-y += \
>         display/intel_color.o \
>         display/intel_combo_phy.o \
>         display/intel_connector.o \
> +       display/intel_crtc.o \
>         display/intel_csr.o \
>         display/intel_cursor.o \
>         display/intel_display.o \
> diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
> new file mode 100644
> index 000000000000..75a79f18cee2
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_crtc.c
> @@ -0,0 +1,951 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2020 Intel Corporation
> + */
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_plane.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "intel_atomic.h"
> +#include "intel_atomic_plane.h"
> +#include "intel_color.h"
> +#include "intel_display_debugfs.h"
> +#include "intel_display_types.h"
> +#include "intel_pipe_crc.h"
> +#include "intel_sprite.h"
> +
> +/* Primary plane formats for gen <= 3 */
> +static const u32 i8xx_primary_formats[] = {
> +       DRM_FORMAT_C8,
> +       DRM_FORMAT_XRGB1555,
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_XRGB8888,
> +};
> +
> +/* Primary plane formats for ivb (no fp16 due to hw issue) */
> +static const u32 ivb_primary_formats[] = {
> +       DRM_FORMAT_C8,
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_XRGB2101010,
> +       DRM_FORMAT_XBGR2101010,
> +};
> +
> +/* Primary plane formats for gen >= 4, except ivb */
> +static const u32 i965_primary_formats[] = {
> +       DRM_FORMAT_C8,
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_XRGB2101010,
> +       DRM_FORMAT_XBGR2101010,
> +       DRM_FORMAT_XBGR16161616F,
> +};
> +
> +/* Primary plane formats for vlv/chv */
> +static const u32 vlv_primary_formats[] = {
> +       DRM_FORMAT_C8,
> +       DRM_FORMAT_RGB565,
> +       DRM_FORMAT_XRGB8888,
> +       DRM_FORMAT_XBGR8888,
> +       DRM_FORMAT_ARGB8888,
> +       DRM_FORMAT_ABGR8888,
> +       DRM_FORMAT_XRGB2101010,
> +       DRM_FORMAT_XBGR2101010,
> +       DRM_FORMAT_ARGB2101010,
> +       DRM_FORMAT_ABGR2101010,
> +       DRM_FORMAT_XBGR16161616F,
> +};
> +
> +static const u64 i9xx_format_modifiers[] = {
> +       I915_FORMAT_MOD_X_TILED,
> +       DRM_FORMAT_MOD_LINEAR,
> +       DRM_FORMAT_MOD_INVALID
> +};
> +
> +static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane,
> +                                           u32 format, u64 modifier)
> +{
> +       switch (modifier) {
> +       case DRM_FORMAT_MOD_LINEAR:
> +       case I915_FORMAT_MOD_X_TILED:
> +               break;
> +       default:
> +               return false;
> +       }
> +
> +       switch (format) {
> +       case DRM_FORMAT_C8:
> +       case DRM_FORMAT_RGB565:
> +       case DRM_FORMAT_XRGB1555:
> +       case DRM_FORMAT_XRGB8888:
> +               return modifier == DRM_FORMAT_MOD_LINEAR ||
> +                       modifier == I915_FORMAT_MOD_X_TILED;
> +       default:
> +               return false;
> +       }
> +}
> +
> +static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
> +                                           u32 format, u64 modifier)
> +{
> +       switch (modifier) {
> +       case DRM_FORMAT_MOD_LINEAR:
> +       case I915_FORMAT_MOD_X_TILED:
> +               break;
> +       default:
> +               return false;
> +       }
> +
> +       switch (format) {
> +       case DRM_FORMAT_C8:
> +       case DRM_FORMAT_RGB565:
> +       case DRM_FORMAT_XRGB8888:
> +       case DRM_FORMAT_XBGR8888:
> +       case DRM_FORMAT_ARGB8888:
> +       case DRM_FORMAT_ABGR8888:
> +       case DRM_FORMAT_XRGB2101010:
> +       case DRM_FORMAT_XBGR2101010:
> +       case DRM_FORMAT_ARGB2101010:
> +       case DRM_FORMAT_ABGR2101010:
> +       case DRM_FORMAT_XBGR16161616F:
> +               return modifier == DRM_FORMAT_MOD_LINEAR ||
> +                       modifier == I915_FORMAT_MOD_X_TILED;
> +       default:
> +               return false;
> +       }
> +}
> +
> +static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
> +                              enum i9xx_plane_id i9xx_plane)
> +{
> +       if (!HAS_FBC(dev_priv))
> +               return false;
> +
> +       if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> +               return i9xx_plane == PLANE_A; /* tied to pipe A */
> +       else if (IS_IVYBRIDGE(dev_priv))
> +               return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B ||
> +                       i9xx_plane == PLANE_C;
> +       else if (INTEL_GEN(dev_priv) >= 4)
> +               return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B;
> +       else
> +               return i9xx_plane == PLANE_A;
> +}
> +
> +static void assert_vblank_disabled(struct drm_crtc *crtc)
> +{
> +       if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
> +               drm_crtc_vblank_put(crtc);
> +}
> +
> +u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->base.dev;
> +       struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
> +
> +       if (!vblank->max_vblank_count)
> +               return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
> +
> +       return crtc->base.funcs->get_vblank_counter(&crtc->base);
> +}
> +
> +u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
> +       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +       u32 mode_flags = crtc->mode_flags;
> +
> +       /*
> +        * From Gen 11, In case of dsi cmd mode, frame counter wouldnt
> +        * have updated at the beginning of TE, if we want to use
> +        * the hw counter, then we would find it updated in only
> +        * the next TE, hence switching to sw counter.
> +        */
> +       if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1))
> +               return 0;
> +
> +       /*
> +        * On i965gm the hardware frame counter reads
> +        * zero when the TV encoder is enabled :(
> +        */
> +       if (IS_I965GM(dev_priv) &&
> +           (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
> +               return 0;
> +
> +       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> +               return 0xffffffff; /* full 32 bit counter */
> +       else if (INTEL_GEN(dev_priv) >= 3)
> +               return 0xffffff; /* only 24 bits of frame count */
> +       else
> +               return 0; /* Gen2 doesn't have a hardware frame counter */
> +}
> +
> +void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
> +{
> +       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +
> +       assert_vblank_disabled(&crtc->base);
> +       drm_crtc_set_max_vblank_count(&crtc->base,
> +                                     intel_crtc_max_vblank_count(crtc_state));
> +       drm_crtc_vblank_on(&crtc->base);
> +}
> +
> +void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state)
> +{
> +       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +
> +       drm_crtc_vblank_off(&crtc->base);
> +       assert_vblank_disabled(&crtc->base);
> +}
> +
> +struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc)
> +{
> +       struct intel_crtc_state *crtc_state;
> +
> +       crtc_state = kmalloc(sizeof(*crtc_state), GFP_KERNEL);
> +
> +       if (crtc_state)
> +               intel_crtc_state_reset(crtc_state, crtc);
> +
> +       return crtc_state;
> +}
> +
> +void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
> +                           struct intel_crtc *crtc)
> +{
> +       memset(crtc_state, 0, sizeof(*crtc_state));
> +
> +       __drm_atomic_helper_crtc_state_reset(&crtc_state->uapi, &crtc->base);
> +
> +       crtc_state->cpu_transcoder = INVALID_TRANSCODER;
> +       crtc_state->master_transcoder = INVALID_TRANSCODER;
> +       crtc_state->hsw_workaround_pipe = INVALID_PIPE;
> +       crtc_state->output_format = INTEL_OUTPUT_FORMAT_INVALID;
> +       crtc_state->scaler_state.scaler_id = -1;
> +       crtc_state->mst_master_transcoder = INVALID_TRANSCODER;
> +}
> +
> +static bool i9xx_plane_has_windowing(struct intel_plane *plane)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> +
> +       if (IS_CHERRYVIEW(dev_priv))
> +               return i9xx_plane == PLANE_B;
> +       else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> +               return false;
> +       else if (IS_GEN(dev_priv, 4))
> +               return i9xx_plane == PLANE_C;
> +       else
> +               return i9xx_plane == PLANE_B ||
> +                       i9xx_plane == PLANE_C;
> +}
> +
> +static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
> +                         const struct intel_plane_state *plane_state)
> +{
> +       struct drm_i915_private *dev_priv =
> +               to_i915(plane_state->uapi.plane->dev);
> +       const struct drm_framebuffer *fb = plane_state->hw.fb;
> +       unsigned int rotation = plane_state->hw.rotation;
> +       u32 dspcntr;
> +
> +       dspcntr = DISPLAY_PLANE_ENABLE;
> +
> +       if (IS_G4X(dev_priv) || IS_GEN(dev_priv, 5) ||
> +           IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
> +               dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
> +
> +       switch (fb->format->format) {
> +       case DRM_FORMAT_C8:
> +               dspcntr |= DISPPLANE_8BPP;
> +               break;
> +       case DRM_FORMAT_XRGB1555:
> +               dspcntr |= DISPPLANE_BGRX555;
> +               break;
> +       case DRM_FORMAT_ARGB1555:
> +               dspcntr |= DISPPLANE_BGRA555;
> +               break;
> +       case DRM_FORMAT_RGB565:
> +               dspcntr |= DISPPLANE_BGRX565;
> +               break;
> +       case DRM_FORMAT_XRGB8888:
> +               dspcntr |= DISPPLANE_BGRX888;
> +               break;
> +       case DRM_FORMAT_XBGR8888:
> +               dspcntr |= DISPPLANE_RGBX888;
> +               break;
> +       case DRM_FORMAT_ARGB8888:
> +               dspcntr |= DISPPLANE_BGRA888;
> +               break;
> +       case DRM_FORMAT_ABGR8888:
> +               dspcntr |= DISPPLANE_RGBA888;
> +               break;
> +       case DRM_FORMAT_XRGB2101010:
> +               dspcntr |= DISPPLANE_BGRX101010;
> +               break;
> +       case DRM_FORMAT_XBGR2101010:
> +               dspcntr |= DISPPLANE_RGBX101010;
> +               break;
> +       case DRM_FORMAT_ARGB2101010:
> +               dspcntr |= DISPPLANE_BGRA101010;
> +               break;
> +       case DRM_FORMAT_ABGR2101010:
> +               dspcntr |= DISPPLANE_RGBA101010;
> +               break;
> +       case DRM_FORMAT_XBGR16161616F:
> +               dspcntr |= DISPPLANE_RGBX161616;
> +               break;
> +       default:
> +               MISSING_CASE(fb->format->format);
> +               return 0;
> +       }
> +
> +       if (INTEL_GEN(dev_priv) >= 4 &&
> +           fb->modifier == I915_FORMAT_MOD_X_TILED)
> +               dspcntr |= DISPPLANE_TILED;
> +
> +       if (rotation & DRM_MODE_ROTATE_180)
> +               dspcntr |= DISPPLANE_ROTATE_180;
> +
> +       if (rotation & DRM_MODE_REFLECT_X)
> +               dspcntr |= DISPPLANE_MIRROR;
> +
> +       return dspcntr;
> +}
> +
> +static int
> +i9xx_plane_check(struct intel_crtc_state *crtc_state,
> +                struct intel_plane_state *plane_state)
> +{
> +       struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
> +       int ret;
> +
> +       ret = chv_plane_check_rotation(plane_state);
> +       if (ret)
> +               return ret;
> +
> +       ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
> +                                               DRM_PLANE_HELPER_NO_SCALING,
> +                                               DRM_PLANE_HELPER_NO_SCALING,
> +                                               i9xx_plane_has_windowing(plane));
> +       if (ret)
> +               return ret;
> +
> +       ret = i9xx_check_plane_surface(plane_state);
> +       if (ret)
> +               return ret;
> +
> +       if (!plane_state->uapi.visible)
> +               return 0;
> +
> +       ret = intel_plane_check_src_coordinates(plane_state);
> +       if (ret)
> +               return ret;
> +
> +       plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);
> +
> +       return 0;
> +}
> +
> +static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
> +{
> +       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       u32 dspcntr = 0;
> +
> +       if (crtc_state->gamma_enable)
> +               dspcntr |= DISPPLANE_GAMMA_ENABLE;
> +
> +       if (crtc_state->csc_enable)
> +               dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
> +
> +       if (INTEL_GEN(dev_priv) < 5)
> +               dspcntr |= DISPPLANE_SEL_PIPE(crtc->pipe);
> +
> +       return dspcntr;
> +}
> +
> +static void i9xx_plane_ratio(const struct intel_crtc_state *crtc_state,
> +                            const struct intel_plane_state *plane_state,
> +                            unsigned int *num, unsigned int *den)
> +{
> +       const struct drm_framebuffer *fb = plane_state->hw.fb;
> +       unsigned int cpp = fb->format->cpp[0];
> +
> +       /*
> +        * g4x bspec says 64bpp pixel rate can't exceed 80%
> +        * of cdclk when the sprite plane is enabled on the
> +        * same pipe. ilk/snb bspec says 64bpp pixel rate is
> +        * never allowed to exceed 80% of cdclk. Let's just go
> +        * with the ilk/snb limit always.
> +        */
> +       if (cpp == 8) {
> +               *num = 10;
> +               *den = 8;
> +       } else {
> +               *num = 1;
> +               *den = 1;
> +       }
> +}
> +
> +static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
> +                               const struct intel_plane_state *plane_state)
> +{
> +       unsigned int pixel_rate;
> +       unsigned int num, den;
> +
> +       /*
> +        * Note that crtc_state->pixel_rate accounts for both
> +        * horizontal and vertical panel fitter downscaling factors.
> +        * Pre-HSW bspec tells us to only consider the horizontal
> +        * downscaling factor here. We ignore that and just consider
> +        * both for simplicity.
> +        */
> +       pixel_rate = crtc_state->pixel_rate;
> +
> +       i9xx_plane_ratio(crtc_state, plane_state, &num, &den);
> +
> +       /* two pixels per clock with double wide pipe */
> +       if (crtc_state->double_wide)
> +               den *= 2;
> +
> +       return DIV_ROUND_UP(pixel_rate * num, den);
> +}
> +
> +static void i9xx_update_plane(struct intel_plane *plane,
> +                             const struct intel_crtc_state *crtc_state,
> +                             const struct intel_plane_state *plane_state)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> +       u32 linear_offset;
> +       int x = plane_state->color_plane[0].x;
> +       int y = plane_state->color_plane[0].y;
> +       int crtc_x = plane_state->uapi.dst.x1;
> +       int crtc_y = plane_state->uapi.dst.y1;
> +       int crtc_w = drm_rect_width(&plane_state->uapi.dst);
> +       int crtc_h = drm_rect_height(&plane_state->uapi.dst);
> +       unsigned long irqflags;
> +       u32 dspaddr_offset;
> +       u32 dspcntr;
> +
> +       dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
> +
> +       linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
> +
> +       if (INTEL_GEN(dev_priv) >= 4)
> +               dspaddr_offset = plane_state->color_plane[0].offset;
> +       else
> +               dspaddr_offset = linear_offset;
> +
> +       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> +
> +       intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane),
> +                         plane_state->color_plane[0].stride);
> +
> +       if (INTEL_GEN(dev_priv) < 4) {
> +               /*
> +                * PLANE_A doesn't actually have a full window
> +                * generator but let's assume we still need to
> +                * program whatever is there.
> +                */
> +               intel_de_write_fw(dev_priv, DSPPOS(i9xx_plane),
> +                                 (crtc_y << 16) | crtc_x);
> +               intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane),
> +                                 ((crtc_h - 1) << 16) | (crtc_w - 1));
> +       } else if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
> +               intel_de_write_fw(dev_priv, PRIMPOS(i9xx_plane),
> +                                 (crtc_y << 16) | crtc_x);
> +               intel_de_write_fw(dev_priv, PRIMSIZE(i9xx_plane),
> +                                 ((crtc_h - 1) << 16) | (crtc_w - 1));
> +               intel_de_write_fw(dev_priv, PRIMCNSTALPHA(i9xx_plane), 0);
> +       }
> +
> +       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
> +               intel_de_write_fw(dev_priv, DSPOFFSET(i9xx_plane),
> +                                 (y << 16) | x);
> +       } else if (INTEL_GEN(dev_priv) >= 4) {
> +               intel_de_write_fw(dev_priv, DSPLINOFF(i9xx_plane),
> +                                 linear_offset);
> +               intel_de_write_fw(dev_priv, DSPTILEOFF(i9xx_plane),
> +                                 (y << 16) | x);
> +       }
> +
> +       /*
> +        * The control register self-arms if the plane was previously
> +        * disabled. Try to make the plane enable atomic by writing
> +        * the control register just before the surface register.
> +        */
> +       intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
> +       if (INTEL_GEN(dev_priv) >= 4)
> +               intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
> +                                 intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
> +       else
> +               intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane),
> +                                 intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
> +
> +       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> +}
> +
> +static void i9xx_disable_plane(struct intel_plane *plane,
> +                              const struct intel_crtc_state *crtc_state)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> +       unsigned long irqflags;
> +       u32 dspcntr;
> +
> +       /*
> +        * DSPCNTR pipe gamma enable on g4x+ and pipe csc
> +        * enable on ilk+ affect the pipe bottom color as
> +        * well, so we must configure them even if the plane
> +        * is disabled.
> +        *
> +        * On pre-g4x there is no way to gamma correct the
> +        * pipe bottom color but we'll keep on doing this
> +        * anyway so that the crtc state readout works correctly.
> +        */
> +       dspcntr = i9xx_plane_ctl_crtc(crtc_state);
> +
> +       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> +
> +       intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
> +       if (INTEL_GEN(dev_priv) >= 4)
> +               intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0);
> +       else
> +               intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0);
> +
> +       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> +}
> +
> +static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
> +                                   enum pipe *pipe)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       enum intel_display_power_domain power_domain;
> +       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> +       intel_wakeref_t wakeref;
> +       bool ret;
> +       u32 val;
> +
> +       /*
> +        * Not 100% correct for planes that can move between pipes,
> +        * but that's only the case for gen2-4 which don't have any
> +        * display power wells.
> +        */
> +       power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> +       wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +       if (!wakeref)
> +               return false;
> +
> +       val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane));
> +
> +       ret = val & DISPLAY_PLANE_ENABLE;
> +
> +       if (INTEL_GEN(dev_priv) >= 5)
> +               *pipe = plane->pipe;
> +       else
> +               *pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
> +                       DISPPLANE_SEL_PIPE_SHIFT;
> +
> +       intel_display_power_put(dev_priv, power_domain, wakeref);
> +
> +       return ret;
> +}
> +
> +unsigned int
> +i9xx_plane_max_stride(struct intel_plane *plane,
> +                     u32 pixel_format, u64 modifier,
> +                     unsigned int rotation)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +
> +       if (!HAS_GMCH(dev_priv)) {
> +               return 32*1024;
> +       } else if (INTEL_GEN(dev_priv) >= 4) {
> +               if (modifier == I915_FORMAT_MOD_X_TILED)
> +                       return 16*1024;
> +               else
> +                       return 32*1024;
> +       } else if (INTEL_GEN(dev_priv) >= 3) {
> +               if (modifier == I915_FORMAT_MOD_X_TILED)
> +                       return 8*1024;
> +               else
> +                       return 16*1024;
> +       } else {
> +               if (plane->i9xx_plane == PLANE_C)
> +                       return 4*1024;
> +               else
> +                       return 8*1024;
> +       }
> +}
> +
> +static const struct drm_plane_funcs i965_plane_funcs = {
> +       .update_plane = drm_atomic_helper_update_plane,
> +       .disable_plane = drm_atomic_helper_disable_plane,
> +       .destroy = intel_plane_destroy,
> +       .atomic_duplicate_state = intel_plane_duplicate_state,
> +       .atomic_destroy_state = intel_plane_destroy_state,
> +       .format_mod_supported = i965_plane_format_mod_supported,
> +};
> +
> +static const struct drm_plane_funcs i8xx_plane_funcs = {
> +       .update_plane = drm_atomic_helper_update_plane,
> +       .disable_plane = drm_atomic_helper_disable_plane,
> +       .destroy = intel_plane_destroy,
> +       .atomic_duplicate_state = intel_plane_duplicate_state,
> +       .atomic_destroy_state = intel_plane_destroy_state,
> +       .format_mod_supported = i8xx_plane_format_mod_supported,
> +};
> +
> +static struct intel_plane *
> +intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
> +{
> +       struct intel_plane *plane;
> +       const struct drm_plane_funcs *plane_funcs;
> +       unsigned int supported_rotations;
> +       const u32 *formats;
> +       int num_formats;
> +       int ret, zpos;
> +
> +       if (INTEL_GEN(dev_priv) >= 9)
> +               return skl_universal_plane_create(dev_priv, pipe,
> +                                                 PLANE_PRIMARY);
> +
> +       plane = intel_plane_alloc();
> +       if (IS_ERR(plane))
> +               return plane;
> +
> +       plane->pipe = pipe;
> +       /*
> +        * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
> +        * port is hooked to pipe B. Hence we want plane A feeding pipe B.
> +        */
> +       if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) < 4 &&
> +           INTEL_NUM_PIPES(dev_priv) == 2)
> +               plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
> +       else
> +               plane->i9xx_plane = (enum i9xx_plane_id) pipe;
> +       plane->id = PLANE_PRIMARY;
> +       plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
> +
> +       plane->has_fbc = i9xx_plane_has_fbc(dev_priv, plane->i9xx_plane);
> +       if (plane->has_fbc) {
> +               struct intel_fbc *fbc = &dev_priv->fbc;
> +
> +               fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
> +       }
> +
> +       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
> +               formats = vlv_primary_formats;
> +               num_formats = ARRAY_SIZE(vlv_primary_formats);
> +       } else if (INTEL_GEN(dev_priv) >= 4) {
> +               /*
> +                * WaFP16GammaEnabling:ivb
> +                * "Workaround : When using the 64-bit format, the plane
> +                *  output on each color channel has one quarter amplitude.
> +                *  It can be brought up to full amplitude by using pipe
> +                *  gamma correction or pipe color space conversion to
> +                *  multiply the plane output by four."
> +                *
> +                * There is no dedicated plane gamma for the primary plane,
> +                * and using the pipe gamma/csc could conflict with other
> +                * planes, so we choose not to expose fp16 on IVB primary
> +                * planes. HSW primary planes no longer have this problem.
> +                */
> +               if (IS_IVYBRIDGE(dev_priv)) {
> +                       formats = ivb_primary_formats;
> +                       num_formats = ARRAY_SIZE(ivb_primary_formats);
> +               } else {
> +                       formats = i965_primary_formats;
> +                       num_formats = ARRAY_SIZE(i965_primary_formats);
> +               }
> +       } else {
> +               formats = i8xx_primary_formats;
> +               num_formats = ARRAY_SIZE(i8xx_primary_formats);
> +       }
> +
> +       if (INTEL_GEN(dev_priv) >= 4)
> +               plane_funcs = &i965_plane_funcs;
> +       else
> +               plane_funcs = &i8xx_plane_funcs;
> +
> +       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> +               plane->min_cdclk = vlv_plane_min_cdclk;
> +       else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> +               plane->min_cdclk = hsw_plane_min_cdclk;
> +       else if (IS_IVYBRIDGE(dev_priv))
> +               plane->min_cdclk = ivb_plane_min_cdclk;
> +       else
> +               plane->min_cdclk = i9xx_plane_min_cdclk;
> +
> +       plane->max_stride = i9xx_plane_max_stride;
> +       plane->update_plane = i9xx_update_plane;
> +       plane->disable_plane = i9xx_disable_plane;
> +       plane->get_hw_state = i9xx_plane_get_hw_state;
> +       plane->check_plane = i9xx_plane_check;
> +
> +       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> +               ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
> +                                              0, plane_funcs,
> +                                              formats, num_formats,
> +                                              i9xx_format_modifiers,
> +                                              DRM_PLANE_TYPE_PRIMARY,
> +                                              "primary %c", pipe_name(pipe));
> +       else
> +               ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
> +                                              0, plane_funcs,
> +                                              formats, num_formats,
> +                                              i9xx_format_modifiers,
> +                                              DRM_PLANE_TYPE_PRIMARY,
> +                                              "plane %c",
> +                                              plane_name(plane->i9xx_plane));
> +       if (ret)
> +               goto fail;
> +
> +       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
> +               supported_rotations =
> +                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
> +                       DRM_MODE_REFLECT_X;
> +       } else if (INTEL_GEN(dev_priv) >= 4) {
> +               supported_rotations =
> +                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
> +       } else {
> +               supported_rotations = DRM_MODE_ROTATE_0;
> +       }
> +
> +       if (INTEL_GEN(dev_priv) >= 4)
> +               drm_plane_create_rotation_property(&plane->base,
> +                                                  DRM_MODE_ROTATE_0,
> +                                                  supported_rotations);
> +
> +       zpos = 0;
> +       drm_plane_create_zpos_immutable_property(&plane->base, zpos);
> +
> +       drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
> +
> +       return plane;
> +
> +fail:
> +       intel_plane_free(plane);
> +
> +       return ERR_PTR(ret);
> +}
> +
> +static struct intel_crtc *intel_crtc_alloc(void)
> +{
> +       struct intel_crtc_state *crtc_state;
> +       struct intel_crtc *crtc;
> +
> +       crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
> +       if (!crtc)
> +               return ERR_PTR(-ENOMEM);
> +
> +       crtc_state = intel_crtc_state_alloc(crtc);
> +       if (!crtc_state) {
> +               kfree(crtc);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       crtc->base.state = &crtc_state->uapi;
> +       crtc->config = crtc_state;
> +
> +       return crtc;
> +}
> +
> +static void intel_crtc_free(struct intel_crtc *crtc)
> +{
> +       intel_crtc_destroy_state(&crtc->base, crtc->base.state);
> +       kfree(crtc);
> +}
> +
> +static void intel_crtc_destroy(struct drm_crtc *crtc)
> +{
> +       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +
> +       drm_crtc_cleanup(crtc);
> +       kfree(intel_crtc);
> +}
> +
> +static int intel_crtc_late_register(struct drm_crtc *crtc)
> +{
> +       intel_crtc_debugfs_add(crtc);
> +       return 0;
> +}
> +
> +#define INTEL_CRTC_FUNCS \
> +       .gamma_set = drm_atomic_helper_legacy_gamma_set, \
> +       .set_config = drm_atomic_helper_set_config, \
> +       .destroy = intel_crtc_destroy, \
> +       .page_flip = drm_atomic_helper_page_flip, \
> +       .atomic_duplicate_state = intel_crtc_duplicate_state, \
> +       .atomic_destroy_state = intel_crtc_destroy_state, \
> +       .set_crc_source = intel_crtc_set_crc_source, \
> +       .verify_crc_source = intel_crtc_verify_crc_source, \
> +       .get_crc_sources = intel_crtc_get_crc_sources, \
> +       .late_register = intel_crtc_late_register
> +
> +static const struct drm_crtc_funcs bdw_crtc_funcs = {
> +       INTEL_CRTC_FUNCS,
> +
> +       .get_vblank_counter = g4x_get_vblank_counter,
> +       .enable_vblank = bdw_enable_vblank,
> +       .disable_vblank = bdw_disable_vblank,
> +       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> +};
> +
> +static const struct drm_crtc_funcs ilk_crtc_funcs = {
> +       INTEL_CRTC_FUNCS,
> +
> +       .get_vblank_counter = g4x_get_vblank_counter,
> +       .enable_vblank = ilk_enable_vblank,
> +       .disable_vblank = ilk_disable_vblank,
> +       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> +};
> +
> +static const struct drm_crtc_funcs g4x_crtc_funcs = {
> +       INTEL_CRTC_FUNCS,
> +
> +       .get_vblank_counter = g4x_get_vblank_counter,
> +       .enable_vblank = i965_enable_vblank,
> +       .disable_vblank = i965_disable_vblank,
> +       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> +};
> +
> +static const struct drm_crtc_funcs i965_crtc_funcs = {
> +       INTEL_CRTC_FUNCS,
> +
> +       .get_vblank_counter = i915_get_vblank_counter,
> +       .enable_vblank = i965_enable_vblank,
> +       .disable_vblank = i965_disable_vblank,
> +       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> +};
> +
> +static const struct drm_crtc_funcs i915gm_crtc_funcs = {
> +       INTEL_CRTC_FUNCS,
> +
> +       .get_vblank_counter = i915_get_vblank_counter,
> +       .enable_vblank = i915gm_enable_vblank,
> +       .disable_vblank = i915gm_disable_vblank,
> +       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> +};
> +
> +static const struct drm_crtc_funcs i915_crtc_funcs = {
> +       INTEL_CRTC_FUNCS,
> +
> +       .get_vblank_counter = i915_get_vblank_counter,
> +       .enable_vblank = i8xx_enable_vblank,
> +       .disable_vblank = i8xx_disable_vblank,
> +       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> +};
> +
> +static const struct drm_crtc_funcs i8xx_crtc_funcs = {
> +       INTEL_CRTC_FUNCS,
> +
> +       /* no hw vblank counter */
> +       .enable_vblank = i8xx_enable_vblank,
> +       .disable_vblank = i8xx_disable_vblank,
> +       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> +};
> +
> +int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
> +{
> +       struct intel_plane *primary, *cursor;
> +       const struct drm_crtc_funcs *funcs;
> +       struct intel_crtc *crtc;
> +       int sprite, ret;
> +
> +       crtc = intel_crtc_alloc();
> +       if (IS_ERR(crtc))
> +               return PTR_ERR(crtc);
> +
> +       crtc->pipe = pipe;
> +       crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe];
> +
> +       primary = intel_primary_plane_create(dev_priv, pipe);
> +       if (IS_ERR(primary)) {
> +               ret = PTR_ERR(primary);
> +               goto fail;
> +       }
> +       crtc->plane_ids_mask |= BIT(primary->id);
> +
> +       for_each_sprite(dev_priv, pipe, sprite) {
> +               struct intel_plane *plane;
> +
> +               plane = intel_sprite_plane_create(dev_priv, pipe, sprite);
> +               if (IS_ERR(plane)) {
> +                       ret = PTR_ERR(plane);
> +                       goto fail;
> +               }
> +               crtc->plane_ids_mask |= BIT(plane->id);
> +       }
> +
> +       cursor = intel_cursor_plane_create(dev_priv, pipe);
> +       if (IS_ERR(cursor)) {
> +               ret = PTR_ERR(cursor);
> +               goto fail;
> +       }
> +       crtc->plane_ids_mask |= BIT(cursor->id);
> +
> +       if (HAS_GMCH(dev_priv)) {
> +               if (IS_CHERRYVIEW(dev_priv) ||
> +                   IS_VALLEYVIEW(dev_priv) || IS_G4X(dev_priv))
> +                       funcs = &g4x_crtc_funcs;
> +               else if (IS_GEN(dev_priv, 4))
> +                       funcs = &i965_crtc_funcs;
> +               else if (IS_I945GM(dev_priv) || IS_I915GM(dev_priv))
> +                       funcs = &i915gm_crtc_funcs;
> +               else if (IS_GEN(dev_priv, 3))
> +                       funcs = &i915_crtc_funcs;
> +               else
> +                       funcs = &i8xx_crtc_funcs;
> +       } else {
> +               if (INTEL_GEN(dev_priv) >= 8)
> +                       funcs = &bdw_crtc_funcs;
> +               else
> +                       funcs = &ilk_crtc_funcs;
> +       }
> +
> +       ret = drm_crtc_init_with_planes(&dev_priv->drm, &crtc->base,
> +                                       &primary->base, &cursor->base,
> +                                       funcs, "pipe %c", pipe_name(pipe));
> +       if (ret)
> +               goto fail;
> +
> +       BUG_ON(pipe >= ARRAY_SIZE(dev_priv->pipe_to_crtc_mapping) ||
> +              dev_priv->pipe_to_crtc_mapping[pipe] != NULL);
> +       dev_priv->pipe_to_crtc_mapping[pipe] = crtc;
> +
> +       if (INTEL_GEN(dev_priv) < 9) {
> +               enum i9xx_plane_id i9xx_plane = primary->i9xx_plane;
> +
> +               BUG_ON(i9xx_plane >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
> +                      dev_priv->plane_to_crtc_mapping[i9xx_plane] != NULL);
> +               dev_priv->plane_to_crtc_mapping[i9xx_plane] = crtc;
> +       }
> +
> +       if (INTEL_GEN(dev_priv) >= 10)
> +               drm_crtc_create_scaling_filter_property(&crtc->base,
> +                                               BIT(DRM_SCALING_FILTER_DEFAULT) |
> +                                               BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
> +
> +       intel_color_init(crtc);
> +
> +       intel_crtc_crc_init(crtc);
> +
> +       drm_WARN_ON(&dev_priv->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
> +
> +       return 0;
> +
> +fail:
> +       intel_crtc_free(crtc);
> +
> +       return ret;
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index 0a3b97889248..c6f30e4ec51e 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -87,56 +87,6 @@
>  #include "intel_tc.h"
>  #include "intel_vga.h"
>
> -/* Primary plane formats for gen <= 3 */
> -static const u32 i8xx_primary_formats[] = {
> -       DRM_FORMAT_C8,
> -       DRM_FORMAT_XRGB1555,
> -       DRM_FORMAT_RGB565,
> -       DRM_FORMAT_XRGB8888,
> -};
> -
> -/* Primary plane formats for ivb (no fp16 due to hw issue) */
> -static const u32 ivb_primary_formats[] = {
> -       DRM_FORMAT_C8,
> -       DRM_FORMAT_RGB565,
> -       DRM_FORMAT_XRGB8888,
> -       DRM_FORMAT_XBGR8888,
> -       DRM_FORMAT_XRGB2101010,
> -       DRM_FORMAT_XBGR2101010,
> -};
> -
> -/* Primary plane formats for gen >= 4, except ivb */
> -static const u32 i965_primary_formats[] = {
> -       DRM_FORMAT_C8,
> -       DRM_FORMAT_RGB565,
> -       DRM_FORMAT_XRGB8888,
> -       DRM_FORMAT_XBGR8888,
> -       DRM_FORMAT_XRGB2101010,
> -       DRM_FORMAT_XBGR2101010,
> -       DRM_FORMAT_XBGR16161616F,
> -};
> -
> -/* Primary plane formats for vlv/chv */
> -static const u32 vlv_primary_formats[] = {
> -       DRM_FORMAT_C8,
> -       DRM_FORMAT_RGB565,
> -       DRM_FORMAT_XRGB8888,
> -       DRM_FORMAT_XBGR8888,
> -       DRM_FORMAT_ARGB8888,
> -       DRM_FORMAT_ABGR8888,
> -       DRM_FORMAT_XRGB2101010,
> -       DRM_FORMAT_XBGR2101010,
> -       DRM_FORMAT_ARGB2101010,
> -       DRM_FORMAT_ABGR2101010,
> -       DRM_FORMAT_XBGR16161616F,
> -};
> -
> -static const u64 i9xx_format_modifiers[] = {
> -       I915_FORMAT_MOD_X_TILED,
> -       DRM_FORMAT_MOD_LINEAR,
> -       DRM_FORMAT_MOD_INVALID
> -};
> -
>  static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
>                                 struct intel_crtc_state *pipe_config);
>  static void ilk_pch_clock_get(struct intel_crtc *crtc,
> @@ -162,7 +112,6 @@ static void skl_pfit_enable(const struct intel_crtc_state *crtc_state);
>  static void ilk_pfit_enable(const struct intel_crtc_state *crtc_state);
>  static void intel_modeset_setup_hw_state(struct drm_device *dev,
>                                          struct drm_modeset_acquire_ctx *ctx);
> -static struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc);
>
>  struct intel_limit {
>         struct {
> @@ -1306,12 +1255,6 @@ static void assert_planes_disabled(struct intel_crtc *crtc)
>                 assert_plane_disabled(plane);
>  }
>
> -static void assert_vblank_disabled(struct drm_crtc *crtc)
> -{
> -       if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
> -               drm_crtc_vblank_put(crtc);
> -}
> -
>  void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
>                                     enum pipe pipe)
>  {
> @@ -1796,55 +1739,6 @@ enum pipe intel_crtc_pch_transcoder(struct intel_crtc *crtc)
>                 return crtc->pipe;
>  }
>
> -static u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
> -       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -       u32 mode_flags = crtc->mode_flags;
> -
> -       /*
> -        * From Gen 11, In case of dsi cmd mode, frame counter wouldnt
> -        * have updated at the beginning of TE, if we want to use
> -        * the hw counter, then we would find it updated in only
> -        * the next TE, hence switching to sw counter.
> -        */
> -       if (mode_flags & (I915_MODE_FLAG_DSI_USE_TE0 | I915_MODE_FLAG_DSI_USE_TE1))
> -               return 0;
> -
> -       /*
> -        * On i965gm the hardware frame counter reads
> -        * zero when the TV encoder is enabled :(
> -        */
> -       if (IS_I965GM(dev_priv) &&
> -           (crtc_state->output_types & BIT(INTEL_OUTPUT_TVOUT)))
> -               return 0;
> -
> -       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> -               return 0xffffffff; /* full 32 bit counter */
> -       else if (INTEL_GEN(dev_priv) >= 3)
> -               return 0xffffff; /* only 24 bits of frame count */
> -       else
> -               return 0; /* Gen2 doesn't have a hardware frame counter */
> -}
> -
> -void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
> -{
> -       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -
> -       assert_vblank_disabled(&crtc->base);
> -       drm_crtc_set_max_vblank_count(&crtc->base,
> -                                     intel_crtc_max_vblank_count(crtc_state));
> -       drm_crtc_vblank_on(&crtc->base);
> -}
> -
> -void intel_crtc_vblank_off(const struct intel_crtc_state *crtc_state)
> -{
> -       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -
> -       drm_crtc_vblank_off(&crtc->base);
> -       assert_vblank_disabled(&crtc->base);
> -}
> -
>  void intel_enable_pipe(const struct intel_crtc_state *new_crtc_state)
>  {
>         struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->uapi.crtc);
> @@ -4057,171 +3951,6 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state)
>         return 0;
>  }
>
> -static void i9xx_plane_ratio(const struct intel_crtc_state *crtc_state,
> -                            const struct intel_plane_state *plane_state,
> -                            unsigned int *num, unsigned int *den)
> -{
> -       const struct drm_framebuffer *fb = plane_state->hw.fb;
> -       unsigned int cpp = fb->format->cpp[0];
> -
> -       /*
> -        * g4x bspec says 64bpp pixel rate can't exceed 80%
> -        * of cdclk when the sprite plane is enabled on the
> -        * same pipe. ilk/snb bspec says 64bpp pixel rate is
> -        * never allowed to exceed 80% of cdclk. Let's just go
> -        * with the ilk/snb limit always.
> -        */
> -       if (cpp == 8) {
> -               *num = 10;
> -               *den = 8;
> -       } else {
> -               *num = 1;
> -               *den = 1;
> -       }
> -}
> -
> -static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
> -                               const struct intel_plane_state *plane_state)
> -{
> -       unsigned int pixel_rate;
> -       unsigned int num, den;
> -
> -       /*
> -        * Note that crtc_state->pixel_rate accounts for both
> -        * horizontal and vertical panel fitter downscaling factors.
> -        * Pre-HSW bspec tells us to only consider the horizontal
> -        * downscaling factor here. We ignore that and just consider
> -        * both for simplicity.
> -        */
> -       pixel_rate = crtc_state->pixel_rate;
> -
> -       i9xx_plane_ratio(crtc_state, plane_state, &num, &den);
> -
> -       /* two pixels per clock with double wide pipe */
> -       if (crtc_state->double_wide)
> -               den *= 2;
> -
> -       return DIV_ROUND_UP(pixel_rate * num, den);
> -}
> -
> -unsigned int
> -i9xx_plane_max_stride(struct intel_plane *plane,
> -                     u32 pixel_format, u64 modifier,
> -                     unsigned int rotation)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -
> -       if (!HAS_GMCH(dev_priv)) {
> -               return 32*1024;
> -       } else if (INTEL_GEN(dev_priv) >= 4) {
> -               if (modifier == I915_FORMAT_MOD_X_TILED)
> -                       return 16*1024;
> -               else
> -                       return 32*1024;
> -       } else if (INTEL_GEN(dev_priv) >= 3) {
> -               if (modifier == I915_FORMAT_MOD_X_TILED)
> -                       return 8*1024;
> -               else
> -                       return 16*1024;
> -       } else {
> -               if (plane->i9xx_plane == PLANE_C)
> -                       return 4*1024;
> -               else
> -                       return 8*1024;
> -       }
> -}
> -
> -static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
> -{
> -       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       u32 dspcntr = 0;
> -
> -       if (crtc_state->gamma_enable)
> -               dspcntr |= DISPPLANE_GAMMA_ENABLE;
> -
> -       if (crtc_state->csc_enable)
> -               dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
> -
> -       if (INTEL_GEN(dev_priv) < 5)
> -               dspcntr |= DISPPLANE_SEL_PIPE(crtc->pipe);
> -
> -       return dspcntr;
> -}
> -
> -static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
> -                         const struct intel_plane_state *plane_state)
> -{
> -       struct drm_i915_private *dev_priv =
> -               to_i915(plane_state->uapi.plane->dev);
> -       const struct drm_framebuffer *fb = plane_state->hw.fb;
> -       unsigned int rotation = plane_state->hw.rotation;
> -       u32 dspcntr;
> -
> -       dspcntr = DISPLAY_PLANE_ENABLE;
> -
> -       if (IS_G4X(dev_priv) || IS_GEN(dev_priv, 5) ||
> -           IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
> -               dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
> -
> -       switch (fb->format->format) {
> -       case DRM_FORMAT_C8:
> -               dspcntr |= DISPPLANE_8BPP;
> -               break;
> -       case DRM_FORMAT_XRGB1555:
> -               dspcntr |= DISPPLANE_BGRX555;
> -               break;
> -       case DRM_FORMAT_ARGB1555:
> -               dspcntr |= DISPPLANE_BGRA555;
> -               break;
> -       case DRM_FORMAT_RGB565:
> -               dspcntr |= DISPPLANE_BGRX565;
> -               break;
> -       case DRM_FORMAT_XRGB8888:
> -               dspcntr |= DISPPLANE_BGRX888;
> -               break;
> -       case DRM_FORMAT_XBGR8888:
> -               dspcntr |= DISPPLANE_RGBX888;
> -               break;
> -       case DRM_FORMAT_ARGB8888:
> -               dspcntr |= DISPPLANE_BGRA888;
> -               break;
> -       case DRM_FORMAT_ABGR8888:
> -               dspcntr |= DISPPLANE_RGBA888;
> -               break;
> -       case DRM_FORMAT_XRGB2101010:
> -               dspcntr |= DISPPLANE_BGRX101010;
> -               break;
> -       case DRM_FORMAT_XBGR2101010:
> -               dspcntr |= DISPPLANE_RGBX101010;
> -               break;
> -       case DRM_FORMAT_ARGB2101010:
> -               dspcntr |= DISPPLANE_BGRA101010;
> -               break;
> -       case DRM_FORMAT_ABGR2101010:
> -               dspcntr |= DISPPLANE_RGBA101010;
> -               break;
> -       case DRM_FORMAT_XBGR16161616F:
> -               dspcntr |= DISPPLANE_RGBX161616;
> -               break;
> -       default:
> -               MISSING_CASE(fb->format->format);
> -               return 0;
> -       }
> -
> -       if (INTEL_GEN(dev_priv) >= 4 &&
> -           fb->modifier == I915_FORMAT_MOD_X_TILED)
> -               dspcntr |= DISPPLANE_TILED;
> -
> -       if (rotation & DRM_MODE_ROTATE_180)
> -               dspcntr |= DISPPLANE_ROTATE_180;
> -
> -       if (rotation & DRM_MODE_REFLECT_X)
> -               dspcntr |= DISPPLANE_MIRROR;
> -
> -       return dspcntr;
> -}
> -
>  int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
>  {
>         struct drm_i915_private *dev_priv =
> @@ -4282,197 +4011,6 @@ int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
>         return 0;
>  }
>
> -static bool i9xx_plane_has_windowing(struct intel_plane *plane)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> -
> -       if (IS_CHERRYVIEW(dev_priv))
> -               return i9xx_plane == PLANE_B;
> -       else if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> -               return false;
> -       else if (IS_GEN(dev_priv, 4))
> -               return i9xx_plane == PLANE_C;
> -       else
> -               return i9xx_plane == PLANE_B ||
> -                       i9xx_plane == PLANE_C;
> -}
> -
> -static int
> -i9xx_plane_check(struct intel_crtc_state *crtc_state,
> -                struct intel_plane_state *plane_state)
> -{
> -       struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
> -       int ret;
> -
> -       ret = chv_plane_check_rotation(plane_state);
> -       if (ret)
> -               return ret;
> -
> -       ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
> -                                               DRM_PLANE_HELPER_NO_SCALING,
> -                                               DRM_PLANE_HELPER_NO_SCALING,
> -                                               i9xx_plane_has_windowing(plane));
> -       if (ret)
> -               return ret;
> -
> -       ret = i9xx_check_plane_surface(plane_state);
> -       if (ret)
> -               return ret;
> -
> -       if (!plane_state->uapi.visible)
> -               return 0;
> -
> -       ret = intel_plane_check_src_coordinates(plane_state);
> -       if (ret)
> -               return ret;
> -
> -       plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);
> -
> -       return 0;
> -}
> -
> -static void i9xx_update_plane(struct intel_plane *plane,
> -                             const struct intel_crtc_state *crtc_state,
> -                             const struct intel_plane_state *plane_state)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> -       u32 linear_offset;
> -       int x = plane_state->color_plane[0].x;
> -       int y = plane_state->color_plane[0].y;
> -       int crtc_x = plane_state->uapi.dst.x1;
> -       int crtc_y = plane_state->uapi.dst.y1;
> -       int crtc_w = drm_rect_width(&plane_state->uapi.dst);
> -       int crtc_h = drm_rect_height(&plane_state->uapi.dst);
> -       unsigned long irqflags;
> -       u32 dspaddr_offset;
> -       u32 dspcntr;
> -
> -       dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
> -
> -       linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
> -
> -       if (INTEL_GEN(dev_priv) >= 4)
> -               dspaddr_offset = plane_state->color_plane[0].offset;
> -       else
> -               dspaddr_offset = linear_offset;
> -
> -       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> -
> -       intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane),
> -                         plane_state->color_plane[0].stride);
> -
> -       if (INTEL_GEN(dev_priv) < 4) {
> -               /*
> -                * PLANE_A doesn't actually have a full window
> -                * generator but let's assume we still need to
> -                * program whatever is there.
> -                */
> -               intel_de_write_fw(dev_priv, DSPPOS(i9xx_plane),
> -                                 (crtc_y << 16) | crtc_x);
> -               intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane),
> -                                 ((crtc_h - 1) << 16) | (crtc_w - 1));
> -       } else if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
> -               intel_de_write_fw(dev_priv, PRIMPOS(i9xx_plane),
> -                                 (crtc_y << 16) | crtc_x);
> -               intel_de_write_fw(dev_priv, PRIMSIZE(i9xx_plane),
> -                                 ((crtc_h - 1) << 16) | (crtc_w - 1));
> -               intel_de_write_fw(dev_priv, PRIMCNSTALPHA(i9xx_plane), 0);
> -       }
> -
> -       if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
> -               intel_de_write_fw(dev_priv, DSPOFFSET(i9xx_plane),
> -                                 (y << 16) | x);
> -       } else if (INTEL_GEN(dev_priv) >= 4) {
> -               intel_de_write_fw(dev_priv, DSPLINOFF(i9xx_plane),
> -                                 linear_offset);
> -               intel_de_write_fw(dev_priv, DSPTILEOFF(i9xx_plane),
> -                                 (y << 16) | x);
> -       }
> -
> -       /*
> -        * The control register self-arms if the plane was previously
> -        * disabled. Try to make the plane enable atomic by writing
> -        * the control register just before the surface register.
> -        */
> -       intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
> -       if (INTEL_GEN(dev_priv) >= 4)
> -               intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
> -                                 intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
> -       else
> -               intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane),
> -                                 intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
> -
> -       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> -}
> -
> -static void i9xx_disable_plane(struct intel_plane *plane,
> -                              const struct intel_crtc_state *crtc_state)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> -       unsigned long irqflags;
> -       u32 dspcntr;
> -
> -       /*
> -        * DSPCNTR pipe gamma enable on g4x+ and pipe csc
> -        * enable on ilk+ affect the pipe bottom color as
> -        * well, so we must configure them even if the plane
> -        * is disabled.
> -        *
> -        * On pre-g4x there is no way to gamma correct the
> -        * pipe bottom color but we'll keep on doing this
> -        * anyway so that the crtc state readout works correctly.
> -        */
> -       dspcntr = i9xx_plane_ctl_crtc(crtc_state);
> -
> -       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> -
> -       intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
> -       if (INTEL_GEN(dev_priv) >= 4)
> -               intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0);
> -       else
> -               intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0);
> -
> -       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> -}
> -
> -static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
> -                                   enum pipe *pipe)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       enum intel_display_power_domain power_domain;
> -       enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
> -       intel_wakeref_t wakeref;
> -       bool ret;
> -       u32 val;
> -
> -       /*
> -        * Not 100% correct for planes that can move between pipes,
> -        * but that's only the case for gen2-4 which don't have any
> -        * display power wells.
> -        */
> -       power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> -       wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> -       if (!wakeref)
> -               return false;
> -
> -       val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane));
> -
> -       ret = val & DISPLAY_PLANE_ENABLE;
> -
> -       if (INTEL_GEN(dev_priv) >= 5)
> -               *pipe = plane->pipe;
> -       else
> -               *pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
> -                       DISPPLANE_SEL_PIPE_SHIFT;
> -
> -       intel_display_power_put(dev_priv, power_domain, wakeref);
> -
> -       return ret;
> -}
> -
>  static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
>  {
>         struct drm_device *dev = intel_crtc->base.dev;
> @@ -11919,33 +11457,6 @@ static void ilk_pch_clock_get(struct intel_crtc *crtc,
>                                          &pipe_config->fdi_m_n);
>  }
>
> -static void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
> -                                  struct intel_crtc *crtc)
> -{
> -       memset(crtc_state, 0, sizeof(*crtc_state));
> -
> -       __drm_atomic_helper_crtc_state_reset(&crtc_state->uapi, &crtc->base);
> -
> -       crtc_state->cpu_transcoder = INVALID_TRANSCODER;
> -       crtc_state->master_transcoder = INVALID_TRANSCODER;
> -       crtc_state->hsw_workaround_pipe = INVALID_PIPE;
> -       crtc_state->output_format = INTEL_OUTPUT_FORMAT_INVALID;
> -       crtc_state->scaler_state.scaler_id = -1;
> -       crtc_state->mst_master_transcoder = INVALID_TRANSCODER;
> -}
> -
> -static struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc)
> -{
> -       struct intel_crtc_state *crtc_state;
> -
> -       crtc_state = kmalloc(sizeof(*crtc_state), GFP_KERNEL);
> -
> -       if (crtc_state)
> -               intel_crtc_state_reset(crtc_state, crtc);
> -
> -       return crtc_state;
> -}
> -
>  /* Returns the currently programmed mode of the given encoder. */
>  struct drm_display_mode *
>  intel_encoder_current_mode(struct intel_encoder *encoder)
> @@ -11986,14 +11497,6 @@ intel_encoder_current_mode(struct intel_encoder *encoder)
>         return mode;
>  }
>
> -static void intel_crtc_destroy(struct drm_crtc *crtc)
> -{
> -       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -
> -       drm_crtc_cleanup(crtc);
> -       kfree(intel_crtc);
> -}
> -
>  /**
>   * intel_wm_need_update - Check whether watermarks need updating
>   * @cur: current plane state
> @@ -15197,17 +14700,6 @@ static int intel_atomic_prepare_commit(struct intel_atomic_state *state)
>         return 0;
>  }
>
> -u32 intel_crtc_get_vblank_counter(struct intel_crtc *crtc)
> -{
> -       struct drm_device *dev = crtc->base.dev;
> -       struct drm_vblank_crtc *vblank = &dev->vblank[drm_crtc_index(&crtc->base)];
> -
> -       if (!vblank->max_vblank_count)
> -               return (u32)drm_crtc_accurate_vblank_count(&crtc->base);
> -
> -       return crtc->base.funcs->get_vblank_counter(&crtc->base);
> -}
> -
>  void intel_crtc_arm_fifo_underrun(struct intel_crtc *crtc,
>                                   struct intel_crtc_state *crtc_state)
>  {
> @@ -16260,336 +15752,6 @@ void intel_plane_destroy(struct drm_plane *plane)
>         kfree(to_intel_plane(plane));
>  }
>
> -static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane,
> -                                           u32 format, u64 modifier)
> -{
> -       switch (modifier) {
> -       case DRM_FORMAT_MOD_LINEAR:
> -       case I915_FORMAT_MOD_X_TILED:
> -               break;
> -       default:
> -               return false;
> -       }
> -
> -       switch (format) {
> -       case DRM_FORMAT_C8:
> -       case DRM_FORMAT_RGB565:
> -       case DRM_FORMAT_XRGB1555:
> -       case DRM_FORMAT_XRGB8888:
> -               return modifier == DRM_FORMAT_MOD_LINEAR ||
> -                       modifier == I915_FORMAT_MOD_X_TILED;
> -       default:
> -               return false;
> -       }
> -}
> -
> -static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
> -                                           u32 format, u64 modifier)
> -{
> -       switch (modifier) {
> -       case DRM_FORMAT_MOD_LINEAR:
> -       case I915_FORMAT_MOD_X_TILED:
> -               break;
> -       default:
> -               return false;
> -       }
> -
> -       switch (format) {
> -       case DRM_FORMAT_C8:
> -       case DRM_FORMAT_RGB565:
> -       case DRM_FORMAT_XRGB8888:
> -       case DRM_FORMAT_XBGR8888:
> -       case DRM_FORMAT_ARGB8888:
> -       case DRM_FORMAT_ABGR8888:
> -       case DRM_FORMAT_XRGB2101010:
> -       case DRM_FORMAT_XBGR2101010:
> -       case DRM_FORMAT_ARGB2101010:
> -       case DRM_FORMAT_ABGR2101010:
> -       case DRM_FORMAT_XBGR16161616F:
> -               return modifier == DRM_FORMAT_MOD_LINEAR ||
> -                       modifier == I915_FORMAT_MOD_X_TILED;
> -       default:
> -               return false;
> -       }
> -}
> -
> -static const struct drm_plane_funcs i965_plane_funcs = {
> -       .update_plane = drm_atomic_helper_update_plane,
> -       .disable_plane = drm_atomic_helper_disable_plane,
> -       .destroy = intel_plane_destroy,
> -       .atomic_duplicate_state = intel_plane_duplicate_state,
> -       .atomic_destroy_state = intel_plane_destroy_state,
> -       .format_mod_supported = i965_plane_format_mod_supported,
> -};
> -
> -static const struct drm_plane_funcs i8xx_plane_funcs = {
> -       .update_plane = drm_atomic_helper_update_plane,
> -       .disable_plane = drm_atomic_helper_disable_plane,
> -       .destroy = intel_plane_destroy,
> -       .atomic_duplicate_state = intel_plane_duplicate_state,
> -       .atomic_destroy_state = intel_plane_destroy_state,
> -       .format_mod_supported = i8xx_plane_format_mod_supported,
> -};
> -
> -static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
> -                              enum i9xx_plane_id i9xx_plane)
> -{
> -       if (!HAS_FBC(dev_priv))
> -               return false;
> -
> -       if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> -               return i9xx_plane == PLANE_A; /* tied to pipe A */
> -       else if (IS_IVYBRIDGE(dev_priv))
> -               return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B ||
> -                       i9xx_plane == PLANE_C;
> -       else if (INTEL_GEN(dev_priv) >= 4)
> -               return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B;
> -       else
> -               return i9xx_plane == PLANE_A;
> -}
> -
> -static struct intel_plane *
> -intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
> -{
> -       struct intel_plane *plane;
> -       const struct drm_plane_funcs *plane_funcs;
> -       unsigned int supported_rotations;
> -       const u32 *formats;
> -       int num_formats;
> -       int ret, zpos;
> -
> -       if (INTEL_GEN(dev_priv) >= 9)
> -               return skl_universal_plane_create(dev_priv, pipe,
> -                                                 PLANE_PRIMARY);
> -
> -       plane = intel_plane_alloc();
> -       if (IS_ERR(plane))
> -               return plane;
> -
> -       plane->pipe = pipe;
> -       /*
> -        * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
> -        * port is hooked to pipe B. Hence we want plane A feeding pipe B.
> -        */
> -       if (HAS_FBC(dev_priv) && INTEL_GEN(dev_priv) < 4 &&
> -           INTEL_NUM_PIPES(dev_priv) == 2)
> -               plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
> -       else
> -               plane->i9xx_plane = (enum i9xx_plane_id) pipe;
> -       plane->id = PLANE_PRIMARY;
> -       plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
> -
> -       plane->has_fbc = i9xx_plane_has_fbc(dev_priv, plane->i9xx_plane);
> -       if (plane->has_fbc) {
> -               struct intel_fbc *fbc = &dev_priv->fbc;
> -
> -               fbc->possible_framebuffer_bits |= plane->frontbuffer_bit;
> -       }
> -
> -       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
> -               formats = vlv_primary_formats;
> -               num_formats = ARRAY_SIZE(vlv_primary_formats);
> -       } else if (INTEL_GEN(dev_priv) >= 4) {
> -               /*
> -                * WaFP16GammaEnabling:ivb
> -                * "Workaround : When using the 64-bit format, the plane
> -                *  output on each color channel has one quarter amplitude.
> -                *  It can be brought up to full amplitude by using pipe
> -                *  gamma correction or pipe color space conversion to
> -                *  multiply the plane output by four."
> -                *
> -                * There is no dedicated plane gamma for the primary plane,
> -                * and using the pipe gamma/csc could conflict with other
> -                * planes, so we choose not to expose fp16 on IVB primary
> -                * planes. HSW primary planes no longer have this problem.
> -                */
> -               if (IS_IVYBRIDGE(dev_priv)) {
> -                       formats = ivb_primary_formats;
> -                       num_formats = ARRAY_SIZE(ivb_primary_formats);
> -               } else {
> -                       formats = i965_primary_formats;
> -                       num_formats = ARRAY_SIZE(i965_primary_formats);
> -               }
> -       } else {
> -               formats = i8xx_primary_formats;
> -               num_formats = ARRAY_SIZE(i8xx_primary_formats);
> -       }
> -
> -       if (INTEL_GEN(dev_priv) >= 4)
> -               plane_funcs = &i965_plane_funcs;
> -       else
> -               plane_funcs = &i8xx_plane_funcs;
> -
> -       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> -               plane->min_cdclk = vlv_plane_min_cdclk;
> -       else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> -               plane->min_cdclk = hsw_plane_min_cdclk;
> -       else if (IS_IVYBRIDGE(dev_priv))
> -               plane->min_cdclk = ivb_plane_min_cdclk;
> -       else
> -               plane->min_cdclk = i9xx_plane_min_cdclk;
> -
> -       plane->max_stride = i9xx_plane_max_stride;
> -       plane->update_plane = i9xx_update_plane;
> -       plane->disable_plane = i9xx_disable_plane;
> -       plane->get_hw_state = i9xx_plane_get_hw_state;
> -       plane->check_plane = i9xx_plane_check;
> -
> -       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> -               ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
> -                                              0, plane_funcs,
> -                                              formats, num_formats,
> -                                              i9xx_format_modifiers,
> -                                              DRM_PLANE_TYPE_PRIMARY,
> -                                              "primary %c", pipe_name(pipe));
> -       else
> -               ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
> -                                              0, plane_funcs,
> -                                              formats, num_formats,
> -                                              i9xx_format_modifiers,
> -                                              DRM_PLANE_TYPE_PRIMARY,
> -                                              "plane %c",
> -                                              plane_name(plane->i9xx_plane));
> -       if (ret)
> -               goto fail;
> -
> -       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
> -               supported_rotations =
> -                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
> -                       DRM_MODE_REFLECT_X;
> -       } else if (INTEL_GEN(dev_priv) >= 4) {
> -               supported_rotations =
> -                       DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
> -       } else {
> -               supported_rotations = DRM_MODE_ROTATE_0;
> -       }
> -
> -       if (INTEL_GEN(dev_priv) >= 4)
> -               drm_plane_create_rotation_property(&plane->base,
> -                                                  DRM_MODE_ROTATE_0,
> -                                                  supported_rotations);
> -
> -       zpos = 0;
> -       drm_plane_create_zpos_immutable_property(&plane->base, zpos);
> -
> -       drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
> -
> -       return plane;
> -
> -fail:
> -       intel_plane_free(plane);
> -
> -       return ERR_PTR(ret);
> -}
> -
> -static int intel_crtc_late_register(struct drm_crtc *crtc)
> -{
> -       intel_crtc_debugfs_add(crtc);
> -       return 0;
> -}
> -
> -#define INTEL_CRTC_FUNCS \
> -       .gamma_set = drm_atomic_helper_legacy_gamma_set, \
> -       .set_config = drm_atomic_helper_set_config, \
> -       .destroy = intel_crtc_destroy, \
> -       .page_flip = drm_atomic_helper_page_flip, \
> -       .atomic_duplicate_state = intel_crtc_duplicate_state, \
> -       .atomic_destroy_state = intel_crtc_destroy_state, \
> -       .set_crc_source = intel_crtc_set_crc_source, \
> -       .verify_crc_source = intel_crtc_verify_crc_source, \
> -       .get_crc_sources = intel_crtc_get_crc_sources, \
> -       .late_register = intel_crtc_late_register
> -
> -static const struct drm_crtc_funcs bdw_crtc_funcs = {
> -       INTEL_CRTC_FUNCS,
> -
> -       .get_vblank_counter = g4x_get_vblank_counter,
> -       .enable_vblank = bdw_enable_vblank,
> -       .disable_vblank = bdw_disable_vblank,
> -       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> -};
> -
> -static const struct drm_crtc_funcs ilk_crtc_funcs = {
> -       INTEL_CRTC_FUNCS,
> -
> -       .get_vblank_counter = g4x_get_vblank_counter,
> -       .enable_vblank = ilk_enable_vblank,
> -       .disable_vblank = ilk_disable_vblank,
> -       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> -};
> -
> -static const struct drm_crtc_funcs g4x_crtc_funcs = {
> -       INTEL_CRTC_FUNCS,
> -
> -       .get_vblank_counter = g4x_get_vblank_counter,
> -       .enable_vblank = i965_enable_vblank,
> -       .disable_vblank = i965_disable_vblank,
> -       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> -};
> -
> -static const struct drm_crtc_funcs i965_crtc_funcs = {
> -       INTEL_CRTC_FUNCS,
> -
> -       .get_vblank_counter = i915_get_vblank_counter,
> -       .enable_vblank = i965_enable_vblank,
> -       .disable_vblank = i965_disable_vblank,
> -       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> -};
> -
> -static const struct drm_crtc_funcs i915gm_crtc_funcs = {
> -       INTEL_CRTC_FUNCS,
> -
> -       .get_vblank_counter = i915_get_vblank_counter,
> -       .enable_vblank = i915gm_enable_vblank,
> -       .disable_vblank = i915gm_disable_vblank,
> -       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> -};
> -
> -static const struct drm_crtc_funcs i915_crtc_funcs = {
> -       INTEL_CRTC_FUNCS,
> -
> -       .get_vblank_counter = i915_get_vblank_counter,
> -       .enable_vblank = i8xx_enable_vblank,
> -       .disable_vblank = i8xx_disable_vblank,
> -       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> -};
> -
> -static const struct drm_crtc_funcs i8xx_crtc_funcs = {
> -       INTEL_CRTC_FUNCS,
> -
> -       /* no hw vblank counter */
> -       .enable_vblank = i8xx_enable_vblank,
> -       .disable_vblank = i8xx_disable_vblank,
> -       .get_vblank_timestamp = intel_crtc_get_vblank_timestamp,
> -};
> -
> -static struct intel_crtc *intel_crtc_alloc(void)
> -{
> -       struct intel_crtc_state *crtc_state;
> -       struct intel_crtc *crtc;
> -
> -       crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
> -       if (!crtc)
> -               return ERR_PTR(-ENOMEM);
> -
> -       crtc_state = intel_crtc_state_alloc(crtc);
> -       if (!crtc_state) {
> -               kfree(crtc);
> -               return ERR_PTR(-ENOMEM);
> -       }
> -
> -       crtc->base.state = &crtc_state->uapi;
> -       crtc->config = crtc_state;
> -
> -       return crtc;
> -}
> -
> -static void intel_crtc_free(struct intel_crtc *crtc)
> -{
> -       intel_crtc_destroy_state(&crtc->base, crtc->base.state);
> -       kfree(crtc);
> -}
> -
>  static void intel_plane_possible_crtcs_init(struct drm_i915_private *dev_priv)
>  {
>         struct intel_plane *plane;
> @@ -16602,100 +15764,6 @@ static void intel_plane_possible_crtcs_init(struct drm_i915_private *dev_priv)
>         }
>  }
>
> -static int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe)
> -{
> -       struct intel_plane *primary, *cursor;
> -       const struct drm_crtc_funcs *funcs;
> -       struct intel_crtc *crtc;
> -       int sprite, ret;
> -
> -       crtc = intel_crtc_alloc();
> -       if (IS_ERR(crtc))
> -               return PTR_ERR(crtc);
> -
> -       crtc->pipe = pipe;
> -       crtc->num_scalers = RUNTIME_INFO(dev_priv)->num_scalers[pipe];
> -
> -       primary = intel_primary_plane_create(dev_priv, pipe);
> -       if (IS_ERR(primary)) {
> -               ret = PTR_ERR(primary);
> -               goto fail;
> -       }
> -       crtc->plane_ids_mask |= BIT(primary->id);
> -
> -       for_each_sprite(dev_priv, pipe, sprite) {
> -               struct intel_plane *plane;
> -
> -               plane = intel_sprite_plane_create(dev_priv, pipe, sprite);
> -               if (IS_ERR(plane)) {
> -                       ret = PTR_ERR(plane);
> -                       goto fail;
> -               }
> -               crtc->plane_ids_mask |= BIT(plane->id);
> -       }
> -
> -       cursor = intel_cursor_plane_create(dev_priv, pipe);
> -       if (IS_ERR(cursor)) {
> -               ret = PTR_ERR(cursor);
> -               goto fail;
> -       }
> -       crtc->plane_ids_mask |= BIT(cursor->id);
> -
> -       if (HAS_GMCH(dev_priv)) {
> -               if (IS_CHERRYVIEW(dev_priv) ||
> -                   IS_VALLEYVIEW(dev_priv) || IS_G4X(dev_priv))
> -                       funcs = &g4x_crtc_funcs;
> -               else if (IS_GEN(dev_priv, 4))
> -                       funcs = &i965_crtc_funcs;
> -               else if (IS_I945GM(dev_priv) || IS_I915GM(dev_priv))
> -                       funcs = &i915gm_crtc_funcs;
> -               else if (IS_GEN(dev_priv, 3))
> -                       funcs = &i915_crtc_funcs;
> -               else
> -                       funcs = &i8xx_crtc_funcs;
> -       } else {
> -               if (INTEL_GEN(dev_priv) >= 8)
> -                       funcs = &bdw_crtc_funcs;
> -               else
> -                       funcs = &ilk_crtc_funcs;
> -       }
> -
> -       ret = drm_crtc_init_with_planes(&dev_priv->drm, &crtc->base,
> -                                       &primary->base, &cursor->base,
> -                                       funcs, "pipe %c", pipe_name(pipe));
> -       if (ret)
> -               goto fail;
> -
> -       BUG_ON(pipe >= ARRAY_SIZE(dev_priv->pipe_to_crtc_mapping) ||
> -              dev_priv->pipe_to_crtc_mapping[pipe] != NULL);
> -       dev_priv->pipe_to_crtc_mapping[pipe] = crtc;
> -
> -       if (INTEL_GEN(dev_priv) < 9) {
> -               enum i9xx_plane_id i9xx_plane = primary->i9xx_plane;
> -
> -               BUG_ON(i9xx_plane >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
> -                      dev_priv->plane_to_crtc_mapping[i9xx_plane] != NULL);
> -               dev_priv->plane_to_crtc_mapping[i9xx_plane] = crtc;
> -       }
> -
> -       if (INTEL_GEN(dev_priv) >= 10)
> -               drm_crtc_create_scaling_filter_property(&crtc->base,
> -                                               BIT(DRM_SCALING_FILTER_DEFAULT) |
> -                                               BIT(DRM_SCALING_FILTER_NEAREST_NEIGHBOR));
> -
> -       intel_color_init(crtc);
> -
> -       intel_crtc_crc_init(crtc);
> -
> -       drm_WARN_ON(&dev_priv->drm, drm_crtc_index(&crtc->base) != crtc->pipe);
> -
> -       return 0;
> -
> -fail:
> -       intel_crtc_free(crtc);
> -
> -       return ret;
> -}
>
>  int intel_get_pipe_from_crtc_id_ioctl(struct drm_device *dev, void *data,
>                                       struct drm_file *file)
> diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
> index f0a5bf69656f..0eba91d18e96 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.h
> +++ b/drivers/gpu/drm/i915/display/intel_display.h
> @@ -659,6 +659,13 @@ struct intel_plane *
>  intel_cursor_plane_create(struct drm_i915_private *dev_priv,
>                           enum pipe pipe);
>
> +/* crtc */
> +u32 intel_crtc_max_vblank_count(const struct intel_crtc_state *crtc_state);
> +int intel_crtc_init(struct drm_i915_private *dev_priv, enum pipe pipe);
> +struct intel_crtc_state *intel_crtc_state_alloc(struct intel_crtc *crtc);
> +void intel_crtc_state_reset(struct intel_crtc_state *crtc_state,
> +                           struct intel_crtc *crtc);
> +
>  /* modesetting */
>  void intel_modeset_init_hw(struct drm_i915_private *i915);
>  int intel_modeset_init_noirq(struct drm_i915_private *i915);
> --
> 2.27.0
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Intel-gfx] [PATCH 1/4] drm/i915: refactor cursor code out of i915_display.c
  2020-12-09  4:21 ` [Intel-gfx] [PATCH 1/4] drm/i915: refactor cursor code out of i915_display.c Dave Airlie
@ 2020-12-09 11:07   ` Daniel Vetter
  0 siblings, 0 replies; 13+ messages in thread
From: Daniel Vetter @ 2020-12-09 11:07 UTC (permalink / raw)
  To: Dave Airlie; +Cc: intel-gfx

On Wed, Dec 9, 2020 at 5:21 AM Dave Airlie <airlied@gmail.com> wrote:
>
> From: Dave Airlie <airlied@redhat.com>
>
> This file is a monster, let's start simple, the cursor plane code
> seems pretty standalone, and splits out easily enough.
>
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> ---
>  drivers/gpu/drm/i915/Makefile                |   1 +
>  drivers/gpu/drm/i915/display/intel_cursor.c  | 817 +++++++++++++++++++
>  drivers/gpu/drm/i915/display/intel_display.c | 796 +-----------------
>  drivers/gpu/drm/i915/display/intel_display.h |  12 +
>  4 files changed, 836 insertions(+), 790 deletions(-)
>  create mode 100644 drivers/gpu/drm/i915/display/intel_cursor.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index e5574e506a5c..98a35b939052 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -197,6 +197,7 @@ i915-y += \
>         display/intel_combo_phy.o \
>         display/intel_connector.o \
>         display/intel_csr.o \
> +       display/intel_cursor.o \
>         display/intel_display.o \
>         display/intel_display_power.o \
>         display/intel_dpio_phy.o \
> diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
> new file mode 100644
> index 000000000000..d69eac067255
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/display/intel_cursor.c
> @@ -0,0 +1,817 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2020 Intel Corporation
> + */
> +#include <linux/kernel.h>
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_damage_helper.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drm_fourcc.h>
> +
> +#include "intel_atomic.h"
> +#include "intel_atomic_plane.h"
> +#include "intel_display_types.h"
> +#include "intel_display.h"
> +
> +#include "intel_frontbuffer.h"
> +#include "intel_pm.h"
> +#include "intel_psr.h"
> +#include "intel_sprite.h"
> +
> +/* Cursor formats */
> +static const u32 intel_cursor_formats[] = {
> +       DRM_FORMAT_ARGB8888,
> +};
> +
> +static const u64 cursor_format_modifiers[] = {
> +       DRM_FORMAT_MOD_LINEAR,
> +       DRM_FORMAT_MOD_INVALID
> +};
> +
> +static bool
> +needs_modeset(const struct intel_crtc_state *state)
> +{
> +       return drm_atomic_crtc_needs_modeset(&state->uapi);
> +}

I think this should be a static inline in intel_crct.h or something?
Feels wrong to duplicate them.

> +
> +static struct intel_frontbuffer *
> +to_intel_frontbuffer(struct drm_framebuffer *fb)
> +{
> +       return fb ? to_intel_framebuffer(fb)->frontbuffer : NULL;
> +}

Same here, fb_to_intel_frontbuffer or so somewhere in a header.

Otherwise looks reasonable, but see the discussion on plane code
placement in general in the next patch.
-Daniel

> +
> +static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
> +{
> +       struct drm_i915_private *dev_priv =
> +               to_i915(plane_state->uapi.plane->dev);
> +       const struct drm_framebuffer *fb = plane_state->hw.fb;
> +       const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
> +       u32 base;
> +
> +       if (INTEL_INFO(dev_priv)->display.cursor_needs_physical)
> +               base = sg_dma_address(obj->mm.pages->sgl);
> +       else
> +               base = intel_plane_ggtt_offset(plane_state);
> +
> +       return base + plane_state->color_plane[0].offset;
> +}
> +
> +static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
> +{
> +       int x = plane_state->uapi.dst.x1;
> +       int y = plane_state->uapi.dst.y1;
> +       u32 pos = 0;
> +
> +       if (x < 0) {
> +               pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
> +               x = -x;
> +       }
> +       pos |= x << CURSOR_X_SHIFT;
> +
> +       if (y < 0) {
> +               pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
> +               y = -y;
> +       }
> +       pos |= y << CURSOR_Y_SHIFT;
> +
> +       return pos;
> +}
> +
> +static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
> +{
> +       const struct drm_mode_config *config =
> +               &plane_state->uapi.plane->dev->mode_config;
> +       int width = drm_rect_width(&plane_state->uapi.dst);
> +       int height = drm_rect_height(&plane_state->uapi.dst);
> +
> +       return width > 0 && width <= config->cursor_width &&
> +               height > 0 && height <= config->cursor_height;
> +}
> +
> +static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
> +{
> +       struct drm_i915_private *dev_priv =
> +               to_i915(plane_state->uapi.plane->dev);
> +       unsigned int rotation = plane_state->hw.rotation;
> +       int src_x, src_y;
> +       u32 offset;
> +       int ret;
> +
> +       ret = intel_plane_compute_gtt(plane_state);
> +       if (ret)
> +               return ret;
> +
> +       if (!plane_state->uapi.visible)
> +               return 0;
> +
> +       src_x = plane_state->uapi.src.x1 >> 16;
> +       src_y = plane_state->uapi.src.y1 >> 16;
> +
> +       intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
> +       offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
> +                                                   plane_state, 0);
> +
> +       if (src_x != 0 || src_y != 0) {
> +               drm_dbg_kms(&dev_priv->drm,
> +                           "Arbitrary cursor panning not supported\n");
> +               return -EINVAL;
> +       }
> +
> +       /*
> +        * Put the final coordinates back so that the src
> +        * coordinate checks will see the right values.
> +        */
> +       drm_rect_translate_to(&plane_state->uapi.src,
> +                             src_x << 16, src_y << 16);
> +
> +       /* ILK+ do this automagically in hardware */
> +       if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) {
> +               const struct drm_framebuffer *fb = plane_state->hw.fb;
> +               int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
> +               int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
> +
> +               offset += (src_h * src_w - 1) * fb->format->cpp[0];
> +       }
> +
> +       plane_state->color_plane[0].offset = offset;
> +       plane_state->color_plane[0].x = src_x;
> +       plane_state->color_plane[0].y = src_y;
> +
> +       return 0;
> +}
> +
> +static int intel_check_cursor(struct intel_crtc_state *crtc_state,
> +                             struct intel_plane_state *plane_state)
> +{
> +       const struct drm_framebuffer *fb = plane_state->hw.fb;
> +       struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
> +       const struct drm_rect src = plane_state->uapi.src;
> +       const struct drm_rect dst = plane_state->uapi.dst;
> +       int ret;
> +
> +       if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
> +               drm_dbg_kms(&i915->drm, "cursor cannot be tiled\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
> +                                               DRM_PLANE_HELPER_NO_SCALING,
> +                                               DRM_PLANE_HELPER_NO_SCALING,
> +                                               true);
> +       if (ret)
> +               return ret;
> +
> +       /* Use the unclipped src/dst rectangles, which we program to hw */
> +       plane_state->uapi.src = src;
> +       plane_state->uapi.dst = dst;
> +
> +       ret = intel_cursor_check_surface(plane_state);
> +       if (ret)
> +               return ret;
> +
> +       if (!plane_state->uapi.visible)
> +               return 0;
> +
> +       ret = intel_plane_check_src_coordinates(plane_state);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +static unsigned int
> +i845_cursor_max_stride(struct intel_plane *plane,
> +                      u32 pixel_format, u64 modifier,
> +                      unsigned int rotation)
> +{
> +       return 2048;
> +}
> +
> +static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
> +{
> +       u32 cntl = 0;
> +
> +       if (crtc_state->gamma_enable)
> +               cntl |= CURSOR_GAMMA_ENABLE;
> +
> +       return cntl;
> +}
> +
> +static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
> +                          const struct intel_plane_state *plane_state)
> +{
> +       return CURSOR_ENABLE |
> +               CURSOR_FORMAT_ARGB |
> +               CURSOR_STRIDE(plane_state->color_plane[0].stride);
> +}
> +
> +static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
> +{
> +       int width = drm_rect_width(&plane_state->uapi.dst);
> +
> +       /*
> +        * 845g/865g are only limited by the width of their cursors,
> +        * the height is arbitrary up to the precision of the register.
> +        */
> +       return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64);
> +}
> +
> +static int i845_check_cursor(struct intel_crtc_state *crtc_state,
> +                            struct intel_plane_state *plane_state)
> +{
> +       const struct drm_framebuffer *fb = plane_state->hw.fb;
> +       struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
> +       int ret;
> +
> +       ret = intel_check_cursor(crtc_state, plane_state);
> +       if (ret)
> +               return ret;
> +
> +       /* if we want to turn off the cursor ignore width and height */
> +       if (!fb)
> +               return 0;
> +
> +       /* Check for which cursor types we support */
> +       if (!i845_cursor_size_ok(plane_state)) {
> +               drm_dbg_kms(&i915->drm,
> +                           "Cursor dimension %dx%d not supported\n",
> +                           drm_rect_width(&plane_state->uapi.dst),
> +                           drm_rect_height(&plane_state->uapi.dst));
> +               return -EINVAL;
> +       }
> +
> +       drm_WARN_ON(&i915->drm, plane_state->uapi.visible &&
> +                   plane_state->color_plane[0].stride != fb->pitches[0]);
> +
> +       switch (fb->pitches[0]) {
> +       case 256:
> +       case 512:
> +       case 1024:
> +       case 2048:
> +               break;
> +       default:
> +                drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n",
> +                            fb->pitches[0]);
> +               return -EINVAL;
> +       }
> +
> +       plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
> +
> +       return 0;
> +}
> +
> +static void i845_update_cursor(struct intel_plane *plane,
> +                              const struct intel_crtc_state *crtc_state,
> +                              const struct intel_plane_state *plane_state)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       u32 cntl = 0, base = 0, pos = 0, size = 0;
> +       unsigned long irqflags;
> +
> +       if (plane_state && plane_state->uapi.visible) {
> +               unsigned int width = drm_rect_width(&plane_state->uapi.dst);
> +               unsigned int height = drm_rect_height(&plane_state->uapi.dst);
> +
> +               cntl = plane_state->ctl |
> +                       i845_cursor_ctl_crtc(crtc_state);
> +
> +               size = (height << 12) | width;
> +
> +               base = intel_cursor_base(plane_state);
> +               pos = intel_cursor_position(plane_state);
> +       }
> +
> +       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> +
> +       /* On these chipsets we can only modify the base/size/stride
> +        * whilst the cursor is disabled.
> +        */
> +       if (plane->cursor.base != base ||
> +           plane->cursor.size != size ||
> +           plane->cursor.cntl != cntl) {
> +               intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), 0);
> +               intel_de_write_fw(dev_priv, CURBASE(PIPE_A), base);
> +               intel_de_write_fw(dev_priv, CURSIZE, size);
> +               intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
> +               intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), cntl);
> +
> +               plane->cursor.base = base;
> +               plane->cursor.size = size;
> +               plane->cursor.cntl = cntl;
> +       } else {
> +               intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
> +       }
> +
> +       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> +}
> +
> +static void i845_disable_cursor(struct intel_plane *plane,
> +                               const struct intel_crtc_state *crtc_state)
> +{
> +       i845_update_cursor(plane, crtc_state, NULL);
> +}
> +
> +static bool i845_cursor_get_hw_state(struct intel_plane *plane,
> +                                    enum pipe *pipe)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       enum intel_display_power_domain power_domain;
> +       intel_wakeref_t wakeref;
> +       bool ret;
> +
> +       power_domain = POWER_DOMAIN_PIPE(PIPE_A);
> +       wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +       if (!wakeref)
> +               return false;
> +
> +       ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE;
> +
> +       *pipe = PIPE_A;
> +
> +       intel_display_power_put(dev_priv, power_domain, wakeref);
> +
> +       return ret;
> +}
> +
> +static unsigned int
> +i9xx_cursor_max_stride(struct intel_plane *plane,
> +                      u32 pixel_format, u64 modifier,
> +                      unsigned int rotation)
> +{
> +       return plane->base.dev->mode_config.cursor_width * 4;
> +}
> +
> +static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
> +{
> +       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> +       u32 cntl = 0;
> +
> +       if (INTEL_GEN(dev_priv) >= 11)
> +               return cntl;
> +
> +       if (crtc_state->gamma_enable)
> +               cntl = MCURSOR_GAMMA_ENABLE;
> +
> +       if (crtc_state->csc_enable)
> +               cntl |= MCURSOR_PIPE_CSC_ENABLE;
> +
> +       if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
> +               cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
> +
> +       return cntl;
> +}
> +
> +static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
> +                          const struct intel_plane_state *plane_state)
> +{
> +       struct drm_i915_private *dev_priv =
> +               to_i915(plane_state->uapi.plane->dev);
> +       u32 cntl = 0;
> +
> +       if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
> +               cntl |= MCURSOR_TRICKLE_FEED_DISABLE;
> +
> +       switch (drm_rect_width(&plane_state->uapi.dst)) {
> +       case 64:
> +               cntl |= MCURSOR_MODE_64_ARGB_AX;
> +               break;
> +       case 128:
> +               cntl |= MCURSOR_MODE_128_ARGB_AX;
> +               break;
> +       case 256:
> +               cntl |= MCURSOR_MODE_256_ARGB_AX;
> +               break;
> +       default:
> +               MISSING_CASE(drm_rect_width(&plane_state->uapi.dst));
> +               return 0;
> +       }
> +
> +       if (plane_state->hw.rotation & DRM_MODE_ROTATE_180)
> +               cntl |= MCURSOR_ROTATE_180;
> +
> +       return cntl;
> +}
> +
> +static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
> +{
> +       struct drm_i915_private *dev_priv =
> +               to_i915(plane_state->uapi.plane->dev);
> +       int width = drm_rect_width(&plane_state->uapi.dst);
> +       int height = drm_rect_height(&plane_state->uapi.dst);
> +
> +       if (!intel_cursor_size_ok(plane_state))
> +               return false;
> +
> +       /* Cursor width is limited to a few power-of-two sizes */
> +       switch (width) {
> +       case 256:
> +       case 128:
> +       case 64:
> +               break;
> +       default:
> +               return false;
> +       }
> +
> +       /*
> +        * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor
> +        * height from 8 lines up to the cursor width, when the
> +        * cursor is not rotated. Everything else requires square
> +        * cursors.
> +        */
> +       if (HAS_CUR_FBC(dev_priv) &&
> +           plane_state->hw.rotation & DRM_MODE_ROTATE_0) {
> +               if (height < 8 || height > width)
> +                       return false;
> +       } else {
> +               if (height != width)
> +                       return false;
> +       }
> +
> +       return true;
> +}
> +
> +static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
> +                            struct intel_plane_state *plane_state)
> +{
> +       struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       const struct drm_framebuffer *fb = plane_state->hw.fb;
> +       enum pipe pipe = plane->pipe;
> +       int ret;
> +
> +       ret = intel_check_cursor(crtc_state, plane_state);
> +       if (ret)
> +               return ret;
> +
> +       /* if we want to turn off the cursor ignore width and height */
> +       if (!fb)
> +               return 0;
> +
> +       /* Check for which cursor types we support */
> +       if (!i9xx_cursor_size_ok(plane_state)) {
> +               drm_dbg(&dev_priv->drm,
> +                       "Cursor dimension %dx%d not supported\n",
> +                       drm_rect_width(&plane_state->uapi.dst),
> +                       drm_rect_height(&plane_state->uapi.dst));
> +               return -EINVAL;
> +       }
> +
> +       drm_WARN_ON(&dev_priv->drm, plane_state->uapi.visible &&
> +                   plane_state->color_plane[0].stride != fb->pitches[0]);
> +
> +       if (fb->pitches[0] !=
> +           drm_rect_width(&plane_state->uapi.dst) * fb->format->cpp[0]) {
> +               drm_dbg_kms(&dev_priv->drm,
> +                           "Invalid cursor stride (%u) (cursor width %d)\n",
> +                           fb->pitches[0],
> +                           drm_rect_width(&plane_state->uapi.dst));
> +               return -EINVAL;
> +       }
> +
> +       /*
> +        * There's something wrong with the cursor on CHV pipe C.
> +        * If it straddles the left edge of the screen then
> +        * moving it away from the edge or disabling it often
> +        * results in a pipe underrun, and often that can lead to
> +        * dead pipe (constant underrun reported, and it scans
> +        * out just a solid color). To recover from that, the
> +        * display power well must be turned off and on again.
> +        * Refuse the put the cursor into that compromised position.
> +        */
> +       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
> +           plane_state->uapi.visible && plane_state->uapi.dst.x1 < 0) {
> +               drm_dbg_kms(&dev_priv->drm,
> +                           "CHV cursor C not allowed to straddle the left screen edge\n");
> +               return -EINVAL;
> +       }
> +
> +       plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
> +
> +       return 0;
> +}
> +
> +static void i9xx_update_cursor(struct intel_plane *plane,
> +                              const struct intel_crtc_state *crtc_state,
> +                              const struct intel_plane_state *plane_state)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       enum pipe pipe = plane->pipe;
> +       u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
> +       unsigned long irqflags;
> +
> +       if (plane_state && plane_state->uapi.visible) {
> +               unsigned width = drm_rect_width(&plane_state->uapi.dst);
> +               unsigned height = drm_rect_height(&plane_state->uapi.dst);
> +
> +               cntl = plane_state->ctl |
> +                       i9xx_cursor_ctl_crtc(crtc_state);
> +
> +               if (width != height)
> +                       fbc_ctl = CUR_FBC_CTL_EN | (height - 1);
> +
> +               base = intel_cursor_base(plane_state);
> +               pos = intel_cursor_position(plane_state);
> +       }
> +
> +       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> +
> +       /*
> +        * On some platforms writing CURCNTR first will also
> +        * cause CURPOS to be armed by the CURBASE write.
> +        * Without the CURCNTR write the CURPOS write would
> +        * arm itself. Thus we always update CURCNTR before
> +        * CURPOS.
> +        *
> +        * On other platforms CURPOS always requires the
> +        * CURBASE write to arm the update. Additonally
> +        * a write to any of the cursor register will cancel
> +        * an already armed cursor update. Thus leaving out
> +        * the CURBASE write after CURPOS could lead to a
> +        * cursor that doesn't appear to move, or even change
> +        * shape. Thus we always write CURBASE.
> +        *
> +        * The other registers are armed by by the CURBASE write
> +        * except when the plane is getting enabled at which time
> +        * the CURCNTR write arms the update.
> +        */
> +
> +       if (INTEL_GEN(dev_priv) >= 9)
> +               skl_write_cursor_wm(plane, crtc_state);
> +
> +       if (!needs_modeset(crtc_state))
> +               intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0);
> +
> +       if (plane->cursor.base != base ||
> +           plane->cursor.size != fbc_ctl ||
> +           plane->cursor.cntl != cntl) {
> +               if (HAS_CUR_FBC(dev_priv))
> +                       intel_de_write_fw(dev_priv, CUR_FBC_CTL(pipe),
> +                                         fbc_ctl);
> +               intel_de_write_fw(dev_priv, CURCNTR(pipe), cntl);
> +               intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
> +               intel_de_write_fw(dev_priv, CURBASE(pipe), base);
> +
> +               plane->cursor.base = base;
> +               plane->cursor.size = fbc_ctl;
> +               plane->cursor.cntl = cntl;
> +       } else {
> +               intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
> +               intel_de_write_fw(dev_priv, CURBASE(pipe), base);
> +       }
> +
> +       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> +}
> +
> +static void i9xx_disable_cursor(struct intel_plane *plane,
> +                               const struct intel_crtc_state *crtc_state)
> +{
> +       i9xx_update_cursor(plane, crtc_state, NULL);
> +}
> +
> +static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
> +                                    enum pipe *pipe)
> +{
> +       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> +       enum intel_display_power_domain power_domain;
> +       intel_wakeref_t wakeref;
> +       bool ret;
> +       u32 val;
> +
> +       /*
> +        * Not 100% correct for planes that can move between pipes,
> +        * but that's only the case for gen2-3 which don't have any
> +        * display power wells.
> +        */
> +       power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> +       wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> +       if (!wakeref)
> +               return false;
> +
> +       val = intel_de_read(dev_priv, CURCNTR(plane->pipe));
> +
> +       ret = val & MCURSOR_MODE;
> +
> +       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> +               *pipe = plane->pipe;
> +       else
> +               *pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
> +                       MCURSOR_PIPE_SELECT_SHIFT;
> +
> +       intel_display_power_put(dev_priv, power_domain, wakeref);
> +
> +       return ret;
> +}
> +
> +static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
> +                                             u32 format, u64 modifier)
> +{
> +       return modifier == DRM_FORMAT_MOD_LINEAR &&
> +               format == DRM_FORMAT_ARGB8888;
> +}
> +
> +static int
> +intel_legacy_cursor_update(struct drm_plane *_plane,
> +                          struct drm_crtc *_crtc,
> +                          struct drm_framebuffer *fb,
> +                          int crtc_x, int crtc_y,
> +                          unsigned int crtc_w, unsigned int crtc_h,
> +                          u32 src_x, u32 src_y,
> +                          u32 src_w, u32 src_h,
> +                          struct drm_modeset_acquire_ctx *ctx)
> +{
> +       struct intel_plane *plane = to_intel_plane(_plane);
> +       struct intel_crtc *crtc = to_intel_crtc(_crtc);
> +       struct intel_plane_state *old_plane_state =
> +               to_intel_plane_state(plane->base.state);
> +       struct intel_plane_state *new_plane_state;
> +       struct intel_crtc_state *crtc_state =
> +               to_intel_crtc_state(crtc->base.state);
> +       struct intel_crtc_state *new_crtc_state;
> +       int ret;
> +
> +       /*
> +        * When crtc is inactive or there is a modeset pending,
> +        * wait for it to complete in the slowpath
> +        *
> +        * FIXME bigjoiner fastpath would be good
> +        */
> +       if (!crtc_state->hw.active || needs_modeset(crtc_state) ||
> +           crtc_state->update_pipe || crtc_state->bigjoiner)
> +               goto slow;
> +
> +       /*
> +        * Don't do an async update if there is an outstanding commit modifying
> +        * the plane.  This prevents our async update's changes from getting
> +        * overridden by a previous synchronous update's state.
> +        */
> +       if (old_plane_state->uapi.commit &&
> +           !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done))
> +               goto slow;
> +
> +       /*
> +        * If any parameters change that may affect watermarks,
> +        * take the slowpath. Only changing fb or position should be
> +        * in the fastpath.
> +        */
> +       if (old_plane_state->uapi.crtc != &crtc->base ||
> +           old_plane_state->uapi.src_w != src_w ||
> +           old_plane_state->uapi.src_h != src_h ||
> +           old_plane_state->uapi.crtc_w != crtc_w ||
> +           old_plane_state->uapi.crtc_h != crtc_h ||
> +           !old_plane_state->uapi.fb != !fb)
> +               goto slow;
> +
> +       new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base));
> +       if (!new_plane_state)
> +               return -ENOMEM;
> +
> +       new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base));
> +       if (!new_crtc_state) {
> +               ret = -ENOMEM;
> +               goto out_free;
> +       }
> +
> +       drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb);
> +
> +       new_plane_state->uapi.src_x = src_x;
> +       new_plane_state->uapi.src_y = src_y;
> +       new_plane_state->uapi.src_w = src_w;
> +       new_plane_state->uapi.src_h = src_h;
> +       new_plane_state->uapi.crtc_x = crtc_x;
> +       new_plane_state->uapi.crtc_y = crtc_y;
> +       new_plane_state->uapi.crtc_w = crtc_w;
> +       new_plane_state->uapi.crtc_h = crtc_h;
> +
> +       intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc);
> +
> +       ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
> +                                                 old_plane_state, new_plane_state);
> +       if (ret)
> +               goto out_free;
> +
> +       ret = intel_plane_pin_fb(new_plane_state);
> +       if (ret)
> +               goto out_free;
> +
> +       intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb),
> +                               ORIGIN_FLIP);
> +       intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb),
> +                               to_intel_frontbuffer(new_plane_state->hw.fb),
> +                               plane->frontbuffer_bit);
> +
> +       /* Swap plane state */
> +       plane->base.state = &new_plane_state->uapi;
> +
> +       /*
> +        * We cannot swap crtc_state as it may be in use by an atomic commit or
> +        * page flip that's running simultaneously. If we swap crtc_state and
> +        * destroy the old state, we will cause a use-after-free there.
> +        *
> +        * Only update active_planes, which is needed for our internal
> +        * bookkeeping. Either value will do the right thing when updating
> +        * planes atomically. If the cursor was part of the atomic update then
> +        * we would have taken the slowpath.
> +        */
> +       crtc_state->active_planes = new_crtc_state->active_planes;
> +
> +       if (new_plane_state->uapi.visible)
> +               intel_update_plane(plane, crtc_state, new_plane_state);
> +       else
> +               intel_disable_plane(plane, crtc_state);
> +
> +       intel_plane_unpin_fb(old_plane_state);
> +
> +out_free:
> +       if (new_crtc_state)
> +               intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi);
> +       if (ret)
> +               intel_plane_destroy_state(&plane->base, &new_plane_state->uapi);
> +       else
> +               intel_plane_destroy_state(&plane->base, &old_plane_state->uapi);
> +       return ret;
> +
> +slow:
> +       return drm_atomic_helper_update_plane(&plane->base, &crtc->base, fb,
> +                                             crtc_x, crtc_y, crtc_w, crtc_h,
> +                                             src_x, src_y, src_w, src_h, ctx);
> +}
> +
> +static const struct drm_plane_funcs intel_cursor_plane_funcs = {
> +       .update_plane = intel_legacy_cursor_update,
> +       .disable_plane = drm_atomic_helper_disable_plane,
> +       .destroy = intel_plane_destroy,
> +       .atomic_duplicate_state = intel_plane_duplicate_state,
> +       .atomic_destroy_state = intel_plane_destroy_state,
> +       .format_mod_supported = intel_cursor_format_mod_supported,
> +};
> +
> +struct intel_plane *
> +intel_cursor_plane_create(struct drm_i915_private *dev_priv,
> +                         enum pipe pipe)
> +{
> +       struct intel_plane *cursor;
> +       int ret, zpos;
> +
> +       cursor = intel_plane_alloc();
> +       if (IS_ERR(cursor))
> +               return cursor;
> +
> +       cursor->pipe = pipe;
> +       cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
> +       cursor->id = PLANE_CURSOR;
> +       cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
> +
> +       if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
> +               cursor->max_stride = i845_cursor_max_stride;
> +               cursor->update_plane = i845_update_cursor;
> +               cursor->disable_plane = i845_disable_cursor;
> +               cursor->get_hw_state = i845_cursor_get_hw_state;
> +               cursor->check_plane = i845_check_cursor;
> +       } else {
> +               cursor->max_stride = i9xx_cursor_max_stride;
> +               cursor->update_plane = i9xx_update_cursor;
> +               cursor->disable_plane = i9xx_disable_cursor;
> +               cursor->get_hw_state = i9xx_cursor_get_hw_state;
> +               cursor->check_plane = i9xx_check_cursor;
> +       }
> +
> +       cursor->cursor.base = ~0;
> +       cursor->cursor.cntl = ~0;
> +
> +       if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
> +               cursor->cursor.size = ~0;
> +
> +       ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
> +                                      0, &intel_cursor_plane_funcs,
> +                                      intel_cursor_formats,
> +                                      ARRAY_SIZE(intel_cursor_formats),
> +                                      cursor_format_modifiers,
> +                                      DRM_PLANE_TYPE_CURSOR,
> +                                      "cursor %c", pipe_name(pipe));
> +       if (ret)
> +               goto fail;
> +
> +       if (INTEL_GEN(dev_priv) >= 4)
> +               drm_plane_create_rotation_property(&cursor->base,
> +                                                  DRM_MODE_ROTATE_0,
> +                                                  DRM_MODE_ROTATE_0 |
> +                                                  DRM_MODE_ROTATE_180);
> +
> +       zpos = RUNTIME_INFO(dev_priv)->num_sprites[pipe] + 1;
> +       drm_plane_create_zpos_immutable_property(&cursor->base, zpos);
> +
> +       if (INTEL_GEN(dev_priv) >= 12)
> +               drm_plane_enable_fb_damage_clips(&cursor->base);
> +
> +       drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
> +
> +       return cursor;
> +
> +fail:
> +       intel_plane_free(cursor);
> +
> +       return ERR_PTR(ret);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index c567c0cada7e..0a3b97889248 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -137,16 +137,6 @@ static const u64 i9xx_format_modifiers[] = {
>         DRM_FORMAT_MOD_INVALID
>  };
>
> -/* Cursor formats */
> -static const u32 intel_cursor_formats[] = {
> -       DRM_FORMAT_ARGB8888,
> -};
> -
> -static const u64 cursor_format_modifiers[] = {
> -       DRM_FORMAT_MOD_LINEAR,
> -       DRM_FORMAT_MOD_INVALID
> -};
> -
>  static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
>                                 struct intel_crtc_state *pipe_config);
>  static void ilk_pch_clock_get(struct intel_crtc *crtc,
> @@ -2533,9 +2523,9 @@ static u32 intel_compute_aligned_offset(struct drm_i915_private *dev_priv,
>         return offset_aligned;
>  }
>
> -static u32 intel_plane_compute_aligned_offset(int *x, int *y,
> -                                             const struct intel_plane_state *state,
> -                                             int color_plane)
> +u32 intel_plane_compute_aligned_offset(int *x, int *y,
> +                                      const struct intel_plane_state *state,
> +                                      int color_plane)
>  {
>         struct intel_plane *intel_plane = to_intel_plane(state->uapi.plane);
>         struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
> @@ -3272,7 +3262,7 @@ intel_plane_remap_gtt(struct intel_plane_state *plane_state)
>         }
>  }
>
> -static int
> +int
>  intel_plane_compute_gtt(struct intel_plane_state *plane_state)
>  {
>         const struct intel_framebuffer *fb =
> @@ -11547,569 +11537,6 @@ static bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state)
>         return true;
>  }
>
> -static u32 intel_cursor_base(const struct intel_plane_state *plane_state)
> -{
> -       struct drm_i915_private *dev_priv =
> -               to_i915(plane_state->uapi.plane->dev);
> -       const struct drm_framebuffer *fb = plane_state->hw.fb;
> -       const struct drm_i915_gem_object *obj = intel_fb_obj(fb);
> -       u32 base;
> -
> -       if (INTEL_INFO(dev_priv)->display.cursor_needs_physical)
> -               base = sg_dma_address(obj->mm.pages->sgl);
> -       else
> -               base = intel_plane_ggtt_offset(plane_state);
> -
> -       return base + plane_state->color_plane[0].offset;
> -}
> -
> -static u32 intel_cursor_position(const struct intel_plane_state *plane_state)
> -{
> -       int x = plane_state->uapi.dst.x1;
> -       int y = plane_state->uapi.dst.y1;
> -       u32 pos = 0;
> -
> -       if (x < 0) {
> -               pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
> -               x = -x;
> -       }
> -       pos |= x << CURSOR_X_SHIFT;
> -
> -       if (y < 0) {
> -               pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
> -               y = -y;
> -       }
> -       pos |= y << CURSOR_Y_SHIFT;
> -
> -       return pos;
> -}
> -
> -static bool intel_cursor_size_ok(const struct intel_plane_state *plane_state)
> -{
> -       const struct drm_mode_config *config =
> -               &plane_state->uapi.plane->dev->mode_config;
> -       int width = drm_rect_width(&plane_state->uapi.dst);
> -       int height = drm_rect_height(&plane_state->uapi.dst);
> -
> -       return width > 0 && width <= config->cursor_width &&
> -               height > 0 && height <= config->cursor_height;
> -}
> -
> -static int intel_cursor_check_surface(struct intel_plane_state *plane_state)
> -{
> -       struct drm_i915_private *dev_priv =
> -               to_i915(plane_state->uapi.plane->dev);
> -       unsigned int rotation = plane_state->hw.rotation;
> -       int src_x, src_y;
> -       u32 offset;
> -       int ret;
> -
> -       ret = intel_plane_compute_gtt(plane_state);
> -       if (ret)
> -               return ret;
> -
> -       if (!plane_state->uapi.visible)
> -               return 0;
> -
> -       src_x = plane_state->uapi.src.x1 >> 16;
> -       src_y = plane_state->uapi.src.y1 >> 16;
> -
> -       intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
> -       offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
> -                                                   plane_state, 0);
> -
> -       if (src_x != 0 || src_y != 0) {
> -               drm_dbg_kms(&dev_priv->drm,
> -                           "Arbitrary cursor panning not supported\n");
> -               return -EINVAL;
> -       }
> -
> -       /*
> -        * Put the final coordinates back so that the src
> -        * coordinate checks will see the right values.
> -        */
> -       drm_rect_translate_to(&plane_state->uapi.src,
> -                             src_x << 16, src_y << 16);
> -
> -       /* ILK+ do this automagically in hardware */
> -       if (HAS_GMCH(dev_priv) && rotation & DRM_MODE_ROTATE_180) {
> -               const struct drm_framebuffer *fb = plane_state->hw.fb;
> -               int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
> -               int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
> -
> -               offset += (src_h * src_w - 1) * fb->format->cpp[0];
> -       }
> -
> -       plane_state->color_plane[0].offset = offset;
> -       plane_state->color_plane[0].x = src_x;
> -       plane_state->color_plane[0].y = src_y;
> -
> -       return 0;
> -}
> -
> -static int intel_check_cursor(struct intel_crtc_state *crtc_state,
> -                             struct intel_plane_state *plane_state)
> -{
> -       const struct drm_framebuffer *fb = plane_state->hw.fb;
> -       struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
> -       const struct drm_rect src = plane_state->uapi.src;
> -       const struct drm_rect dst = plane_state->uapi.dst;
> -       int ret;
> -
> -       if (fb && fb->modifier != DRM_FORMAT_MOD_LINEAR) {
> -               drm_dbg_kms(&i915->drm, "cursor cannot be tiled\n");
> -               return -EINVAL;
> -       }
> -
> -       ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
> -                                               DRM_PLANE_HELPER_NO_SCALING,
> -                                               DRM_PLANE_HELPER_NO_SCALING,
> -                                               true);
> -       if (ret)
> -               return ret;
> -
> -       /* Use the unclipped src/dst rectangles, which we program to hw */
> -       plane_state->uapi.src = src;
> -       plane_state->uapi.dst = dst;
> -
> -       ret = intel_cursor_check_surface(plane_state);
> -       if (ret)
> -               return ret;
> -
> -       if (!plane_state->uapi.visible)
> -               return 0;
> -
> -       ret = intel_plane_check_src_coordinates(plane_state);
> -       if (ret)
> -               return ret;
> -
> -       return 0;
> -}
> -
> -static unsigned int
> -i845_cursor_max_stride(struct intel_plane *plane,
> -                      u32 pixel_format, u64 modifier,
> -                      unsigned int rotation)
> -{
> -       return 2048;
> -}
> -
> -static u32 i845_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
> -{
> -       u32 cntl = 0;
> -
> -       if (crtc_state->gamma_enable)
> -               cntl |= CURSOR_GAMMA_ENABLE;
> -
> -       return cntl;
> -}
> -
> -static u32 i845_cursor_ctl(const struct intel_crtc_state *crtc_state,
> -                          const struct intel_plane_state *plane_state)
> -{
> -       return CURSOR_ENABLE |
> -               CURSOR_FORMAT_ARGB |
> -               CURSOR_STRIDE(plane_state->color_plane[0].stride);
> -}
> -
> -static bool i845_cursor_size_ok(const struct intel_plane_state *plane_state)
> -{
> -       int width = drm_rect_width(&plane_state->uapi.dst);
> -
> -       /*
> -        * 845g/865g are only limited by the width of their cursors,
> -        * the height is arbitrary up to the precision of the register.
> -        */
> -       return intel_cursor_size_ok(plane_state) && IS_ALIGNED(width, 64);
> -}
> -
> -static int i845_check_cursor(struct intel_crtc_state *crtc_state,
> -                            struct intel_plane_state *plane_state)
> -{
> -       const struct drm_framebuffer *fb = plane_state->hw.fb;
> -       struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
> -       int ret;
> -
> -       ret = intel_check_cursor(crtc_state, plane_state);
> -       if (ret)
> -               return ret;
> -
> -       /* if we want to turn off the cursor ignore width and height */
> -       if (!fb)
> -               return 0;
> -
> -       /* Check for which cursor types we support */
> -       if (!i845_cursor_size_ok(plane_state)) {
> -               drm_dbg_kms(&i915->drm,
> -                           "Cursor dimension %dx%d not supported\n",
> -                           drm_rect_width(&plane_state->uapi.dst),
> -                           drm_rect_height(&plane_state->uapi.dst));
> -               return -EINVAL;
> -       }
> -
> -       drm_WARN_ON(&i915->drm, plane_state->uapi.visible &&
> -                   plane_state->color_plane[0].stride != fb->pitches[0]);
> -
> -       switch (fb->pitches[0]) {
> -       case 256:
> -       case 512:
> -       case 1024:
> -       case 2048:
> -               break;
> -       default:
> -                drm_dbg_kms(&i915->drm, "Invalid cursor stride (%u)\n",
> -                            fb->pitches[0]);
> -               return -EINVAL;
> -       }
> -
> -       plane_state->ctl = i845_cursor_ctl(crtc_state, plane_state);
> -
> -       return 0;
> -}
> -
> -static void i845_update_cursor(struct intel_plane *plane,
> -                              const struct intel_crtc_state *crtc_state,
> -                              const struct intel_plane_state *plane_state)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       u32 cntl = 0, base = 0, pos = 0, size = 0;
> -       unsigned long irqflags;
> -
> -       if (plane_state && plane_state->uapi.visible) {
> -               unsigned int width = drm_rect_width(&plane_state->uapi.dst);
> -               unsigned int height = drm_rect_height(&plane_state->uapi.dst);
> -
> -               cntl = plane_state->ctl |
> -                       i845_cursor_ctl_crtc(crtc_state);
> -
> -               size = (height << 12) | width;
> -
> -               base = intel_cursor_base(plane_state);
> -               pos = intel_cursor_position(plane_state);
> -       }
> -
> -       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> -
> -       /* On these chipsets we can only modify the base/size/stride
> -        * whilst the cursor is disabled.
> -        */
> -       if (plane->cursor.base != base ||
> -           plane->cursor.size != size ||
> -           plane->cursor.cntl != cntl) {
> -               intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), 0);
> -               intel_de_write_fw(dev_priv, CURBASE(PIPE_A), base);
> -               intel_de_write_fw(dev_priv, CURSIZE, size);
> -               intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
> -               intel_de_write_fw(dev_priv, CURCNTR(PIPE_A), cntl);
> -
> -               plane->cursor.base = base;
> -               plane->cursor.size = size;
> -               plane->cursor.cntl = cntl;
> -       } else {
> -               intel_de_write_fw(dev_priv, CURPOS(PIPE_A), pos);
> -       }
> -
> -       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> -}
> -
> -static void i845_disable_cursor(struct intel_plane *plane,
> -                               const struct intel_crtc_state *crtc_state)
> -{
> -       i845_update_cursor(plane, crtc_state, NULL);
> -}
> -
> -static bool i845_cursor_get_hw_state(struct intel_plane *plane,
> -                                    enum pipe *pipe)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       enum intel_display_power_domain power_domain;
> -       intel_wakeref_t wakeref;
> -       bool ret;
> -
> -       power_domain = POWER_DOMAIN_PIPE(PIPE_A);
> -       wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> -       if (!wakeref)
> -               return false;
> -
> -       ret = intel_de_read(dev_priv, CURCNTR(PIPE_A)) & CURSOR_ENABLE;
> -
> -       *pipe = PIPE_A;
> -
> -       intel_display_power_put(dev_priv, power_domain, wakeref);
> -
> -       return ret;
> -}
> -
> -static unsigned int
> -i9xx_cursor_max_stride(struct intel_plane *plane,
> -                      u32 pixel_format, u64 modifier,
> -                      unsigned int rotation)
> -{
> -       return plane->base.dev->mode_config.cursor_width * 4;
> -}
> -
> -static u32 i9xx_cursor_ctl_crtc(const struct intel_crtc_state *crtc_state)
> -{
> -       struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> -       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> -       u32 cntl = 0;
> -
> -       if (INTEL_GEN(dev_priv) >= 11)
> -               return cntl;
> -
> -       if (crtc_state->gamma_enable)
> -               cntl = MCURSOR_GAMMA_ENABLE;
> -
> -       if (crtc_state->csc_enable)
> -               cntl |= MCURSOR_PIPE_CSC_ENABLE;
> -
> -       if (INTEL_GEN(dev_priv) < 5 && !IS_G4X(dev_priv))
> -               cntl |= MCURSOR_PIPE_SELECT(crtc->pipe);
> -
> -       return cntl;
> -}
> -
> -static u32 i9xx_cursor_ctl(const struct intel_crtc_state *crtc_state,
> -                          const struct intel_plane_state *plane_state)
> -{
> -       struct drm_i915_private *dev_priv =
> -               to_i915(plane_state->uapi.plane->dev);
> -       u32 cntl = 0;
> -
> -       if (IS_GEN(dev_priv, 6) || IS_IVYBRIDGE(dev_priv))
> -               cntl |= MCURSOR_TRICKLE_FEED_DISABLE;
> -
> -       switch (drm_rect_width(&plane_state->uapi.dst)) {
> -       case 64:
> -               cntl |= MCURSOR_MODE_64_ARGB_AX;
> -               break;
> -       case 128:
> -               cntl |= MCURSOR_MODE_128_ARGB_AX;
> -               break;
> -       case 256:
> -               cntl |= MCURSOR_MODE_256_ARGB_AX;
> -               break;
> -       default:
> -               MISSING_CASE(drm_rect_width(&plane_state->uapi.dst));
> -               return 0;
> -       }
> -
> -       if (plane_state->hw.rotation & DRM_MODE_ROTATE_180)
> -               cntl |= MCURSOR_ROTATE_180;
> -
> -       return cntl;
> -}
> -
> -static bool i9xx_cursor_size_ok(const struct intel_plane_state *plane_state)
> -{
> -       struct drm_i915_private *dev_priv =
> -               to_i915(plane_state->uapi.plane->dev);
> -       int width = drm_rect_width(&plane_state->uapi.dst);
> -       int height = drm_rect_height(&plane_state->uapi.dst);
> -
> -       if (!intel_cursor_size_ok(plane_state))
> -               return false;
> -
> -       /* Cursor width is limited to a few power-of-two sizes */
> -       switch (width) {
> -       case 256:
> -       case 128:
> -       case 64:
> -               break;
> -       default:
> -               return false;
> -       }
> -
> -       /*
> -        * IVB+ have CUR_FBC_CTL which allows an arbitrary cursor
> -        * height from 8 lines up to the cursor width, when the
> -        * cursor is not rotated. Everything else requires square
> -        * cursors.
> -        */
> -       if (HAS_CUR_FBC(dev_priv) &&
> -           plane_state->hw.rotation & DRM_MODE_ROTATE_0) {
> -               if (height < 8 || height > width)
> -                       return false;
> -       } else {
> -               if (height != width)
> -                       return false;
> -       }
> -
> -       return true;
> -}
> -
> -static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
> -                            struct intel_plane_state *plane_state)
> -{
> -       struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       const struct drm_framebuffer *fb = plane_state->hw.fb;
> -       enum pipe pipe = plane->pipe;
> -       int ret;
> -
> -       ret = intel_check_cursor(crtc_state, plane_state);
> -       if (ret)
> -               return ret;
> -
> -       /* if we want to turn off the cursor ignore width and height */
> -       if (!fb)
> -               return 0;
> -
> -       /* Check for which cursor types we support */
> -       if (!i9xx_cursor_size_ok(plane_state)) {
> -               drm_dbg(&dev_priv->drm,
> -                       "Cursor dimension %dx%d not supported\n",
> -                       drm_rect_width(&plane_state->uapi.dst),
> -                       drm_rect_height(&plane_state->uapi.dst));
> -               return -EINVAL;
> -       }
> -
> -       drm_WARN_ON(&dev_priv->drm, plane_state->uapi.visible &&
> -                   plane_state->color_plane[0].stride != fb->pitches[0]);
> -
> -       if (fb->pitches[0] !=
> -           drm_rect_width(&plane_state->uapi.dst) * fb->format->cpp[0]) {
> -               drm_dbg_kms(&dev_priv->drm,
> -                           "Invalid cursor stride (%u) (cursor width %d)\n",
> -                           fb->pitches[0],
> -                           drm_rect_width(&plane_state->uapi.dst));
> -               return -EINVAL;
> -       }
> -
> -       /*
> -        * There's something wrong with the cursor on CHV pipe C.
> -        * If it straddles the left edge of the screen then
> -        * moving it away from the edge or disabling it often
> -        * results in a pipe underrun, and often that can lead to
> -        * dead pipe (constant underrun reported, and it scans
> -        * out just a solid color). To recover from that, the
> -        * display power well must be turned off and on again.
> -        * Refuse the put the cursor into that compromised position.
> -        */
> -       if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_C &&
> -           plane_state->uapi.visible && plane_state->uapi.dst.x1 < 0) {
> -               drm_dbg_kms(&dev_priv->drm,
> -                           "CHV cursor C not allowed to straddle the left screen edge\n");
> -               return -EINVAL;
> -       }
> -
> -       plane_state->ctl = i9xx_cursor_ctl(crtc_state, plane_state);
> -
> -       return 0;
> -}
> -
> -static void i9xx_update_cursor(struct intel_plane *plane,
> -                              const struct intel_crtc_state *crtc_state,
> -                              const struct intel_plane_state *plane_state)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       enum pipe pipe = plane->pipe;
> -       u32 cntl = 0, base = 0, pos = 0, fbc_ctl = 0;
> -       unsigned long irqflags;
> -
> -       if (plane_state && plane_state->uapi.visible) {
> -               unsigned width = drm_rect_width(&plane_state->uapi.dst);
> -               unsigned height = drm_rect_height(&plane_state->uapi.dst);
> -
> -               cntl = plane_state->ctl |
> -                       i9xx_cursor_ctl_crtc(crtc_state);
> -
> -               if (width != height)
> -                       fbc_ctl = CUR_FBC_CTL_EN | (height - 1);
> -
> -               base = intel_cursor_base(plane_state);
> -               pos = intel_cursor_position(plane_state);
> -       }
> -
> -       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> -
> -       /*
> -        * On some platforms writing CURCNTR first will also
> -        * cause CURPOS to be armed by the CURBASE write.
> -        * Without the CURCNTR write the CURPOS write would
> -        * arm itself. Thus we always update CURCNTR before
> -        * CURPOS.
> -        *
> -        * On other platforms CURPOS always requires the
> -        * CURBASE write to arm the update. Additonally
> -        * a write to any of the cursor register will cancel
> -        * an already armed cursor update. Thus leaving out
> -        * the CURBASE write after CURPOS could lead to a
> -        * cursor that doesn't appear to move, or even change
> -        * shape. Thus we always write CURBASE.
> -        *
> -        * The other registers are armed by by the CURBASE write
> -        * except when the plane is getting enabled at which time
> -        * the CURCNTR write arms the update.
> -        */
> -
> -       if (INTEL_GEN(dev_priv) >= 9)
> -               skl_write_cursor_wm(plane, crtc_state);
> -
> -       if (!needs_modeset(crtc_state))
> -               intel_psr2_program_plane_sel_fetch(plane, crtc_state, plane_state, 0);
> -
> -       if (plane->cursor.base != base ||
> -           plane->cursor.size != fbc_ctl ||
> -           plane->cursor.cntl != cntl) {
> -               if (HAS_CUR_FBC(dev_priv))
> -                       intel_de_write_fw(dev_priv, CUR_FBC_CTL(pipe),
> -                                         fbc_ctl);
> -               intel_de_write_fw(dev_priv, CURCNTR(pipe), cntl);
> -               intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
> -               intel_de_write_fw(dev_priv, CURBASE(pipe), base);
> -
> -               plane->cursor.base = base;
> -               plane->cursor.size = fbc_ctl;
> -               plane->cursor.cntl = cntl;
> -       } else {
> -               intel_de_write_fw(dev_priv, CURPOS(pipe), pos);
> -               intel_de_write_fw(dev_priv, CURBASE(pipe), base);
> -       }
> -
> -       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> -}
> -
> -static void i9xx_disable_cursor(struct intel_plane *plane,
> -                               const struct intel_crtc_state *crtc_state)
> -{
> -       i9xx_update_cursor(plane, crtc_state, NULL);
> -}
> -
> -static bool i9xx_cursor_get_hw_state(struct intel_plane *plane,
> -                                    enum pipe *pipe)
> -{
> -       struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> -       enum intel_display_power_domain power_domain;
> -       intel_wakeref_t wakeref;
> -       bool ret;
> -       u32 val;
> -
> -       /*
> -        * Not 100% correct for planes that can move between pipes,
> -        * but that's only the case for gen2-3 which don't have any
> -        * display power wells.
> -        */
> -       power_domain = POWER_DOMAIN_PIPE(plane->pipe);
> -       wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
> -       if (!wakeref)
> -               return false;
> -
> -       val = intel_de_read(dev_priv, CURCNTR(plane->pipe));
> -
> -       ret = val & MCURSOR_MODE;
> -
> -       if (INTEL_GEN(dev_priv) >= 5 || IS_G4X(dev_priv))
> -               *pipe = plane->pipe;
> -       else
> -               *pipe = (val & MCURSOR_PIPE_SELECT_MASK) >>
> -                       MCURSOR_PIPE_SELECT_SHIFT;
> -
> -       intel_display_power_put(dev_priv, power_domain, wakeref);
> -
> -       return ret;
> -}
> -
>  /* VESA 640x480x72Hz mode to set on the pipe */
>  static const struct drm_display_mode load_detect_mode = {
>         DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664,
> @@ -16620,7 +16047,7 @@ static void add_rps_boost_after_vblank(struct drm_crtc *crtc,
>         add_wait_queue(drm_crtc_vblank_waitqueue(crtc), &wait->wait);
>  }
>
> -static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
> +int intel_plane_pin_fb(struct intel_plane_state *plane_state)
>  {
>         struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
>         struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
> @@ -16650,7 +16077,7 @@ static int intel_plane_pin_fb(struct intel_plane_state *plane_state)
>         return 0;
>  }
>
> -static void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
> +void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state)
>  {
>         struct i915_vma *vma;
>
> @@ -16886,13 +16313,6 @@ static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
>         }
>  }
>
> -static bool intel_cursor_format_mod_supported(struct drm_plane *_plane,
> -                                             u32 format, u64 modifier)
> -{
> -       return modifier == DRM_FORMAT_MOD_LINEAR &&
> -               format == DRM_FORMAT_ARGB8888;
> -}
> -
>  static const struct drm_plane_funcs i965_plane_funcs = {
>         .update_plane = drm_atomic_helper_update_plane,
>         .disable_plane = drm_atomic_helper_disable_plane,
> @@ -16911,142 +16331,6 @@ static const struct drm_plane_funcs i8xx_plane_funcs = {
>         .format_mod_supported = i8xx_plane_format_mod_supported,
>  };
>
> -static int
> -intel_legacy_cursor_update(struct drm_plane *_plane,
> -                          struct drm_crtc *_crtc,
> -                          struct drm_framebuffer *fb,
> -                          int crtc_x, int crtc_y,
> -                          unsigned int crtc_w, unsigned int crtc_h,
> -                          u32 src_x, u32 src_y,
> -                          u32 src_w, u32 src_h,
> -                          struct drm_modeset_acquire_ctx *ctx)
> -{
> -       struct intel_plane *plane = to_intel_plane(_plane);
> -       struct intel_crtc *crtc = to_intel_crtc(_crtc);
> -       struct intel_plane_state *old_plane_state =
> -               to_intel_plane_state(plane->base.state);
> -       struct intel_plane_state *new_plane_state;
> -       struct intel_crtc_state *crtc_state =
> -               to_intel_crtc_state(crtc->base.state);
> -       struct intel_crtc_state *new_crtc_state;
> -       int ret;
> -
> -       /*
> -        * When crtc is inactive or there is a modeset pending,
> -        * wait for it to complete in the slowpath
> -        *
> -        * FIXME bigjoiner fastpath would be good
> -        */
> -       if (!crtc_state->hw.active || needs_modeset(crtc_state) ||
> -           crtc_state->update_pipe || crtc_state->bigjoiner)
> -               goto slow;
> -
> -       /*
> -        * Don't do an async update if there is an outstanding commit modifying
> -        * the plane.  This prevents our async update's changes from getting
> -        * overridden by a previous synchronous update's state.
> -        */
> -       if (old_plane_state->uapi.commit &&
> -           !try_wait_for_completion(&old_plane_state->uapi.commit->hw_done))
> -               goto slow;
> -
> -       /*
> -        * If any parameters change that may affect watermarks,
> -        * take the slowpath. Only changing fb or position should be
> -        * in the fastpath.
> -        */
> -       if (old_plane_state->uapi.crtc != &crtc->base ||
> -           old_plane_state->uapi.src_w != src_w ||
> -           old_plane_state->uapi.src_h != src_h ||
> -           old_plane_state->uapi.crtc_w != crtc_w ||
> -           old_plane_state->uapi.crtc_h != crtc_h ||
> -           !old_plane_state->uapi.fb != !fb)
> -               goto slow;
> -
> -       new_plane_state = to_intel_plane_state(intel_plane_duplicate_state(&plane->base));
> -       if (!new_plane_state)
> -               return -ENOMEM;
> -
> -       new_crtc_state = to_intel_crtc_state(intel_crtc_duplicate_state(&crtc->base));
> -       if (!new_crtc_state) {
> -               ret = -ENOMEM;
> -               goto out_free;
> -       }
> -
> -       drm_atomic_set_fb_for_plane(&new_plane_state->uapi, fb);
> -
> -       new_plane_state->uapi.src_x = src_x;
> -       new_plane_state->uapi.src_y = src_y;
> -       new_plane_state->uapi.src_w = src_w;
> -       new_plane_state->uapi.src_h = src_h;
> -       new_plane_state->uapi.crtc_x = crtc_x;
> -       new_plane_state->uapi.crtc_y = crtc_y;
> -       new_plane_state->uapi.crtc_w = crtc_w;
> -       new_plane_state->uapi.crtc_h = crtc_h;
> -
> -       intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc);
> -
> -       ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state,
> -                                                 old_plane_state, new_plane_state);
> -       if (ret)
> -               goto out_free;
> -
> -       ret = intel_plane_pin_fb(new_plane_state);
> -       if (ret)
> -               goto out_free;
> -
> -       intel_frontbuffer_flush(to_intel_frontbuffer(new_plane_state->hw.fb),
> -                               ORIGIN_FLIP);
> -       intel_frontbuffer_track(to_intel_frontbuffer(old_plane_state->hw.fb),
> -                               to_intel_frontbuffer(new_plane_state->hw.fb),
> -                               plane->frontbuffer_bit);
> -
> -       /* Swap plane state */
> -       plane->base.state = &new_plane_state->uapi;
> -
> -       /*
> -        * We cannot swap crtc_state as it may be in use by an atomic commit or
> -        * page flip that's running simultaneously. If we swap crtc_state and
> -        * destroy the old state, we will cause a use-after-free there.
> -        *
> -        * Only update active_planes, which is needed for our internal
> -        * bookkeeping. Either value will do the right thing when updating
> -        * planes atomically. If the cursor was part of the atomic update then
> -        * we would have taken the slowpath.
> -        */
> -       crtc_state->active_planes = new_crtc_state->active_planes;
> -
> -       if (new_plane_state->uapi.visible)
> -               intel_update_plane(plane, crtc_state, new_plane_state);
> -       else
> -               intel_disable_plane(plane, crtc_state);
> -
> -       intel_plane_unpin_fb(old_plane_state);
> -
> -out_free:
> -       if (new_crtc_state)
> -               intel_crtc_destroy_state(&crtc->base, &new_crtc_state->uapi);
> -       if (ret)
> -               intel_plane_destroy_state(&plane->base, &new_plane_state->uapi);
> -       else
> -               intel_plane_destroy_state(&plane->base, &old_plane_state->uapi);
> -       return ret;
> -
> -slow:
> -       return drm_atomic_helper_update_plane(&plane->base, &crtc->base, fb,
> -                                             crtc_x, crtc_y, crtc_w, crtc_h,
> -                                             src_x, src_y, src_w, src_h, ctx);
> -}
> -
> -static const struct drm_plane_funcs intel_cursor_plane_funcs = {
> -       .update_plane = intel_legacy_cursor_update,
> -       .disable_plane = drm_atomic_helper_disable_plane,
> -       .destroy = intel_plane_destroy,
> -       .atomic_duplicate_state = intel_plane_duplicate_state,
> -       .atomic_destroy_state = intel_plane_destroy_state,
> -       .format_mod_supported = intel_cursor_format_mod_supported,
> -};
> -
>  static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
>                                enum i9xx_plane_id i9xx_plane)
>  {
> @@ -17198,74 +16482,6 @@ intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
>         return ERR_PTR(ret);
>  }
>
> -static struct intel_plane *
> -intel_cursor_plane_create(struct drm_i915_private *dev_priv,
> -                         enum pipe pipe)
> -{
> -       struct intel_plane *cursor;
> -       int ret, zpos;
> -
> -       cursor = intel_plane_alloc();
> -       if (IS_ERR(cursor))
> -               return cursor;
> -
> -       cursor->pipe = pipe;
> -       cursor->i9xx_plane = (enum i9xx_plane_id) pipe;
> -       cursor->id = PLANE_CURSOR;
> -       cursor->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, cursor->id);
> -
> -       if (IS_I845G(dev_priv) || IS_I865G(dev_priv)) {
> -               cursor->max_stride = i845_cursor_max_stride;
> -               cursor->update_plane = i845_update_cursor;
> -               cursor->disable_plane = i845_disable_cursor;
> -               cursor->get_hw_state = i845_cursor_get_hw_state;
> -               cursor->check_plane = i845_check_cursor;
> -       } else {
> -               cursor->max_stride = i9xx_cursor_max_stride;
> -               cursor->update_plane = i9xx_update_cursor;
> -               cursor->disable_plane = i9xx_disable_cursor;
> -               cursor->get_hw_state = i9xx_cursor_get_hw_state;
> -               cursor->check_plane = i9xx_check_cursor;
> -       }
> -
> -       cursor->cursor.base = ~0;
> -       cursor->cursor.cntl = ~0;
> -
> -       if (IS_I845G(dev_priv) || IS_I865G(dev_priv) || HAS_CUR_FBC(dev_priv))
> -               cursor->cursor.size = ~0;
> -
> -       ret = drm_universal_plane_init(&dev_priv->drm, &cursor->base,
> -                                      0, &intel_cursor_plane_funcs,
> -                                      intel_cursor_formats,
> -                                      ARRAY_SIZE(intel_cursor_formats),
> -                                      cursor_format_modifiers,
> -                                      DRM_PLANE_TYPE_CURSOR,
> -                                      "cursor %c", pipe_name(pipe));
> -       if (ret)
> -               goto fail;
> -
> -       if (INTEL_GEN(dev_priv) >= 4)
> -               drm_plane_create_rotation_property(&cursor->base,
> -                                                  DRM_MODE_ROTATE_0,
> -                                                  DRM_MODE_ROTATE_0 |
> -                                                  DRM_MODE_ROTATE_180);
> -
> -       zpos = RUNTIME_INFO(dev_priv)->num_sprites[pipe] + 1;
> -       drm_plane_create_zpos_immutable_property(&cursor->base, zpos);
> -
> -       if (INTEL_GEN(dev_priv) >= 12)
> -               drm_plane_enable_fb_damage_clips(&cursor->base);
> -
> -       drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
> -
> -       return cursor;
> -
> -fail:
> -       intel_plane_free(cursor);
> -
> -       return ERR_PTR(ret);
> -}
> -
>  static int intel_crtc_late_register(struct drm_crtc *crtc)
>  {
>         intel_crtc_debugfs_add(crtc);
> diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
> index a5771bfecba6..f0a5bf69656f 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.h
> +++ b/drivers/gpu/drm/i915/display/intel_display.h
> @@ -647,6 +647,18 @@ bool
>  intel_format_info_is_yuv_semiplanar(const struct drm_format_info *info,
>                                     uint64_t modifier);
>
> +int intel_plane_compute_gtt(struct intel_plane_state *plane_state);
> +u32 intel_plane_compute_aligned_offset(int *x, int *y,
> +                                      const struct intel_plane_state *state,
> +                                      int color_plane);
> +int intel_plane_pin_fb(struct intel_plane_state *plane_state);
> +void intel_plane_unpin_fb(struct intel_plane_state *old_plane_state);
> +
> +/* cursor */
> +struct intel_plane *
> +intel_cursor_plane_create(struct drm_i915_private *dev_priv,
> +                         enum pipe pipe);
> +
>  /* modesetting */
>  void intel_modeset_init_hw(struct drm_i915_private *i915);
>  int intel_modeset_init_noirq(struct drm_i915_private *i915);
> --
> 2.27.0
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Intel-gfx] [PATCH 4/4] drm/i915: split fdi code out from intel_display.c
  2020-12-09 10:48   ` Daniel Vetter
@ 2020-12-10  1:32     ` Dave Airlie
  0 siblings, 0 replies; 13+ messages in thread
From: Dave Airlie @ 2020-12-10  1:32 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Wed, 9 Dec 2020 at 20:48, Daniel Vetter <daniel@ffwll.ch> wrote:
>
> On Wed, Dec 9, 2020 at 5:22 AM Dave Airlie <airlied@gmail.com> wrote:
> >
> > From: Dave Airlie <airlied@redhat.com>
> >
> > This just refactors out the fdi code to a separate file.
> >
> > Signed-off-by: Dave Airlie <airlied@redhat.com>
>
> There's also hsw_fdi_link_train from intel_ddi.c (another fairly big
> file), I think that also belongs in here. It's not in the vtable
> because it's directly called from the hsw crt encoder. With that this
> looks reasonable to me.

It does but it's definitely a lot messier to move, it has a lot of
links into the ddi code and tables.

I'll add another patch to the end that we can look at to decide if
there's a cleaner way to do it.

Dave.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2020-12-10  1:32 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-09  4:21 [Intel-gfx] [rfc] start slimming down intel_display.c Dave Airlie
2020-12-09  4:21 ` [Intel-gfx] [PATCH 1/4] drm/i915: refactor cursor code out of i915_display.c Dave Airlie
2020-12-09 11:07   ` Daniel Vetter
2020-12-09  4:21 ` [Intel-gfx] [PATCH 2/4] drm/i915: refactor some crtc code out of intel display Dave Airlie
2020-12-09 11:03   ` Daniel Vetter
2020-12-09  4:21 ` [Intel-gfx] [PATCH 3/4] drm/i915: refactor pll code out into intel_clock.c Dave Airlie
2020-12-09 10:55   ` Daniel Vetter
2020-12-09  4:21 ` [Intel-gfx] [PATCH 4/4] drm/i915: split fdi code out from intel_display.c Dave Airlie
2020-12-09 10:48   ` Daniel Vetter
2020-12-10  1:32     ` Dave Airlie
2020-12-09  4:56 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/4] drm/i915: refactor cursor code out of i915_display.c Patchwork
2020-12-09  5:26 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2020-12-09  6:41 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.