All of lore.kernel.org
 help / color / mirror / Atom feed
* Updated fastboot patches
@ 2013-03-26 23:33 Jesse Barnes
  2013-03-26 23:33 ` [PATCH 1/9] drm/i915: Skip modifying PCH DREF if not changing clock sources Jesse Barnes
                   ` (8 more replies)
  0 siblings, 9 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

They're slowly getting slurped in.  These ones are rebased on top of the
bits Daniel pushed today, and include the comments from Imre.

There's one missing piece for getting fastboot to not slowboot on
laptops that don't use the native mode: overriding the pixel clock of a
panel fitted mode with the native one.  The BIOS takeover code can
already adjust the width, height, and pitch, but for the clock we may
need to fetch it from the EDID and add a pipe_config flag or something.

But as they are, I think most of these patches are ready, with the r-b
from Imre.

Thanks,
Jesse

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

* [PATCH 1/9] drm/i915: Skip modifying PCH DREF if not changing clock sources
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  2013-03-28  7:27   ` Jani Nikula
  2013-03-26 23:33 ` [PATCH 2/9] drm/i915: Split the framebuffer_info creation into a separate routine Jesse Barnes
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

From: Chris Wilson <chris@chris-wilson.co.uk>

Modifying the clock sources (via the DREF control on the PCH) is a slow
multi-stage process as we need to let the clocks stabilise between each
stage. If we are not actually changing the clock sources, then we can
return early.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_display.c |   83 +++++++++++++++++++++++++---------
 1 file changed, 61 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8f0db8c..9d05b30 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4833,7 +4833,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_mode_config *mode_config = &dev->mode_config;
 	struct intel_encoder *encoder;
-	u32 temp;
+	u32 val, final;
 	bool has_lvds = false;
 	bool has_cpu_edp = false;
 	bool has_pch_edp = false;
@@ -4876,70 +4876,109 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
 	 * PCH B stepping, previous chipset stepping should be
 	 * ignoring this setting.
 	 */
-	temp = I915_READ(PCH_DREF_CONTROL);
+	val = I915_READ(PCH_DREF_CONTROL);
+
+	/* As we must carefully and slowly disable/enable each source in turn,
+	 * compute the final state we want first and check if we need to
+	 * make any changes at all.
+	 */
+	final = val;
+	final &= ~DREF_NONSPREAD_SOURCE_MASK;
+	if (has_ck505)
+		final |= DREF_NONSPREAD_CK505_ENABLE;
+	else
+		final |= DREF_NONSPREAD_SOURCE_ENABLE;
+
+	final &= ~DREF_SSC_SOURCE_MASK;
+	final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+	final &= ~DREF_SSC1_ENABLE;
+
+	if (has_panel) {
+		final |= DREF_SSC_SOURCE_ENABLE;
+
+		if (intel_panel_use_ssc(dev_priv) && can_ssc)
+			final |= DREF_SSC1_ENABLE;
+
+		if (has_cpu_edp) {
+			if (intel_panel_use_ssc(dev_priv) && can_ssc)
+				final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+			else
+				final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+		} else
+			final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+	} else {
+		final |= DREF_SSC_SOURCE_DISABLE;
+		final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+	}
+
+	if (final == val)
+		return;
+
 	/* Always enable nonspread source */
-	temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+	val &= ~DREF_NONSPREAD_SOURCE_MASK;
 
 	if (has_ck505)
-		temp |= DREF_NONSPREAD_CK505_ENABLE;
+		val |= DREF_NONSPREAD_CK505_ENABLE;
 	else
-		temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+		val |= DREF_NONSPREAD_SOURCE_ENABLE;
 
 	if (has_panel) {
-		temp &= ~DREF_SSC_SOURCE_MASK;
-		temp |= DREF_SSC_SOURCE_ENABLE;
+		val &= ~DREF_SSC_SOURCE_MASK;
+		val |= DREF_SSC_SOURCE_ENABLE;
 
 		/* SSC must be turned on before enabling the CPU output  */
 		if (intel_panel_use_ssc(dev_priv) && can_ssc) {
 			DRM_DEBUG_KMS("Using SSC on panel\n");
-			temp |= DREF_SSC1_ENABLE;
+			val |= DREF_SSC1_ENABLE;
 		} else
-			temp &= ~DREF_SSC1_ENABLE;
+			val &= ~DREF_SSC1_ENABLE;
 
 		/* Get SSC going before enabling the outputs */
-		I915_WRITE(PCH_DREF_CONTROL, temp);
+		I915_WRITE(PCH_DREF_CONTROL, val);
 		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
 
-		temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+		val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
 		/* Enable CPU source on CPU attached eDP */
 		if (has_cpu_edp) {
 			if (intel_panel_use_ssc(dev_priv) && can_ssc) {
 				DRM_DEBUG_KMS("Using SSC on eDP\n");
-				temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+				val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
 			}
 			else
-				temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+				val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
 		} else
-			temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+			val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
 
-		I915_WRITE(PCH_DREF_CONTROL, temp);
+		I915_WRITE(PCH_DREF_CONTROL, val);
 		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
 	} else {
 		DRM_DEBUG_KMS("Disabling SSC entirely\n");
 
-		temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+		val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
 		/* Turn off CPU output */
-		temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+		val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
 
-		I915_WRITE(PCH_DREF_CONTROL, temp);
+		I915_WRITE(PCH_DREF_CONTROL, val);
 		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
 
 		/* Turn off the SSC source */
-		temp &= ~DREF_SSC_SOURCE_MASK;
-		temp |= DREF_SSC_SOURCE_DISABLE;
+		val &= ~DREF_SSC_SOURCE_MASK;
+		val |= DREF_SSC_SOURCE_DISABLE;
 
 		/* Turn off SSC1 */
-		temp &= ~ DREF_SSC1_ENABLE;
+		val &= ~ DREF_SSC1_ENABLE;
 
-		I915_WRITE(PCH_DREF_CONTROL, temp);
+		I915_WRITE(PCH_DREF_CONTROL, val);
 		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
 	}
+
+	BUG_ON(val != final);
 }
 
 /* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */
-- 
1.7.9.5

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

* [PATCH 2/9] drm/i915: Split the framebuffer_info creation into a separate routine
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
  2013-03-26 23:33 ` [PATCH 1/9] drm/i915: Skip modifying PCH DREF if not changing clock sources Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  2013-03-26 23:33 ` [PATCH 3/9] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v2 Jesse Barnes
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

This will be shared with wrapping the BIOS framebuffer into the fbdev
later. In the meantime, we can tidy the code slightly and improve the
error path handling.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_display.c |    7 --
 drivers/gpu/drm/i915/intel_drv.h     |    7 ++
 drivers/gpu/drm/i915/intel_fb.c      |  154 ++++++++++++++++++----------------
 3 files changed, 91 insertions(+), 77 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9d05b30..dfc8152 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6552,13 +6552,6 @@ intel_framebuffer_create(struct drm_device *dev,
 }
 
 static u32
-intel_framebuffer_pitch_for_width(int width, int bpp)
-{
-	u32 pitch = DIV_ROUND_UP(width * bpp, 8);
-	return ALIGN(pitch, 64);
-}
-
-static u32
 intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp)
 {
 	u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 276f665..f593e26 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -134,6 +134,13 @@ struct intel_framebuffer {
 	struct drm_i915_gem_object *obj;
 };
 
+inline static u32
+intel_framebuffer_pitch_for_width(int width, int bpp)
+{
+	u32 pitch = DIV_ROUND_UP(width * bpp, 8);
+	return ALIGN(pitch, 64);
+}
+
 struct intel_fbdev {
 	struct drm_fb_helper helper;
 	struct intel_framebuffer ifb;
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 8d81c929..8736a77 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -57,30 +57,97 @@ static struct fb_ops intelfb_ops = {
 	.fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
+static struct fb_info *intelfb_create_info(struct intel_fbdev *ifbdev)
+{
+	struct drm_framebuffer *fb = &ifbdev->ifb.base;
+	struct drm_device *dev = fb->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct fb_info *info;
+	u32 gtt_offset, size;
+	int ret;
+
+	info = framebuffer_alloc(0, &dev->pdev->dev);
+	if (!info)
+		return NULL;
+
+	info->par = ifbdev;
+	ifbdev->helper.fb = fb;
+	ifbdev->helper.fbdev = info;
+
+	strcpy(info->fix.id, "inteldrmfb");
+
+	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
+	info->fbops = &intelfb_ops;
+
+	ret = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (ret)
+		goto err_info;
+
+	/* setup aperture base/size for vesafb takeover */
+	info->apertures = alloc_apertures(1);
+	if (!info->apertures)
+		goto err_cmap;
+
+	info->apertures->ranges[0].base = dev->mode_config.fb_base;
+	info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
+
+	gtt_offset = ifbdev->ifb.obj->gtt_offset;
+	size = ifbdev->ifb.obj->base.size;
+
+	info->fix.smem_start = dev->mode_config.fb_base + gtt_offset;
+	info->fix.smem_len = size;
+
+	info->screen_size = size;
+	info->screen_base = ioremap_wc(dev_priv->gtt.mappable_base + gtt_offset,
+				       size);
+	if (!info->screen_base)
+		goto err_cmap;
+
+	/* If the object is shmemfs backed, it will have given us zeroed pages.
+	 * If the object is stolen however, it will be full of whatever
+	 * garbage was left in there.
+	 */
+	if (ifbdev->ifb.obj->stolen)
+		memset_io(info->screen_base, 0, info->screen_size);
+
+	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
+
+	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+	drm_fb_helper_fill_var(info, &ifbdev->helper, fb->width, fb->height);
+
+	return info;
+
+err_cmap:
+	if (info->cmap.len)
+		fb_dealloc_cmap(&info->cmap);
+err_info:
+	framebuffer_release(info);
+	return NULL;
+}
+
 static int intelfb_create(struct drm_fb_helper *helper,
 			  struct drm_fb_helper_surface_size *sizes)
 {
 	struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
 	struct drm_device *dev = ifbdev->helper.dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct fb_info *info;
-	struct drm_framebuffer *fb;
-	struct drm_mode_fb_cmd2 mode_cmd = {};
+	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
 	struct drm_i915_gem_object *obj;
-	struct device *device = &dev->pdev->dev;
+	struct fb_info *info;
 	int size, ret;
 
 	/* we don't do packed 24bpp */
 	if (sizes->surface_bpp == 24)
 		sizes->surface_bpp = 32;
 
-	mode_cmd.width = sizes->surface_width;
+	mode_cmd.width  = sizes->surface_width;
 	mode_cmd.height = sizes->surface_height;
 
-	mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((sizes->surface_bpp + 7) /
-						      8), 64);
-	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
-							  sizes->surface_depth);
+	mode_cmd.pitches[0] =
+		intel_framebuffer_pitch_for_width(mode_cmd.width,
+						  sizes->surface_bpp);
+	mode_cmd.pixel_format =
+		drm_mode_legacy_fb_format(sizes->surface_bpp,
+					  sizes->surface_depth);
 
 	size = mode_cmd.pitches[0] * mode_cmd.height;
 	size = ALIGN(size, PAGE_SIZE);
@@ -102,72 +169,19 @@ static int intelfb_create(struct drm_fb_helper *helper,
 		goto out_unref;
 	}
 
-	info = framebuffer_alloc(0, device);
-	if (!info) {
-		ret = -ENOMEM;
-		goto out_unpin;
-	}
-
-	info->par = ifbdev;
-
 	ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
 	if (ret)
 		goto out_unpin;
 
-	fb = &ifbdev->ifb.base;
-
-	ifbdev->helper.fb = fb;
-	ifbdev->helper.fbdev = info;
-
-	strcpy(info->fix.id, "inteldrmfb");
-
-	info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
-	info->fbops = &intelfb_ops;
+	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
+		      mode_cmd.width, mode_cmd.height,
+		      obj->gtt_offset, obj);
 
-	ret = fb_alloc_cmap(&info->cmap, 256, 0);
-	if (ret) {
-		ret = -ENOMEM;
-		goto out_unpin;
-	}
-	/* setup aperture base/size for vesafb takeover */
-	info->apertures = alloc_apertures(1);
-	if (!info->apertures) {
+	info = intelfb_create_info(ifbdev);
+	if (info == NULL) {
 		ret = -ENOMEM;
 		goto out_unpin;
 	}
-	info->apertures->ranges[0].base = dev->mode_config.fb_base;
-	info->apertures->ranges[0].size = dev_priv->gtt.mappable_end;
-
-	info->fix.smem_start = dev->mode_config.fb_base + obj->gtt_offset;
-	info->fix.smem_len = size;
-
-	info->screen_base =
-		ioremap_wc(dev_priv->gtt.mappable_base + obj->gtt_offset,
-			   size);
-	if (!info->screen_base) {
-		ret = -ENOSPC;
-		goto out_unpin;
-	}
-	info->screen_size = size;
-
-	/* This driver doesn't need a VT switch to restore the mode on resume */
-	info->skip_vt_switch = true;
-
-	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
-	drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
-
-	/* If the object is shmemfs backed, it will have given us zeroed pages.
-	 * If the object is stolen however, it will be full of whatever
-	 * garbage was left in there.
-	 */
-	if (ifbdev->ifb.obj->stolen)
-		memset_io(info->screen_base, 0, info->screen_size);
-
-	/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
-
-	DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
-		      fb->width, fb->height,
-		      obj->gtt_offset, obj);
 
 
 	mutex_unlock(&dev->struct_mutex);
@@ -192,11 +206,11 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
 static void intel_fbdev_destroy(struct drm_device *dev,
 				struct intel_fbdev *ifbdev)
 {
-	struct fb_info *info;
 	struct intel_framebuffer *ifb = &ifbdev->ifb;
 
 	if (ifbdev->helper.fbdev) {
-		info = ifbdev->helper.fbdev;
+		struct fb_info *info = ifbdev->helper.fbdev;
+
 		unregister_framebuffer(info);
 		iounmap(info->screen_base);
 		if (info->cmap.len)
-- 
1.7.9.5

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

* [PATCH 3/9] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v2
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
  2013-03-26 23:33 ` [PATCH 1/9] drm/i915: Skip modifying PCH DREF if not changing clock sources Jesse Barnes
  2013-03-26 23:33 ` [PATCH 2/9] drm/i915: Split the framebuffer_info creation into a separate routine Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  2013-03-26 23:53   ` Chris Wilson
  2013-03-26 23:33 ` [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2 Jesse Barnes
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

v2: check for non-native modes and adjust (Jesse)
    fixup aperture and cmap frees (Imre)
    use unlocked unref if init_bios fails (Jesse)
    fix curly brace around DSPADDR check (Imre)
    comment failure path for pin_and_fence (Imre)

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/i915_dma.c      |    8 +-
 drivers/gpu/drm/i915/i915_drv.h      |    2 +-
 drivers/gpu/drm/i915/intel_display.c |   14 +-
 drivers/gpu/drm/i915/intel_drv.h     |    4 +
 drivers/gpu/drm/i915/intel_fb.c      |  300 ++++++++++++++++++++++++++++++++--
 5 files changed, 308 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index ebcfe2e..1389247 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1273,6 +1273,7 @@ static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
 static int i915_load_modeset_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	bool was_vga_enabled;
 	int ret;
 
 	ret = intel_parse_bios(dev);
@@ -1309,7 +1310,11 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
 	/* Important: The output setup functions called by modeset_init need
 	 * working irqs for e.g. gmbus and dp aux transfers. */
-	intel_modeset_init(dev);
+	intel_modeset_init(dev, &was_vga_enabled);
+
+	/* Wrap existing BIOS mode configuration prior to GEM takeover */
+	if (!was_vga_enabled)
+		intel_fbdev_init_bios(dev);
 
 	ret = i915_gem_init(dev);
 	if (ret)
@@ -1323,6 +1328,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
 	/* FIXME: do pre/post-mode set stuff in core KMS code */
 	dev->vblank_disable_allowed = 1;
 
+	/* Install a default KMS/GEM fbcon if we failed to wrap the BIOS fb */
 	ret = intel_fbdev_init(dev);
 	if (ret)
 		goto cleanup_gem;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7f6452b..d32ed27 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -1806,7 +1806,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
 
 /* modesetting */
 extern void intel_modeset_init_hw(struct drm_device *dev);
-extern void intel_modeset_init(struct drm_device *dev);
+extern void intel_modeset_init(struct drm_device *dev, bool *was_vga_enabled);
 extern void intel_modeset_gem_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
 extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index dfc8152..a55ef8f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8854,12 +8854,17 @@ static void intel_init_quirks(struct drm_device *dev)
 }
 
 /* Disable the VGA plane that we never use */
-static void i915_disable_vga(struct drm_device *dev)
+static bool i915_disable_vga(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	bool was_enabled;
 	u8 sr1;
 	u32 vga_reg = i915_vgacntrl_reg(dev);
 
+	was_enabled = !(I915_READ(vga_reg) & VGA_DISP_DISABLE);
+	DRM_DEBUG_KMS("VGA output is currently %s\n",
+		      was_enabled ? "enabled" : "disabled");
+
 	vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
 	outb(SR01, VGA_SR_INDEX);
 	sr1 = inb(VGA_SR_DATA);
@@ -8869,6 +8874,8 @@ static void i915_disable_vga(struct drm_device *dev)
 
 	I915_WRITE(vga_reg, VGA_DISP_DISABLE);
 	POSTING_READ(vga_reg);
+
+	return was_enabled;
 }
 
 void intel_modeset_init_hw(struct drm_device *dev)
@@ -8884,7 +8891,8 @@ void intel_modeset_init_hw(struct drm_device *dev)
 	mutex_unlock(&dev->struct_mutex);
 }
 
-void intel_modeset_init(struct drm_device *dev)
+void intel_modeset_init(struct drm_device *dev,
+			bool *was_vga_enabled)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i, ret;
@@ -8932,7 +8940,7 @@ void intel_modeset_init(struct drm_device *dev)
 	intel_pch_pll_init(dev);
 
 	/* Just disable it once at startup */
-	i915_disable_vga(dev);
+	*was_vga_enabled = i915_disable_vga(dev);
 	intel_setup_outputs(dev);
 
 	/* Just in case the BIOS is doing something questionable. */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f593e26..52e4924 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -146,6 +146,8 @@ struct intel_fbdev {
 	struct intel_framebuffer ifb;
 	struct list_head fbdev_list;
 	struct drm_display_mode *our_mode;
+	bool stolen;
+	int preferred_bpp;
 };
 
 struct intel_encoder {
@@ -212,6 +214,7 @@ struct intel_crtc {
 	enum plane plane;
 	enum transcoder cpu_transcoder;
 	u8 lut_r[256], lut_g[256], lut_b[256];
+	bool mode_valid;
 	/*
 	 * Whether the crtc and the connected output pipeline is active. Implies
 	 * that crtc->enabled is set, i.e. the current mode configuration has
@@ -621,6 +624,7 @@ extern int intel_framebuffer_init(struct drm_device *dev,
 				  struct intel_framebuffer *ifb,
 				  struct drm_mode_fb_cmd2 *mode_cmd,
 				  struct drm_i915_gem_object *obj);
+extern void intel_fbdev_init_bios(struct drm_device *dev);
 extern int intel_fbdev_init(struct drm_device *dev);
 extern void intel_fbdev_initial_config(struct drm_device *dev);
 extern void intel_fbdev_fini(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 8736a77..f6746af 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -101,7 +101,7 @@ static struct fb_info *intelfb_create_info(struct intel_fbdev *ifbdev)
 	info->screen_base = ioremap_wc(dev_priv->gtt.mappable_base + gtt_offset,
 				       size);
 	if (!info->screen_base)
-		goto err_cmap;
+		goto err_apertures;
 
 	/* If the object is shmemfs backed, it will have given us zeroed pages.
 	 * If the object is stolen however, it will be full of whatever
@@ -117,9 +117,10 @@ static struct fb_info *intelfb_create_info(struct intel_fbdev *ifbdev)
 
 	return info;
 
+err_apertures:
+	kfree(info->apertures);
 err_cmap:
-	if (info->cmap.len)
-		fb_dealloc_cmap(&info->cmap);
+	fb_dealloc_cmap(&info->cmap);
 err_info:
 	framebuffer_release(info);
 	return NULL;
@@ -183,9 +184,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 		goto out_unpin;
 	}
 
-
 	mutex_unlock(&dev->struct_mutex);
-	vga_switcheroo_client_fb_set(dev->pdev, info);
 	return 0;
 
 out_unpin:
@@ -197,6 +196,69 @@ out:
 	return ret;
 }
 
+static struct drm_fb_helper_crtc *
+intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
+{
+	int i;
+
+	for (i = 0; i < fb_helper->crtc_count; i++)
+		if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
+			return &fb_helper->crtc_info[i];
+
+	return NULL;
+}
+
+static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
+				    struct drm_fb_helper_crtc **crtcs,
+				    struct drm_display_mode **modes,
+				    bool *enabled, int width, int height)
+{
+	int i;
+
+	for (i = 0; i < fb_helper->connector_count; i++) {
+		struct drm_connector *connector;
+		struct drm_encoder *encoder;
+
+		connector = fb_helper->connector_info[i]->connector;
+		if (!enabled[i]) {
+			DRM_DEBUG_KMS("connector %d not enabled, skipping\n",
+				      connector->base.id);
+			continue;
+		}
+
+		encoder = connector->encoder;
+		if (!encoder || !encoder->crtc) {
+			DRM_DEBUG_KMS("connector %d has no encoder or crtc, skipping\n",
+				      connector->base.id);
+			continue;
+		}
+
+		if (WARN_ON(!encoder->crtc->enabled)) {
+			DRM_DEBUG_KMS("connector %s on crtc %d has inconsistent state, aborting\n",
+				      drm_get_connector_name(connector),
+				      encoder->crtc->base.id);
+			return false;
+		}
+
+		if (!to_intel_crtc(encoder->crtc)->mode_valid) {
+			DRM_DEBUG_KMS("connector %s on crtc %d has an invalid mode, aborting\n",
+				      drm_get_connector_name(connector),
+				      encoder->crtc->base.id);
+			return false;
+		}
+
+		modes[i] = &encoder->crtc->mode;
+		crtcs[i] = intel_fb_helper_crtc(fb_helper, encoder->crtc);
+
+		DRM_DEBUG_KMS("connector %s on crtc %d: %s\n",
+			      drm_get_connector_name(connector),
+			      encoder->crtc->base.id,
+			      modes[i]->name);
+	}
+
+	return true;
+}
+
 static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
 	.gamma_set = intel_crtc_fb_gamma_set,
 	.gamma_get = intel_crtc_fb_gamma_get,
@@ -212,9 +274,9 @@ static void intel_fbdev_destroy(struct drm_device *dev,
 		struct fb_info *info = ifbdev->helper.fbdev;
 
 		unregister_framebuffer(info);
+		kfree(info->apertures);
 		iounmap(info->screen_base);
-		if (info->cmap.len)
-			fb_dealloc_cmap(&info->cmap);
+		fb_dealloc_cmap(&info->cmap);
 		framebuffer_release(info);
 	}
 
@@ -228,23 +290,229 @@ static void intel_fbdev_destroy(struct drm_device *dev,
 	}
 }
 
-int intel_fbdev_init(struct drm_device *dev)
+static bool pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe)
+{
+	enum transcoder cpu_transcoder =
+		intel_pipe_to_cpu_transcoder(dev_priv, pipe);
+	return !!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE);
+}
+
+/*
+ * Try to read the BIOS display configuration and use it for the initial
+ * fb configuration.
+ *
+ * The BIOS or boot loader will generally create an initial display
+ * configuration for us that includes some set of active pipes and displays.
+ * This routine tries to figure out which pipes are active, what resolutions
+ * are being displayed, and then allocates a framebuffer and initial fb
+ * config based on that data.
+ *
+ * If the BIOS or boot loader leaves the display in VGA mode, there's not
+ * much we can do; switching out of that mode involves allocating a new,
+ * high res buffer, and also recalculating bandwidth requirements for the
+ * new bpp configuration.
+ *
+ * However, if we're loaded into an existing, high res mode, we should
+ * be able to allocate a buffer big enough to handle the largest active
+ * mode, create a mode_set for it, and pass it to the fb helper to create
+ * the configuration.
+ */
+void intel_fbdev_init_bios(struct drm_device *dev)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_fbdev *ifbdev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	int ret;
+	struct drm_crtc *crtc;
+	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+	struct drm_i915_gem_object *obj;
+	u32 obj_offset = 0;
+	int mode_bpp = 0;
+	u32 active = 0;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+		int pipe = intel_crtc->pipe, plane = intel_crtc->plane;
+		u32 val, bpp, offset, format;
+		int pitch, width, height;
+
+		if (!pipe_enabled(dev_priv, pipe)) {
+			DRM_DEBUG_KMS("pipe %c not active, skipping\n",
+				      pipe_name(pipe));
+			continue;
+		}
+
+		val = I915_READ(DSPCNTR(plane));
+
+		if (INTEL_INFO(dev)->gen >= 4) {
+			if (val & DISPPLANE_TILED) {
+				DRM_DEBUG_KMS("tiled BIOS fb?\n");
+				continue; /* unexpected! */
+			}
+		}
+
+		switch (val & DISPPLANE_PIXFORMAT_MASK) {
+		case DISPPLANE_YUV422:
+		default:
+			DRM_DEBUG_KMS("pipe %c unsupported pixel format %x, skipping\n",
+				      pipe_name(pipe), (val & DISPPLANE_PIXFORMAT_MASK) >> 26);
+			continue;
+		case DISPPLANE_8BPP:
+			format = DRM_FORMAT_C8;
+			bpp = 8;
+			break;
+		case DISPPLANE_BGRX555:
+			format = DRM_FORMAT_XRGB1555;
+			bpp = 16;
+			break;
+		case DISPPLANE_BGRX565:
+			format = DRM_FORMAT_RGB565;
+			bpp = 16;
+			break;
+		case DISPPLANE_BGRX888:
+			format = DRM_FORMAT_XRGB8888;
+			bpp = 32;
+			break;
+		}
+
+		if (mode_cmd.pixel_format == 0) {
+			mode_bpp = bpp;
+			mode_cmd.pixel_format = format;
+		}
+
+		if (mode_cmd.pixel_format != format) {
+			DRM_DEBUG_KMS("pipe %c has format/bpp (%d, %d) mismatch: skipping\n",
+				      pipe_name(pipe), format, bpp);
+			continue;
+		}
+
+		if (INTEL_INFO(dev)->gen >= 4) {
+			if (I915_READ(DSPTILEOFF(plane))) {
+				DRM_DEBUG_KMS("pipe %c is offset: skipping\n",
+					      pipe_name(pipe));
+				continue;
+			}
+
+			offset = I915_READ(DSPSURF(plane));
+		} else {
+			offset = I915_READ(DSPADDR(plane));
+		}
+		if (!obj_offset)
+			obj_offset = offset;
+
+		if (offset != obj_offset) {
+			DRM_DEBUG_KMS("multiple pipe setup not in clone mode, skipping\n");
+			continue;
+		}
+
+		val = I915_READ(PIPESRC(pipe));
+		width = ((val >> 16) & 0xfff) + 1;
+		height = ((val >> 0) & 0xfff) + 1;
+
+		/* Adjust fitted modes */
+		val = I915_READ(HTOTAL(pipe));
+		if (((val & 0xffff) + 1) != width) {
+			DRM_DEBUG_DRIVER("BIOS fb not native width (%d vs %d), overriding\n", width, (val & 0xffff) + 1);
+			width = (val & 0xffff) + 1;
+		}
+		val = I915_READ(VTOTAL(pipe));
+		if (((val & 0xffff) + 1) != height) {
+			DRM_DEBUG_DRIVER("BIOS fb not native height (%d vs %d), overriding\n", height, (val & 0xffff) + 1);
+			height = (val & 0xffff) + 1;
+		}
+
+		DRM_DEBUG_KMS("Found active pipe [%d/%d]: size=%dx%d@%d, offset=%x\n",
+			      pipe, plane, width, height, bpp, offset);
+
+		if (width > mode_cmd.width)
+			mode_cmd.width = width;
+
+		if (height > mode_cmd.height)
+			mode_cmd.height = height;
+
+		pitch = intel_framebuffer_pitch_for_width(width, bpp);
+		if (pitch > mode_cmd.pitches[0])
+			mode_cmd.pitches[0] = pitch;
+
+		active |= 1 << pipe;
+	}
+
+	if (active == 0) {
+		DRM_DEBUG_KMS("no active pipes found, not using BIOS config\n");
+		return;
+	}
 
 	ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
-	if (!ifbdev)
-		return -ENOMEM;
+	if (ifbdev == NULL) {
+		DRM_DEBUG_KMS("failed to alloc intel fbdev\n");
+		return;
+	}
 
-	dev_priv->fbdev = ifbdev;
+	ifbdev->stolen = true;
+	ifbdev->preferred_bpp = mode_bpp;
 	ifbdev->helper.funcs = &intel_fb_helper_funcs;
+	ifbdev->helper.funcs->initial_config = intel_fb_initial_config;
+
+	/* assume a 1:1 linear mapping between stolen and GTT */
+	obj = i915_gem_object_create_stolen_for_preallocated(dev,
+							     obj_offset,
+							     obj_offset,
+							     ALIGN(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE));
+	if (obj == NULL) {
+		DRM_DEBUG_KMS("failed to create stolen fb\n");
+		goto out_free_ifbdev;
+	}
+
+	if (intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj)) {
+		DRM_DEBUG_KMS("intel fb init failed\n");
+		goto out_unref_obj;
+	}
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		if ((active & (1 << to_intel_crtc(crtc)->pipe)) == 0)
+			continue;
+
+		/*
+		 * This should only fail on the first one so we don't need
+		 * to cleanup any secondary crtc->fbs
+		 */
+		if (intel_pin_and_fence_fb_obj(dev, obj, NULL))
+			goto out_unref_obj;
+
+		crtc->fb = &ifbdev->ifb.base;
+	}
+
+	dev_priv->fbdev = ifbdev;
+
+	DRM_DEBUG_KMS("using BIOS fb for initial console\n");
+	return;
+
+out_unref_obj:
+	drm_gem_object_unreference_unlocked(&obj->base);
+out_free_ifbdev:
+	kfree(ifbdev);
+}
+
+int intel_fbdev_init(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_fbdev *ifbdev;
+	int ret;
+
+	if ((ifbdev = dev_priv->fbdev) == NULL) {
+		ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
+		if (ifbdev == NULL)
+			return -ENOMEM;
+
+		ifbdev->helper.funcs = &intel_fb_helper_funcs;
+		ifbdev->preferred_bpp = 32;
+
+		dev_priv->fbdev = ifbdev;
+	}
 
 	ret = drm_fb_helper_init(dev, &ifbdev->helper,
 				 INTEL_INFO(dev)->num_pipes,
 				 INTELFB_CONN_LIMIT);
 	if (ret) {
+		dev_priv->fbdev = NULL;
 		kfree(ifbdev);
 		return ret;
 	}
@@ -257,9 +525,10 @@ int intel_fbdev_init(struct drm_device *dev)
 void intel_fbdev_initial_config(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_fbdev *ifbdev = dev_priv->fbdev;
 
 	/* Due to peculiar init order wrt to hpd handling this is separate. */
-	drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
+	drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
 }
 
 void intel_fbdev_fini(struct drm_device *dev)
@@ -287,7 +556,8 @@ MODULE_LICENSE("GPL and additional rights");
 void intel_fb_output_poll_changed(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
+	if (dev_priv->fbdev)
+		drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
 }
 
 void intel_fb_restore_mode(struct drm_device *dev)
-- 
1.7.9.5

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

* [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
                   ` (2 preceding siblings ...)
  2013-03-26 23:33 ` [PATCH 3/9] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v2 Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  2013-03-26 23:36   ` Jesse Barnes
  2013-03-27  0:13   ` Daniel Vetter
  2013-03-26 23:33 ` [PATCH 5/9] drm/i915: Only preserve the BIOS modes if they are the preferred ones Jesse Barnes
                   ` (4 subsequent siblings)
  8 siblings, 2 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

Read the current hardware state to retrieve the active mode and populate
our CRTC config if that mode matches our presumptions.

v2: check that get_hw_state gave us a valid pipe (Imre)
    add clock_get for ILK+ (Jesse)

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h      |    2 +
 drivers/gpu/drm/i915/intel_crt.c     |   27 ++++++-
 drivers/gpu/drm/i915/intel_display.c |  139 +++++++++++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp.c      |   22 ++++++
 drivers/gpu/drm/i915/intel_drv.h     |    7 +-
 drivers/gpu/drm/i915/intel_dvo.c     |   36 ++++++---
 drivers/gpu/drm/i915/intel_hdmi.c    |   22 ++++++
 drivers/gpu/drm/i915/intel_lvds.c    |   27 ++++++-
 drivers/gpu/drm/i915/intel_sdvo.c    |   23 ++++++
 9 files changed, 262 insertions(+), 43 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index d32ed27..905ce86 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -283,6 +283,8 @@ struct drm_i915_display_funcs {
 	void (*update_linetime_wm)(struct drm_device *dev, int pipe,
 				 struct drm_display_mode *mode);
 	void (*modeset_global_resources)(struct drm_device *dev);
+	bool (*crtc_get_mode)(struct drm_crtc *crtc,
+			     struct drm_display_mode *mode);
 	int (*crtc_mode_set)(struct drm_crtc *crtc,
 			     struct drm_display_mode *mode,
 			     struct drm_display_mode *adjusted_mode,
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 32a3693..da0ae7e 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -81,6 +81,27 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
 	return true;
 }
 
+static unsigned intel_crt_get_mode_flags(struct intel_encoder *encoder)
+{
+	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	struct intel_crt *crt = intel_encoder_to_crt(encoder);
+	u32 tmp, flags = 0;
+
+	tmp = I915_READ(crt->adpa_reg);
+
+	if (tmp & ADPA_HSYNC_ACTIVE_HIGH)
+		flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NHSYNC;
+
+	if (tmp & ADPA_VSYNC_ACTIVE_HIGH)
+		flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NVSYNC;
+
+	return flags;
+}
+
 static void intel_disable_crt(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -776,10 +797,12 @@ void intel_crt_init(struct drm_device *dev)
 
 	crt->base.disable = intel_disable_crt;
 	crt->base.enable = intel_enable_crt;
-	if (HAS_DDI(dev))
+	if (HAS_DDI(dev)) {
 		crt->base.get_hw_state = intel_ddi_get_hw_state;
-	else
+	} else {
 		crt->base.get_hw_state = intel_crt_get_hw_state;
+		crt->base.get_mode_flags = intel_crt_get_mode_flags;
+	}
 	intel_connector->get_hw_state = intel_connector_get_hw_state;
 
 	drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index a55ef8f..35a1984 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6748,11 +6748,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 }
 
 /* Returns the clock of the currently programmed mode of the given pipe. */
-static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
+static int i9xx_crtc_clock_get(struct drm_crtc *crtc)
 {
+	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int pipe = intel_crtc->pipe;
+	enum pipe pipe = intel_crtc->pipe;
 	u32 dpll = I915_READ(DPLL(pipe));
 	u32 fp;
 	intel_clock_t clock;
@@ -6835,35 +6836,104 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
 }
 
 /** Returns the currently programmed mode of the given pipe. */
-struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
-					     struct drm_crtc *crtc)
+static bool i9xx_crtc_get_mode(struct drm_crtc *crtc,
+			       struct drm_display_mode *mode)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
-	struct drm_display_mode *mode;
-	int htot = I915_READ(HTOTAL(cpu_transcoder));
-	int hsync = I915_READ(HSYNC(cpu_transcoder));
-	int vtot = I915_READ(VTOTAL(cpu_transcoder));
-	int vsync = I915_READ(VSYNC(cpu_transcoder));
+	u32 tmp;
 
-	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
-	if (!mode)
-		return NULL;
+	memset(mode, 0, sizeof(*mode));
+
+	tmp = I915_READ(HTOTAL(cpu_transcoder));
+	mode->hdisplay = (tmp & 0xffff) + 1;
+	mode->htotal = ((tmp & 0xffff0000) >> 16) + 1;
+
+	tmp = I915_READ(HSYNC(cpu_transcoder));
+	mode->hsync_start = (tmp & 0xffff) + 1;
+	mode->hsync_end = ((tmp & 0xffff0000) >> 16) + 1;
+
+	tmp = I915_READ(VTOTAL(cpu_transcoder));
+	mode->vdisplay = (tmp & 0xffff) + 1;
+	mode->vtotal = ((tmp & 0xffff0000) >> 16) + 1;
 
-	mode->clock = intel_crtc_clock_get(dev, crtc);
-	mode->hdisplay = (htot & 0xffff) + 1;
-	mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
-	mode->hsync_start = (hsync & 0xffff) + 1;
-	mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
-	mode->vdisplay = (vtot & 0xffff) + 1;
-	mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
-	mode->vsync_start = (vsync & 0xffff) + 1;
-	mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
+	tmp = I915_READ(VSYNC(cpu_transcoder));
+	mode->vsync_start = (tmp & 0xffff) + 1;
+	mode->vsync_end = ((tmp & 0xffff0000) >> 16) + 1;
+
+	mode->clock = i9xx_crtc_clock_get(crtc);
 
 	drm_mode_set_name(mode);
 
-	return mode;
+	return true;
+}
+
+static int ironlake_crtc_clock_get(struct drm_crtc *crtc)
+{
+	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+	int clock;
+	u32 link_m;
+
+	/*
+	 * PCH platforms make this easy: we can just use the LINK_M1 reg.
+	 * Note: this may be the pixel clock for a fitted mode, in which
+	 * case it won't match the native mode clock.  That means we won't be
+	 * able to do a simple flip in the fastboot case.
+	 */
+	link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder));
+
+	clock = link_m;
+
+	return clock;
+}
+
+static bool ironlake_crtc_get_mode(struct drm_crtc *crtc,
+				   struct drm_display_mode *mode)
+{
+	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+	u32 tmp;
+
+	memset(mode, 0, sizeof(*mode));
+
+	tmp = I915_READ(HTOTAL(cpu_transcoder));
+	mode->hdisplay = (tmp & 0xffff) + 1;
+	mode->htotal = ((tmp & 0xffff0000) >> 16) + 1;
+
+	tmp = I915_READ(HSYNC(cpu_transcoder));
+	mode->hsync_start = (tmp & 0xffff) + 1;
+	mode->hsync_end = ((tmp & 0xffff0000) >> 16) + 1;
+
+	tmp = I915_READ(VTOTAL(cpu_transcoder));
+	mode->vdisplay = (tmp & 0xffff) + 1;
+	mode->vtotal = ((tmp & 0xffff0000) >> 16) + 1;
+
+	tmp = I915_READ(VSYNC(cpu_transcoder));
+	mode->vsync_start = (tmp & 0xffff) + 1;
+	mode->vsync_end = ((tmp & 0xffff0000) >> 16) + 1;
+
+	mode->clock = ironlake_crtc_clock_get(crtc);
+
+	drm_mode_set_name(mode);
+
+	return true;
+}
+
+static __maybe_unused bool no_crtc_get_mode(struct drm_crtc *crtc,
+					    struct drm_display_mode *mode)
+{
+	return false;
+}
+
+bool intel_crtc_get_mode(struct drm_crtc *crtc,
+			 struct drm_display_mode *mode)
+{
+	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
+	return dev_priv->display.crtc_get_mode(crtc, mode);
 }
 
 static void intel_increase_pllclock(struct drm_crtc *crtc)
@@ -8632,19 +8702,24 @@ static void intel_init_display(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	dev_priv->display.crtc_get_mode = no_crtc_get_mode;
+
 	if (HAS_DDI(dev)) {
+		dev_priv->display.crtc_get_mode = ironlake_crtc_get_mode;
 		dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
 		dev_priv->display.crtc_enable = haswell_crtc_enable;
 		dev_priv->display.crtc_disable = haswell_crtc_disable;
 		dev_priv->display.off = haswell_crtc_off;
 		dev_priv->display.update_plane = ironlake_update_plane;
 	} else if (HAS_PCH_SPLIT(dev)) {
+		dev_priv->display.crtc_get_mode = ironlake_crtc_get_mode;
 		dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
 		dev_priv->display.crtc_enable = ironlake_crtc_enable;
 		dev_priv->display.crtc_disable = ironlake_crtc_disable;
 		dev_priv->display.off = ironlake_crtc_off;
 		dev_priv->display.update_plane = ironlake_update_plane;
 	} else {
+		dev_priv->display.crtc_get_mode = i9xx_crtc_get_mode;
 		dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
 		dev_priv->display.crtc_enable = i9xx_crtc_enable;
 		dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -9198,6 +9273,14 @@ setup_pipes:
 		DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
 			      crtc->base.base.id,
 			      crtc->active ? "enabled" : "disabled");
+
+
+		if (crtc->base.enabled)
+			crtc->mode_valid = intel_crtc_get_mode(&crtc->base, &crtc->base.mode);
+		if (crtc->mode_valid) {
+			DRM_DEBUG_KMS("found active mode: ");
+			drm_mode_debug_printmodeline(&crtc->base.mode);
+		}
 	}
 
 	if (HAS_DDI(dev))
@@ -9205,11 +9288,13 @@ setup_pipes:
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list,
 			    base.head) {
-		pipe = 0;
+		pipe = -1;
 
-		if (encoder->get_hw_state(encoder, &pipe)) {
-			encoder->base.crtc =
-				dev_priv->pipe_to_crtc_mapping[pipe];
+		if (encoder->get_hw_state(encoder, &pipe) && pipe != -1) {
+			crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+			if (crtc->mode_valid && encoder->get_mode_flags)
+				crtc->base.mode.flags |= encoder->get_mode_flags(encoder);
+			encoder->base.crtc = &crtc->base;
 		} else {
 			encoder->base.crtc = NULL;
 		}
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 2f2ec42..1262f25 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1369,6 +1369,27 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
 	return true;
 }
 
+static unsigned intel_dp_get_mode_flags(struct intel_encoder *encoder)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	u32 tmp, flags = 0;
+
+	tmp = I915_READ(intel_dp->output_reg);
+
+	if (tmp & DP_SYNC_HS_HIGH)
+		flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NHSYNC;
+
+	if (tmp & DP_SYNC_VS_HIGH)
+		flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NVSYNC;
+
+	return flags;
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -2951,6 +2972,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
 	intel_encoder->disable = intel_disable_dp;
 	intel_encoder->post_disable = intel_post_disable_dp;
 	intel_encoder->get_hw_state = intel_dp_get_hw_state;
+	intel_encoder->get_mode_flags = intel_dp_get_mode_flags;
 
 	intel_dig_port->port = port;
 	intel_dig_port->dp.output_reg = output_reg;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 52e4924..3036576 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -176,6 +176,9 @@ struct intel_encoder {
 	 * the encoder is active. If the encoder is enabled it also set the pipe
 	 * it is connected to in the pipe parameter. */
 	bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
+	/* Reconstructs the equivalent mode flags for the current hardware
+	 * state. */
+	unsigned (*get_mode_flags)(struct intel_encoder *);
 	int crtc_mask;
 };
 
@@ -586,8 +589,8 @@ extern void intel_connector_attach_encoder(struct intel_connector *connector,
 					   struct intel_encoder *encoder);
 extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
 
-extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
-						    struct drm_crtc *crtc);
+extern bool intel_crtc_get_mode(struct drm_crtc *crtc,
+				struct drm_display_mode *mode);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
 				struct drm_file *file_priv);
 extern enum transcoder
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 00e70db..c29094e 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -129,6 +129,22 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
 	return true;
 }
 
+static unsigned
+intel_dvo_get_mode_flags(struct intel_encoder *encoder)
+{
+	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+	u32 tmp, flags = 0;
+
+	tmp = I915_READ(intel_dvo->dev.dvo_reg);
+	if (tmp & DVO_HSYNC_ACTIVE_HIGH)
+		flags |= DRM_MODE_FLAG_PHSYNC;
+	if (tmp & DVO_VSYNC_ACTIVE_HIGH)
+		flags |= DRM_MODE_FLAG_PVSYNC;
+
+	return flags;
+}
+
 static void intel_disable_dvo(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -389,29 +405,26 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 	uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
-	struct drm_display_mode *mode = NULL;
+	struct drm_display_mode *fixed_mode = NULL;
 
 	/* If the DVO port is active, that'll be the LVDS, so we can pull out
 	 * its timings to get how the BIOS set up the panel.
 	 */
 	if (dvo_val & DVO_ENABLE) {
+		struct drm_display_mode mode;
 		struct drm_crtc *crtc;
 		int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
 
 		crtc = intel_get_crtc_for_pipe(dev, pipe);
-		if (crtc) {
-			mode = intel_crtc_mode_get(dev, crtc);
-			if (mode) {
-				mode->type |= DRM_MODE_TYPE_PREFERRED;
-				if (dvo_val & DVO_HSYNC_ACTIVE_HIGH)
-					mode->flags |= DRM_MODE_FLAG_PHSYNC;
-				if (dvo_val & DVO_VSYNC_ACTIVE_HIGH)
-					mode->flags |= DRM_MODE_FLAG_PVSYNC;
-			}
+		if (intel_crtc_get_mode(crtc, &mode))
+			fixed_mode = drm_mode_duplicate(dev, &mode);
+		if (fixed_mode) {
+			fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+			fixed_mode->flags = intel_dvo_get_mode_flags(&intel_dvo->base);
 		}
 	}
 
-	return mode;
+	return fixed_mode;
 }
 
 void intel_dvo_init(struct drm_device *dev)
@@ -440,6 +453,7 @@ void intel_dvo_init(struct drm_device *dev)
 	intel_encoder->disable = intel_disable_dvo;
 	intel_encoder->enable = intel_enable_dvo;
 	intel_encoder->get_hw_state = intel_dvo_get_hw_state;
+	intel_encoder->get_mode_flags = intel_dvo_get_mode_flags;
 	intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
 
 	/* Now, try to find a controller */
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 2474b1b..e953f7a 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -657,6 +657,27 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
 	return true;
 }
 
+static unsigned intel_hdmi_get_mode_flags(struct intel_encoder *encoder)
+{
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	u32 tmp, flags = 0;
+
+	tmp = I915_READ(intel_hdmi->hdmi_reg);
+
+	if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
+		flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NHSYNC;
+
+	if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
+		flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NVSYNC;
+
+	return flags;
+}
+
 static void intel_enable_hdmi(struct intel_encoder *encoder)
 {
 	struct drm_device *dev = encoder->base.dev;
@@ -1068,6 +1089,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
 	intel_encoder->enable = intel_enable_hdmi;
 	intel_encoder->disable = intel_disable_hdmi;
 	intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
+	intel_encoder->get_mode_flags = intel_hdmi_get_mode_flags;
 
 	intel_encoder->type = INTEL_OUTPUT_HDMI;
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 6ff145f..2530927 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -88,6 +88,26 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
 	return true;
 }
 
+static unsigned intel_lvds_get_mode_flags(struct intel_encoder *encoder)
+{
+	struct drm_device *dev = encoder->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 lvds_reg, tmp, flags = 0;
+
+	if (HAS_PCH_SPLIT(dev))
+		lvds_reg = PCH_LVDS;
+	else
+		lvds_reg = LVDS;
+
+	tmp = I915_READ(lvds_reg);
+	if (tmp & LVDS_HSYNC_POLARITY)
+		flags |= DRM_MODE_FLAG_NHSYNC;
+	if (tmp & LVDS_VSYNC_POLARITY)
+		flags |= DRM_MODE_FLAG_NVSYNC;
+
+	return flags;
+}
+
 /* The LVDS pin pair needs to be on before the DPLLs are enabled.
  * This is an exception to the general rule that mode_set doesn't turn
  * things on.
@@ -1107,6 +1127,7 @@ bool intel_lvds_init(struct drm_device *dev)
 	intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds;
 	intel_encoder->disable = intel_disable_lvds;
 	intel_encoder->get_hw_state = intel_lvds_get_hw_state;
+	intel_encoder->get_mode_flags = intel_lvds_get_mode_flags;
 	intel_connector->get_hw_state = intel_connector_get_hw_state;
 
 	intel_connector_attach_encoder(intel_connector, intel_encoder);
@@ -1218,11 +1239,15 @@ bool intel_lvds_init(struct drm_device *dev)
 	crtc = intel_get_crtc_for_pipe(dev, pipe);
 
 	if (crtc && (lvds & LVDS_PORT_EN)) {
-		fixed_mode = intel_crtc_mode_get(dev, crtc);
+		struct drm_display_mode mode;
+
+		if (intel_crtc_get_mode(crtc, &mode))
+			fixed_mode = drm_mode_duplicate(dev, &mode);
 		if (fixed_mode) {
 			DRM_DEBUG_KMS("using current (BIOS) mode: ");
 			drm_mode_debug_printmodeline(fixed_mode);
 			fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+			fixed_mode->flags = intel_lvds_get_mode_flags(intel_encoder);
 			goto out;
 		}
 	}
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 678c47c..1160092 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1254,6 +1254,27 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
 	return true;
 }
 
+static unsigned intel_sdvo_get_mode_flags(struct intel_encoder *encoder)
+{
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	u32 tmp, flags = 0;
+
+	tmp = I915_READ(intel_sdvo->sdvo_reg);
+
+	if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
+		flags |= DRM_MODE_FLAG_PHSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NHSYNC;
+
+	if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
+		flags |= DRM_MODE_FLAG_PVSYNC;
+	else
+		flags |= DRM_MODE_FLAG_NVSYNC;
+
+	return flags;
+}
+
 static void intel_disable_sdvo(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -2784,6 +2805,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
 	intel_encoder->disable = intel_disable_sdvo;
 	intel_encoder->enable = intel_enable_sdvo;
 	intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
+	if (INTEL_INFO(dev)->gen >= 4)
+		intel_encoder->get_mode_flags = intel_sdvo_get_mode_flags;
 
 	/* In default case sdvo lvds is false */
 	if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
-- 
1.7.9.5

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

* [PATCH 5/9] drm/i915: Only preserve the BIOS modes if they are the preferred ones
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
                   ` (3 preceding siblings ...)
  2013-03-26 23:33 ` [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2 Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  2013-03-26 23:33 ` [PATCH 6/9] drm/i915: Validate that the framebuffer accommodates the current mode Jesse Barnes
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

From: Chris Wilson <chris@chris-wilson.co.uk>

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_display.c |    9 +++++++++
 drivers/gpu/drm/i915/intel_dp.c      |    1 +
 drivers/gpu/drm/i915/intel_drv.h     |    8 ++++++++
 drivers/gpu/drm/i915/intel_fb.c      |    9 +++++++++
 drivers/gpu/drm/i915/intel_lvds.c    |    1 +
 drivers/gpu/drm/i915/intel_panel.c   |   10 ++++++++++
 6 files changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 35a1984..d1dd1ec 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9424,6 +9424,15 @@ void intel_connector_attach_encoder(struct intel_connector *connector,
 					  &encoder->base);
 }
 
+bool intel_connector_get_preferred_mode(struct intel_connector *connector,
+					struct drm_display_mode *mode)
+{
+	if (!connector->get_preferred_mode)
+		return false;
+
+	return connector->get_preferred_mode(connector, mode);
+}
+
 /*
  * set vga decode state - true == enable VGA decode
  */
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1262f25..e1b0c94 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2926,6 +2926,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	}
 
 	if (is_edp(intel_dp)) {
+		intel_connector->get_preferred_mode = intel_connector_get_panel_fixed_mode;
 		intel_panel_init(&intel_connector->panel, fixed_mode);
 		intel_panel_setup_backlight(connector);
 	}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3036576..37f4bb3 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -204,6 +204,9 @@ struct intel_connector {
 	 * and active (i.e. dpms ON state). */
 	bool (*get_hw_state)(struct intel_connector *);
 
+	bool (*get_preferred_mode)(struct intel_connector *,
+				   struct drm_display_mode *);
+
 	/* Panel info for eDP and LVDS */
 	struct intel_panel panel;
 
@@ -514,6 +517,9 @@ extern int intel_panel_init(struct intel_panel *panel,
 			    struct drm_display_mode *fixed_mode);
 extern void intel_panel_fini(struct intel_panel *panel);
 
+extern bool intel_connector_get_panel_fixed_mode(struct intel_connector *connector,
+						 struct drm_display_mode *mode);
+
 extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 				   struct drm_display_mode *adjusted_mode);
 extern void intel_pch_panel_fitting(struct drm_device *dev,
@@ -585,6 +591,8 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
 bool ibx_digital_port_connected(struct drm_i915_private *dev_priv,
 				struct intel_digital_port *port);
 
+extern bool intel_connector_get_preferred_mode(struct intel_connector *connector,
+					       struct drm_display_mode *mode);
 extern void intel_connector_attach_encoder(struct intel_connector *connector,
 					   struct intel_encoder *encoder);
 extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index f6746af..eb3a04e 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -218,6 +218,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 	for (i = 0; i < fb_helper->connector_count; i++) {
 		struct drm_connector *connector;
 		struct drm_encoder *encoder;
+		struct drm_display_mode mode;
 
 		connector = fb_helper->connector_info[i]->connector;
 		if (!enabled[i]) {
@@ -247,6 +248,14 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
 			return false;
 		}
 
+		if (intel_connector_get_preferred_mode(to_intel_connector(connector), &mode) &&
+		    !drm_mode_equal(&mode, &encoder->crtc->mode)) {
+			DRM_DEBUG_KMS("connector %s on crtc %d has an non-native mode, aborting\n",
+				      drm_get_connector_name(connector),
+				      encoder->crtc->base.id);
+			return false;
+		}
+
 		modes[i] = &encoder->crtc->mode;
 		crtcs[i] = intel_fb_helper_crtc(fb_helper, encoder->crtc);
 
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 2530927..e29bc72 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -1129,6 +1129,7 @@ bool intel_lvds_init(struct drm_device *dev)
 	intel_encoder->get_hw_state = intel_lvds_get_hw_state;
 	intel_encoder->get_mode_flags = intel_lvds_get_mode_flags;
 	intel_connector->get_hw_state = intel_connector_get_hw_state;
+	intel_connector->get_preferred_mode = intel_connector_get_panel_fixed_mode;
 
 	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	intel_encoder->type = INTEL_OUTPUT_LVDS;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index f1530f4..60bf3ce 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -35,6 +35,16 @@
 
 #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
 
+bool intel_connector_get_panel_fixed_mode(struct intel_connector *connector,
+					  struct drm_display_mode *mode)
+{
+	if (!connector->panel.fixed_mode)
+		return false;
+
+	*mode = *connector->panel.fixed_mode;
+	return true;
+}
+
 void
 intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 		       struct drm_display_mode *adjusted_mode)
-- 
1.7.9.5

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

* [PATCH 6/9] drm/i915: Validate that the framebuffer accommodates the current mode
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
                   ` (4 preceding siblings ...)
  2013-03-26 23:33 ` [PATCH 5/9] drm/i915: Only preserve the BIOS modes if they are the preferred ones Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  2013-03-26 23:33 ` [PATCH 7/9] drm/i915: check panel fit status at update_plane time v2 Jesse Barnes
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

From: Chris Wilson <chris@chris-wilson.co.uk>

As we retrieve the mode from the BIOS it may be constructed using
different assumptions for its configuration, such as utilizing the panel
fitter in a conflicting manner. As such the associated framebuffer may be
insufficient for our setup, and so we need to reject the current mode
and install our own.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_display.c |   38 +++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d1dd1ec..3741fe8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6580,27 +6580,40 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,
 	return intel_framebuffer_create(dev, &mode_cmd, obj);
 }
 
+static bool
+mode_fits_in_fb(struct drm_display_mode *mode,
+		struct drm_framebuffer *fb)
+{
+	struct drm_i915_gem_object *obj;
+	int min_pitch;
+
+	min_pitch = intel_framebuffer_pitch_for_width(mode->hdisplay,
+						      fb->bits_per_pixel);
+	if (fb->pitches[0] < min_pitch)
+		return false;
+
+	obj = to_intel_framebuffer(fb)->obj;
+	if (obj == NULL)
+		return false;
+
+	if (obj->base.size < mode->vdisplay * fb->pitches[0])
+		return false;
+
+	return true;
+}
+
 static struct drm_framebuffer *
 mode_fits_in_fbdev(struct drm_device *dev,
 		   struct drm_display_mode *mode)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_i915_gem_object *obj;
 	struct drm_framebuffer *fb;
 
 	if (dev_priv->fbdev == NULL)
 		return NULL;
 
-	obj = dev_priv->fbdev->ifb.obj;
-	if (obj == NULL)
-		return NULL;
-
 	fb = &dev_priv->fbdev->ifb.base;
-	if (fb->pitches[0] < intel_framebuffer_pitch_for_width(mode->hdisplay,
-							       fb->bits_per_pixel))
-		return NULL;
-
-	if (obj->base.size < mode->vdisplay * fb->pitches[0])
+	if (!mode_fits_in_fb(mode, fb))
 		return NULL;
 
 	return fb;
@@ -9277,6 +9290,11 @@ setup_pipes:
 
 		if (crtc->base.enabled)
 			crtc->mode_valid = intel_crtc_get_mode(&crtc->base, &crtc->base.mode);
+
+		if (crtc->base.fb &&
+		    !mode_fits_in_fb(&crtc->base.mode, crtc->base.fb))
+			crtc->mode_valid = false;
+
 		if (crtc->mode_valid) {
 			DRM_DEBUG_KMS("found active mode: ");
 			drm_mode_debug_printmodeline(&crtc->base.mode);
-- 
1.7.9.5

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

* [PATCH 7/9] drm/i915: check panel fit status at update_plane time v2
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
                   ` (5 preceding siblings ...)
  2013-03-26 23:33 ` [PATCH 6/9] drm/i915: Validate that the framebuffer accommodates the current mode Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  2013-03-26 23:33 ` [PATCH 8/9] drm/i915: treat no fb -> fb as simple flip instead of full mode set Jesse Barnes
  2013-03-26 23:33 ` [PATCH 9/9] drm/i915: add debug messages for mode_valid checks Jesse Barnes
  8 siblings, 0 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

We may need to disable the panel when flipping to a new buffer, so check
the state here and zero it out if needed, otherwise leave it alone.

v2: fixup pipe_set_base check (Imre)

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_display.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 3741fe8..0f3c036 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2363,6 +2363,18 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 		return ret;
 	}
 
+	/* Update pipe size and adjust fitter if needed */
+	I915_WRITE(PIPESRC(intel_crtc->pipe),
+		   ((crtc->mode.hdisplay - 1) << 16) |
+		   (crtc->mode.vdisplay - 1));
+	if (!dev_priv->pch_pf_size &&
+	    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
+	     intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
+		I915_WRITE(PF_CTL(intel_crtc->pipe), 0);
+		I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0);
+		I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0);
+	}
+
 	ret = dev_priv->display.update_plane(crtc, fb, x, y);
 	if (ret) {
 		intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
-- 
1.7.9.5

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

* [PATCH 8/9] drm/i915: treat no fb -> fb as simple flip instead of full mode set
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
                   ` (6 preceding siblings ...)
  2013-03-26 23:33 ` [PATCH 7/9] drm/i915: check panel fit status at update_plane time v2 Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  2013-03-27  0:03   ` Daniel Vetter
  2013-03-26 23:33 ` [PATCH 9/9] drm/i915: add debug messages for mode_valid checks Jesse Barnes
  8 siblings, 1 reply; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

In case we don't get an fb from the BIOS, we may still be able to re-use
existing state and flip a new buffer.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_display.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 0f3c036..f24da1a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8109,10 +8109,8 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
 	/* We should be able to check here if the fb has the same properties
 	 * and then just flip_or_move it */
 	if (set->crtc->fb != set->fb) {
-		/* If we have no fb then treat it as a full mode set */
 		if (set->crtc->fb == NULL) {
-			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
-			config->mode_changed = true;
+			config->fb_changed = true;
 		} else if (set->fb == NULL) {
 			config->mode_changed = true;
 		} else if (set->fb->depth != set->crtc->fb->depth) {
-- 
1.7.9.5

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

* [PATCH 9/9] drm/i915: add debug messages for mode_valid checks
  2013-03-26 23:33 Updated fastboot patches Jesse Barnes
                   ` (7 preceding siblings ...)
  2013-03-26 23:33 ` [PATCH 8/9] drm/i915: treat no fb -> fb as simple flip instead of full mode set Jesse Barnes
@ 2013-03-26 23:33 ` Jesse Barnes
  8 siblings, 0 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:33 UTC (permalink / raw)
  To: intel-gfx

Lets us see what's going on if we slowboot instead of fastboot.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
---
 drivers/gpu/drm/i915/intel_display.c |   11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f24da1a..8b55427 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9298,12 +9298,19 @@ setup_pipes:
 			      crtc->active ? "enabled" : "disabled");
 
 
-		if (crtc->base.enabled)
+		if (crtc->base.enabled) {
 			crtc->mode_valid = intel_crtc_get_mode(&crtc->base, &crtc->base.mode);
+			DRM_DEBUG_KMS("[CRTC:%d]: mode valid? %s\n",
+				      crtc->base.base.id,
+				      crtc->mode_valid ? "yes" : "no");
+		}
 
 		if (crtc->base.fb &&
-		    !mode_fits_in_fb(&crtc->base.mode, crtc->base.fb))
+		    !mode_fits_in_fb(&crtc->base.mode, crtc->base.fb)) {
 			crtc->mode_valid = false;
+			DRM_DEBUG_KMS("[CRTC:%d] mode doesn't fit in fb\n",
+				      crtc->base.base.id);
+		}
 
 		if (crtc->mode_valid) {
 			DRM_DEBUG_KMS("found active mode: ");
-- 
1.7.9.5

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

* Re: [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2
  2013-03-26 23:33 ` [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2 Jesse Barnes
@ 2013-03-26 23:36   ` Jesse Barnes
  2013-03-27  0:13   ` Daniel Vetter
  1 sibling, 0 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-26 23:36 UTC (permalink / raw)
  To: Jesse Barnes; +Cc: intel-gfx

On Tue, 26 Mar 2013 16:33:07 -0700
Jesse Barnes <jbarnes@virtuousgeek.org> wrote:

> Read the current hardware state to retrieve the active mode and populate
> our CRTC config if that mode matches our presumptions.
> 
> v2: check that get_hw_state gave us a valid pipe (Imre)
>     add clock_get for ILK+ (Jesse)
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

-- 
Jesse Barnes, Intel Open Source Technology Center

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

* Re: [PATCH 3/9] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v2
  2013-03-26 23:33 ` [PATCH 3/9] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v2 Jesse Barnes
@ 2013-03-26 23:53   ` Chris Wilson
  2013-03-27 14:07     ` Imre Deak
  0 siblings, 1 reply; 18+ messages in thread
From: Chris Wilson @ 2013-03-26 23:53 UTC (permalink / raw)
  To: Jesse Barnes; +Cc: intel-gfx

On Tue, Mar 26, 2013 at 04:33:06PM -0700, Jesse Barnes wrote:
> v2: check for non-native modes and adjust (Jesse)
>     fixup aperture and cmap frees (Imre)
The aperture is already freed via framebuffer_release(). And wrong
patch?
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre

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

* Re: [PATCH 8/9] drm/i915: treat no fb -> fb as simple flip instead of full mode set
  2013-03-26 23:33 ` [PATCH 8/9] drm/i915: treat no fb -> fb as simple flip instead of full mode set Jesse Barnes
@ 2013-03-27  0:03   ` Daniel Vetter
  0 siblings, 0 replies; 18+ messages in thread
From: Daniel Vetter @ 2013-03-27  0:03 UTC (permalink / raw)
  To: Jesse Barnes; +Cc: intel-gfx

On Tue, Mar 26, 2013 at 04:33:11PM -0700, Jesse Barnes wrote:
> In case we don't get an fb from the BIOS, we may still be able to re-use
> existing state and flip a new buffer.
> 
> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

This hack here smells extremely fishy. Where do we come up with no fb, but
a real mode and want to actually fastboot?
-Daniel

> ---
>  drivers/gpu/drm/i915/intel_display.c |    4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 0f3c036..f24da1a 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -8109,10 +8109,8 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
>  	/* We should be able to check here if the fb has the same properties
>  	 * and then just flip_or_move it */
>  	if (set->crtc->fb != set->fb) {
> -		/* If we have no fb then treat it as a full mode set */
>  		if (set->crtc->fb == NULL) {
> -			DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
> -			config->mode_changed = true;
> +			config->fb_changed = true;
>  		} else if (set->fb == NULL) {
>  			config->mode_changed = true;
>  		} else if (set->fb->depth != set->crtc->fb->depth) {
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2
  2013-03-26 23:33 ` [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2 Jesse Barnes
  2013-03-26 23:36   ` Jesse Barnes
@ 2013-03-27  0:13   ` Daniel Vetter
  2013-03-27 15:52     ` Jesse Barnes
  1 sibling, 1 reply; 18+ messages in thread
From: Daniel Vetter @ 2013-03-27  0:13 UTC (permalink / raw)
  To: Jesse Barnes; +Cc: intel-gfx

On Tue, Mar 26, 2013 at 04:33:07PM -0700, Jesse Barnes wrote:
> Read the current hardware state to retrieve the active mode and populate
> our CRTC config if that mode matches our presumptions.
> 
> v2: check that get_hw_state gave us a valid pipe (Imre)
>     add clock_get for ILK+ (Jesse)
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

Please preheat your wrath-dispenser ...

Atm the mode retrieval logic is smashed into setup_hw_state. Imo this
needs to be part of the general hw state readout, and for paranoia needs
to be of the usual cross-checking after each modeset.

Some later patches from my pipe_config series (after the pieces just
resend) add some basic infrastructure for this, including lax matching
ruels (e.g. for the clock cross-checking after a modeset, since we don't
yet put the _real_ hw dotclock into adjusted_mode->clock).

Cheers, Daniel

> ---
>  drivers/gpu/drm/i915/i915_drv.h      |    2 +
>  drivers/gpu/drm/i915/intel_crt.c     |   27 ++++++-
>  drivers/gpu/drm/i915/intel_display.c |  139 +++++++++++++++++++++++++++-------
>  drivers/gpu/drm/i915/intel_dp.c      |   22 ++++++
>  drivers/gpu/drm/i915/intel_drv.h     |    7 +-
>  drivers/gpu/drm/i915/intel_dvo.c     |   36 ++++++---
>  drivers/gpu/drm/i915/intel_hdmi.c    |   22 ++++++
>  drivers/gpu/drm/i915/intel_lvds.c    |   27 ++++++-
>  drivers/gpu/drm/i915/intel_sdvo.c    |   23 ++++++
>  9 files changed, 262 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index d32ed27..905ce86 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -283,6 +283,8 @@ struct drm_i915_display_funcs {
>  	void (*update_linetime_wm)(struct drm_device *dev, int pipe,
>  				 struct drm_display_mode *mode);
>  	void (*modeset_global_resources)(struct drm_device *dev);
> +	bool (*crtc_get_mode)(struct drm_crtc *crtc,
> +			     struct drm_display_mode *mode);
>  	int (*crtc_mode_set)(struct drm_crtc *crtc,
>  			     struct drm_display_mode *mode,
>  			     struct drm_display_mode *adjusted_mode,
> diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
> index 32a3693..da0ae7e 100644
> --- a/drivers/gpu/drm/i915/intel_crt.c
> +++ b/drivers/gpu/drm/i915/intel_crt.c
> @@ -81,6 +81,27 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
>  	return true;
>  }
>  
> +static unsigned intel_crt_get_mode_flags(struct intel_encoder *encoder)
> +{
> +	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
> +	struct intel_crt *crt = intel_encoder_to_crt(encoder);
> +	u32 tmp, flags = 0;
> +
> +	tmp = I915_READ(crt->adpa_reg);
> +
> +	if (tmp & ADPA_HSYNC_ACTIVE_HIGH)
> +		flags |= DRM_MODE_FLAG_PHSYNC;
> +	else
> +		flags |= DRM_MODE_FLAG_NHSYNC;
> +
> +	if (tmp & ADPA_VSYNC_ACTIVE_HIGH)
> +		flags |= DRM_MODE_FLAG_PVSYNC;
> +	else
> +		flags |= DRM_MODE_FLAG_NVSYNC;
> +
> +	return flags;
> +}
> +
>  static void intel_disable_crt(struct intel_encoder *encoder)
>  {
>  	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
> @@ -776,10 +797,12 @@ void intel_crt_init(struct drm_device *dev)
>  
>  	crt->base.disable = intel_disable_crt;
>  	crt->base.enable = intel_enable_crt;
> -	if (HAS_DDI(dev))
> +	if (HAS_DDI(dev)) {
>  		crt->base.get_hw_state = intel_ddi_get_hw_state;
> -	else
> +	} else {
>  		crt->base.get_hw_state = intel_crt_get_hw_state;
> +		crt->base.get_mode_flags = intel_crt_get_mode_flags;
> +	}
>  	intel_connector->get_hw_state = intel_connector_get_hw_state;
>  
>  	drm_encoder_helper_add(&crt->base.base, &crt_encoder_funcs);
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index a55ef8f..35a1984 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -6748,11 +6748,12 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
>  }
>  
>  /* Returns the clock of the currently programmed mode of the given pipe. */
> -static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
> +static int i9xx_crtc_clock_get(struct drm_crtc *crtc)
>  {
> +	struct drm_device *dev = crtc->dev;
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> -	int pipe = intel_crtc->pipe;
> +	enum pipe pipe = intel_crtc->pipe;
>  	u32 dpll = I915_READ(DPLL(pipe));
>  	u32 fp;
>  	intel_clock_t clock;
> @@ -6835,35 +6836,104 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
>  }
>  
>  /** Returns the currently programmed mode of the given pipe. */
> -struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
> -					     struct drm_crtc *crtc)
> +static bool i9xx_crtc_get_mode(struct drm_crtc *crtc,
> +			       struct drm_display_mode *mode)
>  {
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> +	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
> -	struct drm_display_mode *mode;
> -	int htot = I915_READ(HTOTAL(cpu_transcoder));
> -	int hsync = I915_READ(HSYNC(cpu_transcoder));
> -	int vtot = I915_READ(VTOTAL(cpu_transcoder));
> -	int vsync = I915_READ(VSYNC(cpu_transcoder));
> +	u32 tmp;
>  
> -	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
> -	if (!mode)
> -		return NULL;
> +	memset(mode, 0, sizeof(*mode));
> +
> +	tmp = I915_READ(HTOTAL(cpu_transcoder));
> +	mode->hdisplay = (tmp & 0xffff) + 1;
> +	mode->htotal = ((tmp & 0xffff0000) >> 16) + 1;
> +
> +	tmp = I915_READ(HSYNC(cpu_transcoder));
> +	mode->hsync_start = (tmp & 0xffff) + 1;
> +	mode->hsync_end = ((tmp & 0xffff0000) >> 16) + 1;
> +
> +	tmp = I915_READ(VTOTAL(cpu_transcoder));
> +	mode->vdisplay = (tmp & 0xffff) + 1;
> +	mode->vtotal = ((tmp & 0xffff0000) >> 16) + 1;
>  
> -	mode->clock = intel_crtc_clock_get(dev, crtc);
> -	mode->hdisplay = (htot & 0xffff) + 1;
> -	mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
> -	mode->hsync_start = (hsync & 0xffff) + 1;
> -	mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
> -	mode->vdisplay = (vtot & 0xffff) + 1;
> -	mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
> -	mode->vsync_start = (vsync & 0xffff) + 1;
> -	mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
> +	tmp = I915_READ(VSYNC(cpu_transcoder));
> +	mode->vsync_start = (tmp & 0xffff) + 1;
> +	mode->vsync_end = ((tmp & 0xffff0000) >> 16) + 1;
> +
> +	mode->clock = i9xx_crtc_clock_get(crtc);
>  
>  	drm_mode_set_name(mode);
>  
> -	return mode;
> +	return true;
> +}
> +
> +static int ironlake_crtc_clock_get(struct drm_crtc *crtc)
> +{
> +	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
> +	int clock;
> +	u32 link_m;
> +
> +	/*
> +	 * PCH platforms make this easy: we can just use the LINK_M1 reg.
> +	 * Note: this may be the pixel clock for a fitted mode, in which
> +	 * case it won't match the native mode clock.  That means we won't be
> +	 * able to do a simple flip in the fastboot case.
> +	 */
> +	link_m = I915_READ(PIPE_LINK_M1(cpu_transcoder));
> +
> +	clock = link_m;
> +
> +	return clock;
> +}
> +
> +static bool ironlake_crtc_get_mode(struct drm_crtc *crtc,
> +				   struct drm_display_mode *mode)
> +{
> +	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
> +	enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
> +	u32 tmp;
> +
> +	memset(mode, 0, sizeof(*mode));
> +
> +	tmp = I915_READ(HTOTAL(cpu_transcoder));
> +	mode->hdisplay = (tmp & 0xffff) + 1;
> +	mode->htotal = ((tmp & 0xffff0000) >> 16) + 1;
> +
> +	tmp = I915_READ(HSYNC(cpu_transcoder));
> +	mode->hsync_start = (tmp & 0xffff) + 1;
> +	mode->hsync_end = ((tmp & 0xffff0000) >> 16) + 1;
> +
> +	tmp = I915_READ(VTOTAL(cpu_transcoder));
> +	mode->vdisplay = (tmp & 0xffff) + 1;
> +	mode->vtotal = ((tmp & 0xffff0000) >> 16) + 1;
> +
> +	tmp = I915_READ(VSYNC(cpu_transcoder));
> +	mode->vsync_start = (tmp & 0xffff) + 1;
> +	mode->vsync_end = ((tmp & 0xffff0000) >> 16) + 1;
> +
> +	mode->clock = ironlake_crtc_clock_get(crtc);
> +
> +	drm_mode_set_name(mode);
> +
> +	return true;
> +}
> +
> +static __maybe_unused bool no_crtc_get_mode(struct drm_crtc *crtc,
> +					    struct drm_display_mode *mode)
> +{
> +	return false;
> +}
> +
> +bool intel_crtc_get_mode(struct drm_crtc *crtc,
> +			 struct drm_display_mode *mode)
> +{
> +	struct drm_i915_private *dev_priv = crtc->dev->dev_private;
> +	return dev_priv->display.crtc_get_mode(crtc, mode);
>  }
>  
>  static void intel_increase_pllclock(struct drm_crtc *crtc)
> @@ -8632,19 +8702,24 @@ static void intel_init_display(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  
> +	dev_priv->display.crtc_get_mode = no_crtc_get_mode;
> +
>  	if (HAS_DDI(dev)) {
> +		dev_priv->display.crtc_get_mode = ironlake_crtc_get_mode;
>  		dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
>  		dev_priv->display.crtc_enable = haswell_crtc_enable;
>  		dev_priv->display.crtc_disable = haswell_crtc_disable;
>  		dev_priv->display.off = haswell_crtc_off;
>  		dev_priv->display.update_plane = ironlake_update_plane;
>  	} else if (HAS_PCH_SPLIT(dev)) {
> +		dev_priv->display.crtc_get_mode = ironlake_crtc_get_mode;
>  		dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
>  		dev_priv->display.crtc_enable = ironlake_crtc_enable;
>  		dev_priv->display.crtc_disable = ironlake_crtc_disable;
>  		dev_priv->display.off = ironlake_crtc_off;
>  		dev_priv->display.update_plane = ironlake_update_plane;
>  	} else {
> +		dev_priv->display.crtc_get_mode = i9xx_crtc_get_mode;
>  		dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
>  		dev_priv->display.crtc_enable = i9xx_crtc_enable;
>  		dev_priv->display.crtc_disable = i9xx_crtc_disable;
> @@ -9198,6 +9273,14 @@ setup_pipes:
>  		DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n",
>  			      crtc->base.base.id,
>  			      crtc->active ? "enabled" : "disabled");
> +
> +
> +		if (crtc->base.enabled)
> +			crtc->mode_valid = intel_crtc_get_mode(&crtc->base, &crtc->base.mode);
> +		if (crtc->mode_valid) {
> +			DRM_DEBUG_KMS("found active mode: ");
> +			drm_mode_debug_printmodeline(&crtc->base.mode);
> +		}
>  	}
>  
>  	if (HAS_DDI(dev))
> @@ -9205,11 +9288,13 @@ setup_pipes:
>  
>  	list_for_each_entry(encoder, &dev->mode_config.encoder_list,
>  			    base.head) {
> -		pipe = 0;
> +		pipe = -1;
>  
> -		if (encoder->get_hw_state(encoder, &pipe)) {
> -			encoder->base.crtc =
> -				dev_priv->pipe_to_crtc_mapping[pipe];
> +		if (encoder->get_hw_state(encoder, &pipe) && pipe != -1) {
> +			crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
> +			if (crtc->mode_valid && encoder->get_mode_flags)
> +				crtc->base.mode.flags |= encoder->get_mode_flags(encoder);
> +			encoder->base.crtc = &crtc->base;
>  		} else {
>  			encoder->base.crtc = NULL;
>  		}
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 2f2ec42..1262f25 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1369,6 +1369,27 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
>  	return true;
>  }
>  
> +static unsigned intel_dp_get_mode_flags(struct intel_encoder *encoder)
> +{
> +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
> +	u32 tmp, flags = 0;
> +
> +	tmp = I915_READ(intel_dp->output_reg);
> +
> +	if (tmp & DP_SYNC_HS_HIGH)
> +		flags |= DRM_MODE_FLAG_PHSYNC;
> +	else
> +		flags |= DRM_MODE_FLAG_NHSYNC;
> +
> +	if (tmp & DP_SYNC_VS_HIGH)
> +		flags |= DRM_MODE_FLAG_PVSYNC;
> +	else
> +		flags |= DRM_MODE_FLAG_NVSYNC;
> +
> +	return flags;
> +}
> +
>  static void intel_disable_dp(struct intel_encoder *encoder)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> @@ -2951,6 +2972,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
>  	intel_encoder->disable = intel_disable_dp;
>  	intel_encoder->post_disable = intel_post_disable_dp;
>  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> +	intel_encoder->get_mode_flags = intel_dp_get_mode_flags;
>  
>  	intel_dig_port->port = port;
>  	intel_dig_port->dp.output_reg = output_reg;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 52e4924..3036576 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -176,6 +176,9 @@ struct intel_encoder {
>  	 * the encoder is active. If the encoder is enabled it also set the pipe
>  	 * it is connected to in the pipe parameter. */
>  	bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
> +	/* Reconstructs the equivalent mode flags for the current hardware
> +	 * state. */
> +	unsigned (*get_mode_flags)(struct intel_encoder *);
>  	int crtc_mask;
>  };
>  
> @@ -586,8 +589,8 @@ extern void intel_connector_attach_encoder(struct intel_connector *connector,
>  					   struct intel_encoder *encoder);
>  extern struct drm_encoder *intel_best_encoder(struct drm_connector *connector);
>  
> -extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
> -						    struct drm_crtc *crtc);
> +extern bool intel_crtc_get_mode(struct drm_crtc *crtc,
> +				struct drm_display_mode *mode);
>  int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
>  				struct drm_file *file_priv);
>  extern enum transcoder
> diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
> index 00e70db..c29094e 100644
> --- a/drivers/gpu/drm/i915/intel_dvo.c
> +++ b/drivers/gpu/drm/i915/intel_dvo.c
> @@ -129,6 +129,22 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
>  	return true;
>  }
>  
> +static unsigned
> +intel_dvo_get_mode_flags(struct intel_encoder *encoder)
> +{
> +	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
> +	struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
> +	u32 tmp, flags = 0;
> +
> +	tmp = I915_READ(intel_dvo->dev.dvo_reg);
> +	if (tmp & DVO_HSYNC_ACTIVE_HIGH)
> +		flags |= DRM_MODE_FLAG_PHSYNC;
> +	if (tmp & DVO_VSYNC_ACTIVE_HIGH)
> +		flags |= DRM_MODE_FLAG_PVSYNC;
> +
> +	return flags;
> +}
> +
>  static void intel_disable_dvo(struct intel_encoder *encoder)
>  {
>  	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
> @@ -389,29 +405,26 @@ intel_dvo_get_current_mode(struct drm_connector *connector)
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
>  	uint32_t dvo_val = I915_READ(intel_dvo->dev.dvo_reg);
> -	struct drm_display_mode *mode = NULL;
> +	struct drm_display_mode *fixed_mode = NULL;
>  
>  	/* If the DVO port is active, that'll be the LVDS, so we can pull out
>  	 * its timings to get how the BIOS set up the panel.
>  	 */
>  	if (dvo_val & DVO_ENABLE) {
> +		struct drm_display_mode mode;
>  		struct drm_crtc *crtc;
>  		int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
>  
>  		crtc = intel_get_crtc_for_pipe(dev, pipe);
> -		if (crtc) {
> -			mode = intel_crtc_mode_get(dev, crtc);
> -			if (mode) {
> -				mode->type |= DRM_MODE_TYPE_PREFERRED;
> -				if (dvo_val & DVO_HSYNC_ACTIVE_HIGH)
> -					mode->flags |= DRM_MODE_FLAG_PHSYNC;
> -				if (dvo_val & DVO_VSYNC_ACTIVE_HIGH)
> -					mode->flags |= DRM_MODE_FLAG_PVSYNC;
> -			}
> +		if (intel_crtc_get_mode(crtc, &mode))
> +			fixed_mode = drm_mode_duplicate(dev, &mode);
> +		if (fixed_mode) {
> +			fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
> +			fixed_mode->flags = intel_dvo_get_mode_flags(&intel_dvo->base);
>  		}
>  	}
>  
> -	return mode;
> +	return fixed_mode;
>  }
>  
>  void intel_dvo_init(struct drm_device *dev)
> @@ -440,6 +453,7 @@ void intel_dvo_init(struct drm_device *dev)
>  	intel_encoder->disable = intel_disable_dvo;
>  	intel_encoder->enable = intel_enable_dvo;
>  	intel_encoder->get_hw_state = intel_dvo_get_hw_state;
> +	intel_encoder->get_mode_flags = intel_dvo_get_mode_flags;
>  	intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
>  
>  	/* Now, try to find a controller */
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 2474b1b..e953f7a 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -657,6 +657,27 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
>  	return true;
>  }
>  
> +static unsigned intel_hdmi_get_mode_flags(struct intel_encoder *encoder)
> +{
> +	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
> +	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
> +	u32 tmp, flags = 0;
> +
> +	tmp = I915_READ(intel_hdmi->hdmi_reg);
> +
> +	if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
> +		flags |= DRM_MODE_FLAG_PHSYNC;
> +	else
> +		flags |= DRM_MODE_FLAG_NHSYNC;
> +
> +	if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
> +		flags |= DRM_MODE_FLAG_PVSYNC;
> +	else
> +		flags |= DRM_MODE_FLAG_NVSYNC;
> +
> +	return flags;
> +}
> +
>  static void intel_enable_hdmi(struct intel_encoder *encoder)
>  {
>  	struct drm_device *dev = encoder->base.dev;
> @@ -1068,6 +1089,7 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
>  	intel_encoder->enable = intel_enable_hdmi;
>  	intel_encoder->disable = intel_disable_hdmi;
>  	intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
> +	intel_encoder->get_mode_flags = intel_hdmi_get_mode_flags;
>  
>  	intel_encoder->type = INTEL_OUTPUT_HDMI;
>  	intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
> diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
> index 6ff145f..2530927 100644
> --- a/drivers/gpu/drm/i915/intel_lvds.c
> +++ b/drivers/gpu/drm/i915/intel_lvds.c
> @@ -88,6 +88,26 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
>  	return true;
>  }
>  
> +static unsigned intel_lvds_get_mode_flags(struct intel_encoder *encoder)
> +{
> +	struct drm_device *dev = encoder->base.dev;
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	u32 lvds_reg, tmp, flags = 0;
> +
> +	if (HAS_PCH_SPLIT(dev))
> +		lvds_reg = PCH_LVDS;
> +	else
> +		lvds_reg = LVDS;
> +
> +	tmp = I915_READ(lvds_reg);
> +	if (tmp & LVDS_HSYNC_POLARITY)
> +		flags |= DRM_MODE_FLAG_NHSYNC;
> +	if (tmp & LVDS_VSYNC_POLARITY)
> +		flags |= DRM_MODE_FLAG_NVSYNC;
> +
> +	return flags;
> +}
> +
>  /* The LVDS pin pair needs to be on before the DPLLs are enabled.
>   * This is an exception to the general rule that mode_set doesn't turn
>   * things on.
> @@ -1107,6 +1127,7 @@ bool intel_lvds_init(struct drm_device *dev)
>  	intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds;
>  	intel_encoder->disable = intel_disable_lvds;
>  	intel_encoder->get_hw_state = intel_lvds_get_hw_state;
> +	intel_encoder->get_mode_flags = intel_lvds_get_mode_flags;
>  	intel_connector->get_hw_state = intel_connector_get_hw_state;
>  
>  	intel_connector_attach_encoder(intel_connector, intel_encoder);
> @@ -1218,11 +1239,15 @@ bool intel_lvds_init(struct drm_device *dev)
>  	crtc = intel_get_crtc_for_pipe(dev, pipe);
>  
>  	if (crtc && (lvds & LVDS_PORT_EN)) {
> -		fixed_mode = intel_crtc_mode_get(dev, crtc);
> +		struct drm_display_mode mode;
> +
> +		if (intel_crtc_get_mode(crtc, &mode))
> +			fixed_mode = drm_mode_duplicate(dev, &mode);
>  		if (fixed_mode) {
>  			DRM_DEBUG_KMS("using current (BIOS) mode: ");
>  			drm_mode_debug_printmodeline(fixed_mode);
>  			fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
> +			fixed_mode->flags = intel_lvds_get_mode_flags(intel_encoder);
>  			goto out;
>  		}
>  	}
> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> index 678c47c..1160092 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> @@ -1254,6 +1254,27 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
>  	return true;
>  }
>  
> +static unsigned intel_sdvo_get_mode_flags(struct intel_encoder *encoder)
> +{
> +	struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
> +	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
> +	u32 tmp, flags = 0;
> +
> +	tmp = I915_READ(intel_sdvo->sdvo_reg);
> +
> +	if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
> +		flags |= DRM_MODE_FLAG_PHSYNC;
> +	else
> +		flags |= DRM_MODE_FLAG_NHSYNC;
> +
> +	if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
> +		flags |= DRM_MODE_FLAG_PVSYNC;
> +	else
> +		flags |= DRM_MODE_FLAG_NVSYNC;
> +
> +	return flags;
> +}
> +
>  static void intel_disable_sdvo(struct intel_encoder *encoder)
>  {
>  	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
> @@ -2784,6 +2805,8 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
>  	intel_encoder->disable = intel_disable_sdvo;
>  	intel_encoder->enable = intel_enable_sdvo;
>  	intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
> +	if (INTEL_INFO(dev)->gen >= 4)
> +		intel_encoder->get_mode_flags = intel_sdvo_get_mode_flags;
>  
>  	/* In default case sdvo lvds is false */
>  	if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
> -- 
> 1.7.9.5
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH 3/9] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v2
  2013-03-26 23:53   ` Chris Wilson
@ 2013-03-27 14:07     ` Imre Deak
  0 siblings, 0 replies; 18+ messages in thread
From: Imre Deak @ 2013-03-27 14:07 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

On Tue, 2013-03-26 at 23:53 +0000, Chris Wilson wrote:
> On Tue, Mar 26, 2013 at 04:33:06PM -0700, Jesse Barnes wrote:
> > v2: check for non-native modes and adjust (Jesse)
> >     fixup aperture and cmap frees (Imre)
> The aperture is already freed via framebuffer_release(). And wrong
> patch?

Ah, haven't checked in there.. So aperture shouldn't be freed by us.

--Imre

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

* Re: [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2
  2013-03-27  0:13   ` Daniel Vetter
@ 2013-03-27 15:52     ` Jesse Barnes
  0 siblings, 0 replies; 18+ messages in thread
From: Jesse Barnes @ 2013-03-27 15:52 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: intel-gfx

On Wed, 27 Mar 2013 01:13:48 +0100
Daniel Vetter <daniel@ffwll.ch> wrote:

> On Tue, Mar 26, 2013 at 04:33:07PM -0700, Jesse Barnes wrote:
> > Read the current hardware state to retrieve the active mode and populate
> > our CRTC config if that mode matches our presumptions.
> > 
> > v2: check that get_hw_state gave us a valid pipe (Imre)
> >     add clock_get for ILK+ (Jesse)
> > 
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> 
> Please preheat your wrath-dispenser ...
> 
> Atm the mode retrieval logic is smashed into setup_hw_state. Imo this
> needs to be part of the general hw state readout, and for paranoia needs
> to be of the usual cross-checking after each modeset.

I was thinking about this last night too; I don't like reading the
state in the fb layer either, it really belongs in intel_display
somewhere.

> Some later patches from my pipe_config series (after the pieces just
> resend) add some basic infrastructure for this, including lax matching
> ruels (e.g. for the clock cross-checking after a modeset, since we don't
> yet put the _real_ hw dotclock into adjusted_mode->clock).

I'll check it out.

Thanks,
-- 
Jesse Barnes, Intel Open Source Technology Center

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

* Re: [PATCH 1/9] drm/i915: Skip modifying PCH DREF if not changing clock sources
  2013-03-26 23:33 ` [PATCH 1/9] drm/i915: Skip modifying PCH DREF if not changing clock sources Jesse Barnes
@ 2013-03-28  7:27   ` Jani Nikula
  2013-04-02 17:53     ` Daniel Vetter
  0 siblings, 1 reply; 18+ messages in thread
From: Jani Nikula @ 2013-03-28  7:27 UTC (permalink / raw)
  To: Jesse Barnes, intel-gfx

On Wed, 27 Mar 2013, Jesse Barnes <jbarnes@virtuousgeek.org> wrote:
> From: Chris Wilson <chris@chris-wilson.co.uk>
>
> Modifying the clock sources (via the DREF control on the PCH) is a slow
> multi-stage process as we need to let the clocks stabilise between each
> stage. If we are not actually changing the clock sources, then we can
> return early.
>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/intel_display.c |   83 +++++++++++++++++++++++++---------
>  1 file changed, 61 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index 8f0db8c..9d05b30 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -4833,7 +4833,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
>  	struct drm_i915_private *dev_priv = dev->dev_private;
>  	struct drm_mode_config *mode_config = &dev->mode_config;
>  	struct intel_encoder *encoder;
> -	u32 temp;
> +	u32 val, final;
>  	bool has_lvds = false;
>  	bool has_cpu_edp = false;
>  	bool has_pch_edp = false;
> @@ -4876,70 +4876,109 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
>  	 * PCH B stepping, previous chipset stepping should be
>  	 * ignoring this setting.
>  	 */
> -	temp = I915_READ(PCH_DREF_CONTROL);
> +	val = I915_READ(PCH_DREF_CONTROL);
> +
> +	/* As we must carefully and slowly disable/enable each source in turn,
> +	 * compute the final state we want first and check if we need to
> +	 * make any changes at all.
> +	 */
> +	final = val;
> +	final &= ~DREF_NONSPREAD_SOURCE_MASK;
> +	if (has_ck505)
> +		final |= DREF_NONSPREAD_CK505_ENABLE;
> +	else
> +		final |= DREF_NONSPREAD_SOURCE_ENABLE;
> +
> +	final &= ~DREF_SSC_SOURCE_MASK;
> +	final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> +	final &= ~DREF_SSC1_ENABLE;
> +
> +	if (has_panel) {
> +		final |= DREF_SSC_SOURCE_ENABLE;
> +
> +		if (intel_panel_use_ssc(dev_priv) && can_ssc)
> +			final |= DREF_SSC1_ENABLE;
> +
> +		if (has_cpu_edp) {
> +			if (intel_panel_use_ssc(dev_priv) && can_ssc)
> +				final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
> +			else
> +				final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
> +		} else
> +			final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;

I've been assimilated, I dislike not having braces in all branches if
one branch requires them... but that's bikeshedding. On the stuff that
matters,

Reviewed-by: Jani Nikula <jani.nikula@intel.com>

> +	} else {
> +		final |= DREF_SSC_SOURCE_DISABLE;
> +		final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> +	}
> +
> +	if (final == val)
> +		return;
> +
>  	/* Always enable nonspread source */
> -	temp &= ~DREF_NONSPREAD_SOURCE_MASK;
> +	val &= ~DREF_NONSPREAD_SOURCE_MASK;
>  
>  	if (has_ck505)
> -		temp |= DREF_NONSPREAD_CK505_ENABLE;
> +		val |= DREF_NONSPREAD_CK505_ENABLE;
>  	else
> -		temp |= DREF_NONSPREAD_SOURCE_ENABLE;
> +		val |= DREF_NONSPREAD_SOURCE_ENABLE;
>  
>  	if (has_panel) {
> -		temp &= ~DREF_SSC_SOURCE_MASK;
> -		temp |= DREF_SSC_SOURCE_ENABLE;
> +		val &= ~DREF_SSC_SOURCE_MASK;
> +		val |= DREF_SSC_SOURCE_ENABLE;
>  
>  		/* SSC must be turned on before enabling the CPU output  */
>  		if (intel_panel_use_ssc(dev_priv) && can_ssc) {
>  			DRM_DEBUG_KMS("Using SSC on panel\n");
> -			temp |= DREF_SSC1_ENABLE;
> +			val |= DREF_SSC1_ENABLE;
>  		} else
> -			temp &= ~DREF_SSC1_ENABLE;
> +			val &= ~DREF_SSC1_ENABLE;
>  
>  		/* Get SSC going before enabling the outputs */
> -		I915_WRITE(PCH_DREF_CONTROL, temp);
> +		I915_WRITE(PCH_DREF_CONTROL, val);
>  		POSTING_READ(PCH_DREF_CONTROL);
>  		udelay(200);
>  
> -		temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> +		val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
>  
>  		/* Enable CPU source on CPU attached eDP */
>  		if (has_cpu_edp) {
>  			if (intel_panel_use_ssc(dev_priv) && can_ssc) {
>  				DRM_DEBUG_KMS("Using SSC on eDP\n");
> -				temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
> +				val |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
>  			}
>  			else
> -				temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
> +				val |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
>  		} else
> -			temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> +			val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
>  
> -		I915_WRITE(PCH_DREF_CONTROL, temp);
> +		I915_WRITE(PCH_DREF_CONTROL, val);
>  		POSTING_READ(PCH_DREF_CONTROL);
>  		udelay(200);
>  	} else {
>  		DRM_DEBUG_KMS("Disabling SSC entirely\n");
>  
> -		temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> +		val &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
>  
>  		/* Turn off CPU output */
> -		temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> +		val |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
>  
> -		I915_WRITE(PCH_DREF_CONTROL, temp);
> +		I915_WRITE(PCH_DREF_CONTROL, val);
>  		POSTING_READ(PCH_DREF_CONTROL);
>  		udelay(200);
>  
>  		/* Turn off the SSC source */
> -		temp &= ~DREF_SSC_SOURCE_MASK;
> -		temp |= DREF_SSC_SOURCE_DISABLE;
> +		val &= ~DREF_SSC_SOURCE_MASK;
> +		val |= DREF_SSC_SOURCE_DISABLE;
>  
>  		/* Turn off SSC1 */
> -		temp &= ~ DREF_SSC1_ENABLE;
> +		val &= ~ DREF_SSC1_ENABLE;
>  
> -		I915_WRITE(PCH_DREF_CONTROL, temp);
> +		I915_WRITE(PCH_DREF_CONTROL, val);
>  		POSTING_READ(PCH_DREF_CONTROL);
>  		udelay(200);
>  	}
> +
> +	BUG_ON(val != final);
>  }
>  
>  /* Sequence to enable CLKOUT_DP for FDI usage and configure PCH FDI I/O. */
> -- 
> 1.7.9.5
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 1/9] drm/i915: Skip modifying PCH DREF if not changing clock sources
  2013-03-28  7:27   ` Jani Nikula
@ 2013-04-02 17:53     ` Daniel Vetter
  0 siblings, 0 replies; 18+ messages in thread
From: Daniel Vetter @ 2013-04-02 17:53 UTC (permalink / raw)
  To: Jani Nikula; +Cc: intel-gfx

On Thu, Mar 28, 2013 at 09:27:31AM +0200, Jani Nikula wrote:
> On Wed, 27 Mar 2013, Jesse Barnes <jbarnes@virtuousgeek.org> wrote:
> > From: Chris Wilson <chris@chris-wilson.co.uk>
> >
> > Modifying the clock sources (via the DREF control on the PCH) is a slow
> > multi-stage process as we need to let the clocks stabilise between each
> > stage. If we are not actually changing the clock sources, then we can
> > return early.
> >
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > ---
> >  drivers/gpu/drm/i915/intel_display.c |   83 +++++++++++++++++++++++++---------
> >  1 file changed, 61 insertions(+), 22 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 8f0db8c..9d05b30 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -4833,7 +4833,7 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
> >  	struct drm_i915_private *dev_priv = dev->dev_private;
> >  	struct drm_mode_config *mode_config = &dev->mode_config;
> >  	struct intel_encoder *encoder;
> > -	u32 temp;
> > +	u32 val, final;
> >  	bool has_lvds = false;
> >  	bool has_cpu_edp = false;
> >  	bool has_pch_edp = false;
> > @@ -4876,70 +4876,109 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
> >  	 * PCH B stepping, previous chipset stepping should be
> >  	 * ignoring this setting.
> >  	 */
> > -	temp = I915_READ(PCH_DREF_CONTROL);
> > +	val = I915_READ(PCH_DREF_CONTROL);
> > +
> > +	/* As we must carefully and slowly disable/enable each source in turn,
> > +	 * compute the final state we want first and check if we need to
> > +	 * make any changes at all.
> > +	 */
> > +	final = val;
> > +	final &= ~DREF_NONSPREAD_SOURCE_MASK;
> > +	if (has_ck505)
> > +		final |= DREF_NONSPREAD_CK505_ENABLE;
> > +	else
> > +		final |= DREF_NONSPREAD_SOURCE_ENABLE;
> > +
> > +	final &= ~DREF_SSC_SOURCE_MASK;
> > +	final &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
> > +	final &= ~DREF_SSC1_ENABLE;
> > +
> > +	if (has_panel) {
> > +		final |= DREF_SSC_SOURCE_ENABLE;
> > +
> > +		if (intel_panel_use_ssc(dev_priv) && can_ssc)
> > +			final |= DREF_SSC1_ENABLE;
> > +
> > +		if (has_cpu_edp) {
> > +			if (intel_panel_use_ssc(dev_priv) && can_ssc)
> > +				final |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
> > +			else
> > +				final |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
> > +		} else
> > +			final |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
> 
> I've been assimilated, I dislike not having braces in all branches if
> one branch requires them... but that's bikeshedding. On the stuff that
> matters,

I've punted on this bikeshed (checkpatch didn't yell), but fixed another
one ;-)
> 
> Reviewed-by: Jani Nikula <jani.nikula@intel.com>

I've figured that speeding this up and moving it into
->global_modeset_resources are rather orthogonal, since even with fastboot
we might want to adjust pm state a bit (e.g. with the power wells stuff).
So even when this is move into the modeset code and thought more clever
tricks, we'll still run it in the boot-up modeset path.

Queued for -next, thanks for the patch.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

end of thread, other threads:[~2013-04-02 17:51 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-26 23:33 Updated fastboot patches Jesse Barnes
2013-03-26 23:33 ` [PATCH 1/9] drm/i915: Skip modifying PCH DREF if not changing clock sources Jesse Barnes
2013-03-28  7:27   ` Jani Nikula
2013-04-02 17:53     ` Daniel Vetter
2013-03-26 23:33 ` [PATCH 2/9] drm/i915: Split the framebuffer_info creation into a separate routine Jesse Barnes
2013-03-26 23:33 ` [PATCH 3/9] drm/i915: Wrap the preallocated BIOS framebuffer and preserve for KMS fbcon v2 Jesse Barnes
2013-03-26 23:53   ` Chris Wilson
2013-03-27 14:07     ` Imre Deak
2013-03-26 23:33 ` [PATCH 4/9] drm/i915: Retrieve the current mode upon KMS takeover v2 Jesse Barnes
2013-03-26 23:36   ` Jesse Barnes
2013-03-27  0:13   ` Daniel Vetter
2013-03-27 15:52     ` Jesse Barnes
2013-03-26 23:33 ` [PATCH 5/9] drm/i915: Only preserve the BIOS modes if they are the preferred ones Jesse Barnes
2013-03-26 23:33 ` [PATCH 6/9] drm/i915: Validate that the framebuffer accommodates the current mode Jesse Barnes
2013-03-26 23:33 ` [PATCH 7/9] drm/i915: check panel fit status at update_plane time v2 Jesse Barnes
2013-03-26 23:33 ` [PATCH 8/9] drm/i915: treat no fb -> fb as simple flip instead of full mode set Jesse Barnes
2013-03-27  0:03   ` Daniel Vetter
2013-03-26 23:33 ` [PATCH 9/9] drm/i915: add debug messages for mode_valid checks Jesse Barnes

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.