Merge remote branch 'intel/drm-intel-next' of ../drm-next into drm-core-next

* 'intel/drm-intel-next' of ../drm-next: (266 commits)
  drm/i915: Avoid circular locking from intel_fbdev_fini()
  drm/i915: mark display port DPMS state as 'ON' when enabling output
  drm/i915: Skip pread/pwrite if size to copy is 0.
  drm/i915: avoid struct mutex output_poll mutex lock loop on unload
  drm/i915: Rephrase pwrite bounds checking to avoid any potential overflow
  drm/i915: Sanity check pread/pwrite
  drm/i915: Use pipe state to tell when pipe is off
  drm/i915: vblank status not valid while training display port
  drivers/gpu/drm/i915/i915_gem.c: Add missing error handling code
  drm/i915: Don't mask the return code whilst relocating.
  drm/i915: If the GPU hangs twice within 5 seconds, declare it wedged.
  drm/i915: Only print 'generating error event' if we actually are
  drm/i915: Try to reset gen2 devices.
  drm/i915: Clear fence registers on GPU reset
  drm/i915: Force the domain to CPU on unbinding whilst wedged.
  drm: Move the GTT accounting to i915
  drm/i915: Fix refleak during eviction.
  i915: Added function to initialize VBT settings
  drm/i915: Remove redundant deletion of obj->gpu_write_list
  drm/i915: Make get/put pages static
  ...
diff --git a/MAINTAINERS b/MAINTAINERS
index df34283..534f4d0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2051,6 +2051,15 @@
 F:	drivers/gpu/drm/
 F:	include/drm/
 
+INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
+M:	Chris Wilson <chris@chris-wilson.co.uk>
+L:	intel-gfx@lists.freedesktop.org
+L:	dri-devel@lists.freedesktop.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git
+S:	Supported
+F:	drivers/gpu/drm/i915
+F:	include/drm/i915*
+
 DSCC4 DRIVER
 M:	Francois Romieu <romieu@fr.zoreil.com>
 L:	netdev@vger.kernel.org
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index 627f542..8eb56e2 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_AGP_PARISC)	+= parisc-agp.o
 obj-$(CONFIG_AGP_I460)		+= i460-agp.o
 obj-$(CONFIG_AGP_INTEL)		+= intel-agp.o
+obj-$(CONFIG_AGP_INTEL)		+= intel-gtt.o
 obj-$(CONFIG_AGP_NVIDIA)	+= nvidia-agp.o
 obj-$(CONFIG_AGP_SGI_TIOCA)	+= sgi-agp.o
 obj-$(CONFIG_AGP_SIS)		+= sis-agp.o
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 1204909..5259065 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -121,11 +121,6 @@
 	void (*agp_destroy_pages)(struct agp_memory *);
 	int (*agp_type_to_mask_type) (struct agp_bridge_data *, int);
 	void (*chipset_flush)(struct agp_bridge_data *);
-
-	int (*agp_map_page)(struct page *page, dma_addr_t *ret);
-	void (*agp_unmap_page)(struct page *page, dma_addr_t dma);
-	int (*agp_map_memory)(struct agp_memory *mem);
-	void (*agp_unmap_memory)(struct agp_memory *mem);
 };
 
 struct agp_bridge_data {
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index ee4f855..f27d0d0 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -151,17 +151,7 @@
 		}
 
 		bridge->scratch_page_page = page;
-		if (bridge->driver->agp_map_page) {
-			if (bridge->driver->agp_map_page(page,
-							 &bridge->scratch_page_dma)) {
-				dev_err(&bridge->dev->dev,
-					"unable to dma-map scratch page\n");
-				rc = -ENOMEM;
-				goto err_out_nounmap;
-			}
-		} else {
-			bridge->scratch_page_dma = page_to_phys(page);
-		}
+		bridge->scratch_page_dma = page_to_phys(page);
 
 		bridge->scratch_page = bridge->driver->mask_memory(bridge,
 						   bridge->scratch_page_dma, 0);
@@ -204,12 +194,6 @@
 	return 0;
 
 err_out:
-	if (bridge->driver->needs_scratch_page &&
-	    bridge->driver->agp_unmap_page) {
-		bridge->driver->agp_unmap_page(bridge->scratch_page_page,
-					       bridge->scratch_page_dma);
-	}
-err_out_nounmap:
 	if (bridge->driver->needs_scratch_page) {
 		void *va = page_address(bridge->scratch_page_page);
 
@@ -240,10 +224,6 @@
 	    bridge->driver->needs_scratch_page) {
 		void *va = page_address(bridge->scratch_page_page);
 
-		if (bridge->driver->agp_unmap_page)
-			bridge->driver->agp_unmap_page(bridge->scratch_page_page,
-						       bridge->scratch_page_dma);
-
 		bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
 		bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
 	}
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index d2abf51..78235ce 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -437,11 +437,6 @@
 		curr->is_flushed = true;
 	}
 
-	if (curr->bridge->driver->agp_map_memory) {
-		ret_val = curr->bridge->driver->agp_map_memory(curr);
-		if (ret_val)
-			return ret_val;
-	}
 	ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type);
 
 	if (ret_val != 0)
@@ -483,9 +478,6 @@
 	if (ret_val != 0)
 		return ret_val;
 
-	if (curr->bridge->driver->agp_unmap_memory)
-		curr->bridge->driver->agp_unmap_memory(curr);
-
 	curr->is_bound = false;
 	curr->pg_start = 0;
 	spin_lock(&curr->bridge->mapped_lock);
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index cd18493..5cd2221 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -12,9 +12,6 @@
 #include <asm/smp.h>
 #include "agp.h"
 #include "intel-agp.h"
-#include <linux/intel-gtt.h>
-
-#include "intel-gtt.c"
 
 int intel_agp_enabled;
 EXPORT_SYMBOL(intel_agp_enabled);
@@ -703,179 +700,37 @@
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static int find_gmch(u16 device)
-{
-	struct pci_dev *gmch_device;
-
-	gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
-	if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
-		gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
-					     device, gmch_device);
-	}
-
-	if (!gmch_device)
-		return 0;
-
-	intel_private.pcidev = gmch_device;
-	return 1;
-}
-
 /* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
  * driver and gmch_driver must be non-null, and find_gmch will determine
  * which one should be used if a gmch_chip_id is present.
  */
-static const struct intel_driver_description {
+static const struct intel_agp_driver_description {
 	unsigned int chip_id;
-	unsigned int gmch_chip_id;
 	char *name;
 	const struct agp_bridge_driver *driver;
-	const struct agp_bridge_driver *gmch_driver;
 } intel_agp_chipsets[] = {
-	{ PCI_DEVICE_ID_INTEL_82443LX_0, 0, "440LX", &intel_generic_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82443BX_0, 0, "440BX", &intel_generic_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82443GX_0, 0, "440GX", &intel_generic_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, "i810",
-		NULL, &intel_810_driver },
-	{ PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, "i810",
-		NULL, &intel_810_driver },
-	{ PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, "i810",
-		NULL, &intel_810_driver },
-	{ PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, "i815",
-		&intel_815_driver, &intel_810_driver },
-	{ PCI_DEVICE_ID_INTEL_82820_HB, 0, "i820", &intel_820_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, "i820", &intel_820_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
-		&intel_830mp_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82840_HB, 0, "i840", &intel_840_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82845_HB, 0, "845G", &intel_845_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
-		&intel_845_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82850_HB, 0, "i850", &intel_850_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, "854",
-		&intel_845_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82855PM_HB, 0, "855PM", &intel_845_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
-		&intel_845_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82860_HB, 0, "i860", &intel_860_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, "865",
-		&intel_845_driver, &intel_830_driver },
-	{ PCI_DEVICE_ID_INTEL_82875_HB, 0, "i875", &intel_845_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
-		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
-		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_7505_0, 0, "E7505", &intel_7505_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_7205_0, 0, "E7205", &intel_7505_driver, NULL },
-	{ PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, "G33",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
-		NULL, &intel_g33_driver },
-	{ PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG,
-	    "GM45", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG,
-	    "Eaglelake", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG,
-	    "Q45/Q43", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG,
-	    "G45/G43", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG,
-	    "B43", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_B43_1_HB, PCI_DEVICE_ID_INTEL_B43_1_IG,
-	    "B43", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG,
-	    "G41", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
-	    "HD Graphics", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-	    "HD Graphics", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-	    "HD Graphics", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
-	    "HD Graphics", NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
-	    "Sandybridge", NULL, &intel_gen6_driver },
-	{ 0, 0, NULL, NULL, NULL }
+	{ PCI_DEVICE_ID_INTEL_82443LX_0, "440LX", &intel_generic_driver },
+	{ PCI_DEVICE_ID_INTEL_82443BX_0, "440BX", &intel_generic_driver },
+	{ PCI_DEVICE_ID_INTEL_82443GX_0, "440GX", &intel_generic_driver },
+	{ PCI_DEVICE_ID_INTEL_82815_MC, "i815", &intel_815_driver },
+	{ PCI_DEVICE_ID_INTEL_82820_HB, "i820", &intel_820_driver },
+	{ PCI_DEVICE_ID_INTEL_82820_UP_HB, "i820", &intel_820_driver },
+	{ PCI_DEVICE_ID_INTEL_82830_HB, "830M", &intel_830mp_driver },
+	{ PCI_DEVICE_ID_INTEL_82840_HB, "i840", &intel_840_driver },
+	{ PCI_DEVICE_ID_INTEL_82845_HB, "845G", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82845G_HB, "830M", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82850_HB, "i850", &intel_850_driver },
+	{ PCI_DEVICE_ID_INTEL_82854_HB, "854", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82855PM_HB, "855PM", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82855GM_HB, "855GM", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82860_HB, "i860", &intel_860_driver },
+	{ PCI_DEVICE_ID_INTEL_82865_HB, "865", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_82875_HB, "i875", &intel_845_driver },
+	{ PCI_DEVICE_ID_INTEL_7505_0, "E7505", &intel_7505_driver },
+	{ PCI_DEVICE_ID_INTEL_7205_0, "E7205", &intel_7505_driver },
+	{ 0, NULL, NULL }
 };
 
-static int __devinit intel_gmch_probe(struct pci_dev *pdev,
-				      struct agp_bridge_data *bridge)
-{
-	int i, mask;
-
-	bridge->driver = NULL;
-
-	for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
-		if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
-			find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
-			bridge->driver =
-				intel_agp_chipsets[i].gmch_driver;
-			break;
-		}
-	}
-
-	if (!bridge->driver)
-		return 0;
-
-	bridge->dev_private_data = &intel_private;
-	bridge->dev = pdev;
-
-	dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
-
-	if (bridge->driver->mask_memory == intel_gen6_mask_memory)
-		mask = 40;
-	else if (bridge->driver->mask_memory == intel_i965_mask_memory)
-		mask = 36;
-	else
-		mask = 32;
-
-	if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
-		dev_err(&intel_private.pcidev->dev,
-			"set gfx device dma mask %d-bit failed!\n", mask);
-	else
-		pci_set_consistent_dma_mask(intel_private.pcidev,
-					    DMA_BIT_MASK(mask));
-
-	return 1;
-}
-
 static int __devinit agp_intel_probe(struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
 {
@@ -905,7 +760,7 @@
 		}
 	}
 
-	if (intel_agp_chipsets[i].name == NULL) {
+	if (!bridge->driver) {
 		if (cap_ptr)
 			dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n",
 				 pdev->vendor, pdev->device);
@@ -913,14 +768,6 @@
 		return -ENODEV;
 	}
 
-	if (!bridge->driver) {
-		if (cap_ptr)
-			dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n",
-			    	 intel_agp_chipsets[i].gmch_chip_id);
-		agp_put_bridge(bridge);
-		return -ENODEV;
-	}
-
 	bridge->dev = pdev;
 	bridge->dev_private_data = NULL;
 
@@ -972,8 +819,7 @@
 
 	agp_remove_bridge(bridge);
 
-	if (intel_private.pcidev)
-		pci_dev_put(intel_private.pcidev);
+	intel_gmch_remove(pdev);
 
 	agp_put_bridge(bridge);
 }
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index d09b1ab..90539df 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -215,44 +215,7 @@
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB		0x0108  /* Server */
 #define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG		0x010A
 
-/* cover 915 and 945 variants */
-#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
-
-#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
-		 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
-
-#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
-
-#define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB)
-
-#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \
-		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \
-		IS_SNB)
-
+int intel_gmch_probe(struct pci_dev *pdev,
+			       struct agp_bridge_data *bridge);
+void intel_gmch_remove(struct pci_dev *pdev);
 #endif
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 75e0a34..0c8ff6d 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -15,6 +15,18 @@
  * /fairy-tale-mode off
  */
 
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/agp_backend.h>
+#include <asm/smp.h>
+#include "agp.h"
+#include "intel-agp.h"
+#include <linux/intel-gtt.h>
+#include <drm/intel-gtt.h>
+
 /*
  * If we have Intel graphics, we're not going to have anything other than
  * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
@@ -23,11 +35,12 @@
  */
 #ifdef CONFIG_DMAR
 #define USE_PCI_DMA_API 1
+#else
+#define USE_PCI_DMA_API 0
 #endif
 
 /* Max amount of stolen space, anything above will be returned to Linux */
 int intel_max_stolen = 32 * 1024 * 1024;
-EXPORT_SYMBOL(intel_max_stolen);
 
 static const struct aper_size_info_fixed intel_i810_sizes[] =
 {
@@ -55,32 +68,36 @@
 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC        3
 #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT   4
 
-static struct gatt_mask intel_gen6_masks[] =
-{
-	{.mask = I810_PTE_VALID | GEN6_PTE_UNCACHED,
-	 .type = INTEL_AGP_UNCACHED_MEMORY },
-	{.mask = I810_PTE_VALID | GEN6_PTE_LLC,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC },
-	{.mask = I810_PTE_VALID | GEN6_PTE_LLC | GEN6_PTE_GFDT,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_GFDT },
-	{.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC },
-	{.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC | GEN6_PTE_GFDT,
-         .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT },
+struct intel_gtt_driver {
+	unsigned int gen : 8;
+	unsigned int is_g33 : 1;
+	unsigned int is_pineview : 1;
+	unsigned int is_ironlake : 1;
+	unsigned int dma_mask_size : 8;
+	/* Chipset specific GTT setup */
+	int (*setup)(void);
+	/* This should undo anything done in ->setup() save the unmapping
+	 * of the mmio register file, that's done in the generic code. */
+	void (*cleanup)(void);
+	void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags);
+	/* Flags is a more or less chipset specific opaque value.
+	 * For chipsets that need to support old ums (non-gem) code, this
+	 * needs to be identical to the various supported agp memory types! */
+	bool (*check_flags)(unsigned int flags);
+	void (*chipset_flush)(void);
 };
 
 static struct _intel_private {
+	struct intel_gtt base;
+	const struct intel_gtt_driver *driver;
 	struct pci_dev *pcidev;	/* device one */
+	struct pci_dev *bridge_dev;
 	u8 __iomem *registers;
+	phys_addr_t gtt_bus_addr;
+	phys_addr_t gma_bus_addr;
+	phys_addr_t pte_bus_addr;
 	u32 __iomem *gtt;		/* I915G */
 	int num_dcache_entries;
-	/* gtt_entries is the number of gtt entries that are already mapped
-	 * to stolen memory.  Stolen memory is larger than the memory mapped
-	 * through gtt_entries, as it includes some reserved space for the BIOS
-	 * popup and for the GTT.
-	 */
-	int gtt_entries;			/* i830+ */
-	int gtt_total_size;
 	union {
 		void __iomem *i9xx_flush_page;
 		void *i8xx_flush_page;
@@ -88,23 +105,14 @@
 	struct page *i8xx_page;
 	struct resource ifp_resource;
 	int resource_valid;
+	struct page *scratch_page;
+	dma_addr_t scratch_page_dma;
 } intel_private;
 
-#ifdef USE_PCI_DMA_API
-static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
-{
-	*ret = pci_map_page(intel_private.pcidev, page, 0,
-			    PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-	if (pci_dma_mapping_error(intel_private.pcidev, *ret))
-		return -EINVAL;
-	return 0;
-}
-
-static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
-{
-	pci_unmap_page(intel_private.pcidev, dma,
-		       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-}
+#define INTEL_GTT_GEN	intel_private.driver->gen
+#define IS_G33		intel_private.driver->is_g33
+#define IS_PINEVIEW	intel_private.driver->is_pineview
+#define IS_IRONLAKE	intel_private.driver->is_ironlake
 
 static void intel_agp_free_sglist(struct agp_memory *mem)
 {
@@ -125,6 +133,9 @@
 	struct scatterlist *sg;
 	int i;
 
+	if (mem->sg_list)
+		return 0; /* already mapped (for e.g. resume */
+
 	DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
 
 	if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
@@ -156,70 +167,17 @@
 	intel_agp_free_sglist(mem);
 }
 
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-					off_t pg_start, int mask_type)
-{
-	struct scatterlist *sg;
-	int i, j;
-
-	j = pg_start;
-
-	WARN_ON(!mem->num_sg);
-
-	if (mem->num_sg == mem->page_count) {
-		for_each_sg(mem->sg_list, sg, mem->page_count, i) {
-			writel(agp_bridge->driver->mask_memory(agp_bridge,
-					sg_dma_address(sg), mask_type),
-					intel_private.gtt+j);
-			j++;
-		}
-	} else {
-		/* sg may merge pages, but we have to separate
-		 * per-page addr for GTT */
-		unsigned int len, m;
-
-		for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
-			len = sg_dma_len(sg) / PAGE_SIZE;
-			for (m = 0; m < len; m++) {
-				writel(agp_bridge->driver->mask_memory(agp_bridge,
-								       sg_dma_address(sg) + m * PAGE_SIZE,
-								       mask_type),
-				       intel_private.gtt+j);
-				j++;
-			}
-		}
-	}
-	readl(intel_private.gtt+j-1);
-}
-
-#else
-
-static void intel_agp_insert_sg_entries(struct agp_memory *mem,
-					off_t pg_start, int mask_type)
-{
-	int i, j;
-
-	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(agp_bridge,
-				page_to_phys(mem->pages[i]), mask_type),
-		       intel_private.gtt+j);
-	}
-
-	readl(intel_private.gtt+j-1);
-}
-
-#endif
-
 static int intel_i810_fetch_size(void)
 {
 	u32 smram_miscc;
 	struct aper_size_info_fixed *values;
 
-	pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
+	pci_read_config_dword(intel_private.bridge_dev,
+			      I810_SMRAM_MISCC, &smram_miscc);
 	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
 
 	if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
-		dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
+		dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n");
 		return 0;
 	}
 	if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
@@ -284,7 +242,7 @@
 	iounmap(intel_private.registers);
 }
 
-static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
 {
 	return;
 }
@@ -319,34 +277,6 @@
 	atomic_dec(&agp_bridge->current_memory_agp);
 }
 
-static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
-					int type)
-{
-	if (type < AGP_USER_TYPES)
-		return type;
-	else if (type == AGP_USER_CACHED_MEMORY)
-		return INTEL_AGP_CACHED_MEMORY;
-	else
-		return 0;
-}
-
-static int intel_gen6_type_to_mask_type(struct agp_bridge_data *bridge,
-					int type)
-{
-	unsigned int type_mask = type & ~AGP_USER_CACHED_MEMORY_GFDT;
-	unsigned int gfdt = type & AGP_USER_CACHED_MEMORY_GFDT;
-
-	if (type_mask == AGP_USER_UNCACHED_MEMORY)
-		return INTEL_AGP_UNCACHED_MEMORY;
-	else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC)
-		return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT :
-			      INTEL_AGP_CACHED_MEMORY_LLC_MLC;
-	else /* set 'normal'/'cached' to LLC by default */
-		return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_GFDT :
-			      INTEL_AGP_CACHED_MEMORY_LLC;
-}
-
-
 static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
 				int type)
 {
@@ -514,8 +444,33 @@
 	return addr | bridge->driver->masks[type].mask;
 }
 
-static struct aper_size_info_fixed intel_i830_sizes[] =
+static int intel_gtt_setup_scratch_page(void)
 {
+	struct page *page;
+	dma_addr_t dma_addr;
+
+	page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+	if (page == NULL)
+		return -ENOMEM;
+	get_page(page);
+	set_pages_uc(page, 1);
+
+	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+		dma_addr = pci_map_page(intel_private.pcidev, page, 0,
+				    PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+		if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
+			return -EINVAL;
+
+		intel_private.scratch_page_dma = dma_addr;
+	} else
+		intel_private.scratch_page_dma = page_to_phys(page);
+
+	intel_private.scratch_page = page;
+
+	return 0;
+}
+
+static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = {
 	{128, 32768, 5},
 	/* The 64M mode still requires a 128k gatt */
 	{64, 16384, 5},
@@ -523,102 +478,49 @@
 	{512, 131072, 7},
 };
 
-static void intel_i830_init_gtt_entries(void)
+static unsigned int intel_gtt_stolen_entries(void)
 {
 	u16 gmch_ctrl;
-	int gtt_entries = 0;
 	u8 rdct;
 	int local = 0;
 	static const int ddt[4] = { 0, 16, 32, 64 };
-	int size; /* reserved space (in kb) at the top of stolen memory */
+	unsigned int overhead_entries, stolen_entries;
+	unsigned int stolen_size = 0;
 
-	pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+	pci_read_config_word(intel_private.bridge_dev,
+			     I830_GMCH_CTRL, &gmch_ctrl);
 
-	if (IS_I965) {
-		u32 pgetbl_ctl;
-		pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+	if (INTEL_GTT_GEN > 4 || IS_PINEVIEW)
+		overhead_entries = 0;
+	else
+		overhead_entries = intel_private.base.gtt_mappable_entries
+			/ 1024;
 
-		/* The 965 has a field telling us the size of the GTT,
-		 * which may be larger than what is necessary to map the
-		 * aperture.
-		 */
-		switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
-		case I965_PGETBL_SIZE_128KB:
-			size = 128;
-			break;
-		case I965_PGETBL_SIZE_256KB:
-			size = 256;
-			break;
-		case I965_PGETBL_SIZE_512KB:
-			size = 512;
-			break;
-		case I965_PGETBL_SIZE_1MB:
-			size = 1024;
-			break;
-		case I965_PGETBL_SIZE_2MB:
-			size = 2048;
-			break;
-		case I965_PGETBL_SIZE_1_5MB:
-			size = 1024 + 512;
-			break;
-		default:
-			dev_info(&intel_private.pcidev->dev,
-				 "unknown page table size, assuming 512KB\n");
-			size = 512;
-		}
-		size += 4; /* add in BIOS popup space */
-	} else if (IS_G33 && !IS_PINEVIEW) {
-	/* G33's GTT size defined in gmch_ctrl */
-		switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
-		case G33_PGETBL_SIZE_1M:
-			size = 1024;
-			break;
-		case G33_PGETBL_SIZE_2M:
-			size = 2048;
-			break;
-		default:
-			dev_info(&agp_bridge->dev->dev,
-				 "unknown page table size 0x%x, assuming 512KB\n",
-				(gmch_ctrl & G33_PGETBL_SIZE_MASK));
-			size = 512;
-		}
-		size += 4;
-	} else if (IS_G4X || IS_PINEVIEW) {
-		/* On 4 series hardware, GTT stolen is separate from graphics
-		 * stolen, ignore it in stolen gtt entries counting.  However,
-		 * 4KB of the stolen memory doesn't get mapped to the GTT.
-		 */
-		size = 4;
-	} else {
-		/* On previous hardware, the GTT size was just what was
-		 * required to map the aperture.
-		 */
-		size = agp_bridge->driver->fetch_size() + 4;
-	}
+	overhead_entries += 1; /* BIOS popup */
 
-	if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
-	    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+	if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+	    intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
 		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
 		case I830_GMCH_GMS_STOLEN_512:
-			gtt_entries = KB(512) - KB(size);
+			stolen_size = KB(512);
 			break;
 		case I830_GMCH_GMS_STOLEN_1024:
-			gtt_entries = MB(1) - KB(size);
+			stolen_size = MB(1);
 			break;
 		case I830_GMCH_GMS_STOLEN_8192:
-			gtt_entries = MB(8) - KB(size);
+			stolen_size = MB(8);
 			break;
 		case I830_GMCH_GMS_LOCAL:
 			rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
-			gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+			stolen_size = (I830_RDRAM_ND(rdct) + 1) *
 					MB(ddt[I830_RDRAM_DDT(rdct)]);
 			local = 1;
 			break;
 		default:
-			gtt_entries = 0;
+			stolen_size = 0;
 			break;
 		}
-	} else if (IS_SNB) {
+	} else if (INTEL_GTT_GEN == 6) {
 		/*
 		 * SandyBridge has new memory control reg at 0x50.w
 		 */
@@ -626,149 +528,292 @@
 		pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
 		switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
 		case SNB_GMCH_GMS_STOLEN_32M:
-			gtt_entries = MB(32) - KB(size);
+			stolen_size = MB(32);
 			break;
 		case SNB_GMCH_GMS_STOLEN_64M:
-			gtt_entries = MB(64) - KB(size);
+			stolen_size = MB(64);
 			break;
 		case SNB_GMCH_GMS_STOLEN_96M:
-			gtt_entries = MB(96) - KB(size);
+			stolen_size = MB(96);
 			break;
 		case SNB_GMCH_GMS_STOLEN_128M:
-			gtt_entries = MB(128) - KB(size);
+			stolen_size = MB(128);
 			break;
 		case SNB_GMCH_GMS_STOLEN_160M:
-			gtt_entries = MB(160) - KB(size);
+			stolen_size = MB(160);
 			break;
 		case SNB_GMCH_GMS_STOLEN_192M:
-			gtt_entries = MB(192) - KB(size);
+			stolen_size = MB(192);
 			break;
 		case SNB_GMCH_GMS_STOLEN_224M:
-			gtt_entries = MB(224) - KB(size);
+			stolen_size = MB(224);
 			break;
 		case SNB_GMCH_GMS_STOLEN_256M:
-			gtt_entries = MB(256) - KB(size);
+			stolen_size = MB(256);
 			break;
 		case SNB_GMCH_GMS_STOLEN_288M:
-			gtt_entries = MB(288) - KB(size);
+			stolen_size = MB(288);
 			break;
 		case SNB_GMCH_GMS_STOLEN_320M:
-			gtt_entries = MB(320) - KB(size);
+			stolen_size = MB(320);
 			break;
 		case SNB_GMCH_GMS_STOLEN_352M:
-			gtt_entries = MB(352) - KB(size);
+			stolen_size = MB(352);
 			break;
 		case SNB_GMCH_GMS_STOLEN_384M:
-			gtt_entries = MB(384) - KB(size);
+			stolen_size = MB(384);
 			break;
 		case SNB_GMCH_GMS_STOLEN_416M:
-			gtt_entries = MB(416) - KB(size);
+			stolen_size = MB(416);
 			break;
 		case SNB_GMCH_GMS_STOLEN_448M:
-			gtt_entries = MB(448) - KB(size);
+			stolen_size = MB(448);
 			break;
 		case SNB_GMCH_GMS_STOLEN_480M:
-			gtt_entries = MB(480) - KB(size);
+			stolen_size = MB(480);
 			break;
 		case SNB_GMCH_GMS_STOLEN_512M:
-			gtt_entries = MB(512) - KB(size);
+			stolen_size = MB(512);
 			break;
 		}
 	} else {
 		switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
 		case I855_GMCH_GMS_STOLEN_1M:
-			gtt_entries = MB(1) - KB(size);
+			stolen_size = MB(1);
 			break;
 		case I855_GMCH_GMS_STOLEN_4M:
-			gtt_entries = MB(4) - KB(size);
+			stolen_size = MB(4);
 			break;
 		case I855_GMCH_GMS_STOLEN_8M:
-			gtt_entries = MB(8) - KB(size);
+			stolen_size = MB(8);
 			break;
 		case I855_GMCH_GMS_STOLEN_16M:
-			gtt_entries = MB(16) - KB(size);
+			stolen_size = MB(16);
 			break;
 		case I855_GMCH_GMS_STOLEN_32M:
-			gtt_entries = MB(32) - KB(size);
+			stolen_size = MB(32);
 			break;
 		case I915_GMCH_GMS_STOLEN_48M:
-			/* Check it's really I915G */
-			if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-				gtt_entries = MB(48) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(48);
 			break;
 		case I915_GMCH_GMS_STOLEN_64M:
-			/* Check it's really I915G */
-			if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
-				gtt_entries = MB(64) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(64);
 			break;
 		case G33_GMCH_GMS_STOLEN_128M:
-			if (IS_G33 || IS_I965 || IS_G4X)
-				gtt_entries = MB(128) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(128);
 			break;
 		case G33_GMCH_GMS_STOLEN_256M:
-			if (IS_G33 || IS_I965 || IS_G4X)
-				gtt_entries = MB(256) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(256);
 			break;
 		case INTEL_GMCH_GMS_STOLEN_96M:
-			if (IS_I965 || IS_G4X)
-				gtt_entries = MB(96) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(96);
 			break;
 		case INTEL_GMCH_GMS_STOLEN_160M:
-			if (IS_I965 || IS_G4X)
-				gtt_entries = MB(160) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(160);
 			break;
 		case INTEL_GMCH_GMS_STOLEN_224M:
-			if (IS_I965 || IS_G4X)
-				gtt_entries = MB(224) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(224);
 			break;
 		case INTEL_GMCH_GMS_STOLEN_352M:
-			if (IS_I965 || IS_G4X)
-				gtt_entries = MB(352) - KB(size);
-			else
-				gtt_entries = 0;
+			stolen_size = MB(352);
 			break;
 		default:
-			gtt_entries = 0;
+			stolen_size = 0;
 			break;
 		}
 	}
-	if (!local && gtt_entries > intel_max_stolen) {
-		dev_info(&agp_bridge->dev->dev,
+
+	if (!local && stolen_size > intel_max_stolen) {
+		dev_info(&intel_private.bridge_dev->dev,
 			 "detected %dK stolen memory, trimming to %dK\n",
-			 gtt_entries / KB(1), intel_max_stolen / KB(1));
-		gtt_entries = intel_max_stolen / KB(4);
-	} else if (gtt_entries > 0) {
-		dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
-		       gtt_entries / KB(1), local ? "local" : "stolen");
-		gtt_entries /= KB(4);
+			 stolen_size / KB(1), intel_max_stolen / KB(1));
+		stolen_size = intel_max_stolen;
+	} else if (stolen_size > 0) {
+		dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n",
+		       stolen_size / KB(1), local ? "local" : "stolen");
 	} else {
-		dev_info(&agp_bridge->dev->dev,
+		dev_info(&intel_private.bridge_dev->dev,
 		       "no pre-allocated video memory detected\n");
-		gtt_entries = 0;
+		stolen_size = 0;
 	}
 
-	intel_private.gtt_entries = gtt_entries;
+	stolen_entries = stolen_size/KB(4) - overhead_entries;
+
+	return stolen_entries;
 }
 
-static void intel_i830_fini_flush(void)
+static unsigned int intel_gtt_total_entries(void)
+{
+	int size;
+
+	if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) {
+		u32 pgetbl_ctl;
+		pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
+
+		switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
+		case I965_PGETBL_SIZE_128KB:
+			size = KB(128);
+			break;
+		case I965_PGETBL_SIZE_256KB:
+			size = KB(256);
+			break;
+		case I965_PGETBL_SIZE_512KB:
+			size = KB(512);
+			break;
+		case I965_PGETBL_SIZE_1MB:
+			size = KB(1024);
+			break;
+		case I965_PGETBL_SIZE_2MB:
+			size = KB(2048);
+			break;
+		case I965_PGETBL_SIZE_1_5MB:
+			size = KB(1024 + 512);
+			break;
+		default:
+			dev_info(&intel_private.pcidev->dev,
+				 "unknown page table size, assuming 512KB\n");
+			size = KB(512);
+		}
+
+		return size/4;
+	} else if (INTEL_GTT_GEN == 6) {
+		u16 snb_gmch_ctl;
+
+		pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
+		switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
+		default:
+		case SNB_GTT_SIZE_0M:
+			printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
+			size = MB(0);
+			break;
+		case SNB_GTT_SIZE_1M:
+			size = MB(1);
+			break;
+		case SNB_GTT_SIZE_2M:
+			size = MB(2);
+			break;
+		}
+		return size/4;
+	} else {
+		/* On previous hardware, the GTT size was just what was
+		 * required to map the aperture.
+		 */
+		return intel_private.base.gtt_mappable_entries;
+	}
+}
+
+static unsigned int intel_gtt_mappable_entries(void)
+{
+	unsigned int aperture_size;
+
+	if (INTEL_GTT_GEN == 2) {
+		u16 gmch_ctrl;
+
+		pci_read_config_word(intel_private.bridge_dev,
+				     I830_GMCH_CTRL, &gmch_ctrl);
+
+		if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M)
+			aperture_size = MB(64);
+		else
+			aperture_size = MB(128);
+	} else {
+		/* 9xx supports large sizes, just look at the length */
+		aperture_size = pci_resource_len(intel_private.pcidev, 2);
+	}
+
+	return aperture_size >> PAGE_SHIFT;
+}
+
+static void intel_gtt_teardown_scratch_page(void)
+{
+	set_pages_wb(intel_private.scratch_page, 1);
+	pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
+		       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+	put_page(intel_private.scratch_page);
+	__free_page(intel_private.scratch_page);
+}
+
+static void intel_gtt_cleanup(void)
+{
+	intel_private.driver->cleanup();
+
+	iounmap(intel_private.gtt);
+	iounmap(intel_private.registers);
+	
+	intel_gtt_teardown_scratch_page();
+}
+
+static int intel_gtt_init(void)
+{
+	u32 gtt_map_size;
+	int ret;
+
+	ret = intel_private.driver->setup();
+	if (ret != 0)
+		return ret;
+
+	intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
+	intel_private.base.gtt_total_entries = intel_gtt_total_entries();
+
+	dev_info(&intel_private.bridge_dev->dev,
+			"detected gtt size: %dK total, %dK mappable\n",
+			intel_private.base.gtt_total_entries * 4,
+			intel_private.base.gtt_mappable_entries * 4);
+
+	gtt_map_size = intel_private.base.gtt_total_entries * 4;
+
+	intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
+				    gtt_map_size);
+	if (!intel_private.gtt) {
+		intel_private.driver->cleanup();
+		iounmap(intel_private.registers);
+		return -ENOMEM;
+	}
+
+	global_cache_flush();   /* FIXME: ? */
+
+	/* we have to call this as early as possible after the MMIO base address is known */
+	intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries();
+	if (intel_private.base.gtt_stolen_entries == 0) {
+		intel_private.driver->cleanup();
+		iounmap(intel_private.registers);
+		iounmap(intel_private.gtt);
+		return -ENOMEM;
+	}
+
+	ret = intel_gtt_setup_scratch_page();
+	if (ret != 0) {
+		intel_gtt_cleanup();
+		return ret;
+	}
+
+	return 0;
+}
+
+static int intel_fake_agp_fetch_size(void)
+{
+	int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
+	unsigned int aper_size;
+	int i;
+
+	aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT)
+		    / MB(1);
+
+	for (i = 0; i < num_sizes; i++) {
+		if (aper_size == intel_fake_agp_sizes[i].size) {
+			agp_bridge->current_size =
+				(void *) (intel_fake_agp_sizes + i);
+			return aper_size;
+		}
+	}
+
+	return 0;
+}
+
+static void i830_cleanup(void)
 {
 	kunmap(intel_private.i8xx_page);
 	intel_private.i8xx_flush_page = NULL;
-	unmap_page_from_agp(intel_private.i8xx_page);
 
 	__free_page(intel_private.i8xx_page);
 	intel_private.i8xx_page = NULL;
@@ -780,13 +825,13 @@
 	if (intel_private.i8xx_page)
 		return;
 
-	intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
+	intel_private.i8xx_page = alloc_page(GFP_KERNEL);
 	if (!intel_private.i8xx_page)
 		return;
 
 	intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
 	if (!intel_private.i8xx_flush_page)
-		intel_i830_fini_flush();
+		i830_cleanup();
 }
 
 /* The chipset_flush interface needs to get data that has already been
@@ -799,7 +844,7 @@
  * that buffer out, we just fill 1KB and clflush it out, on the assumption
  * that it'll push whatever was in there out.  It appears to work.
  */
-static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
+static void i830_chipset_flush(void)
 {
 	unsigned int *pg = intel_private.i8xx_flush_page;
 
@@ -811,169 +856,184 @@
 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
 }
 
-/* The intel i830 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
+static void i830_write_entry(dma_addr_t addr, unsigned int entry,
+			     unsigned int flags)
 {
-	int page_order;
-	struct aper_size_info_fixed *size;
-	int num_entries;
-	u32 temp;
+	u32 pte_flags = I810_PTE_VALID;
+	
+	switch (flags) {
+	case AGP_DCACHE_MEMORY:
+		pte_flags |= I810_PTE_LOCAL;
+		break;
+	case AGP_USER_CACHED_MEMORY:
+		pte_flags |= I830_PTE_SYSTEM_CACHED;
+		break;
+	}
 
-	size = agp_bridge->current_size;
-	page_order = size->page_order;
-	num_entries = size->num_entries;
-	agp_bridge->gatt_table_real = NULL;
+	writel(addr | pte_flags, intel_private.gtt + entry);
+}
 
-	pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
-	temp &= 0xfff80000;
+static void intel_enable_gtt(void)
+{
+	u32 gma_addr;
+	u16 gmch_ctrl;
 
-	intel_private.registers = ioremap(temp, 128 * 4096);
+	if (INTEL_GTT_GEN == 2)
+		pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
+				      &gma_addr);
+	else
+		pci_read_config_dword(intel_private.pcidev, I915_GMADDR,
+				      &gma_addr);
+
+	intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
+
+	pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl);
+	gmch_ctrl |= I830_GMCH_ENABLED;
+	pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl);
+
+	writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED,
+	       intel_private.registers+I810_PGETBL_CTL);
+	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
+}
+
+static int i830_setup(void)
+{
+	u32 reg_addr;
+
+	pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
+	reg_addr &= 0xfff80000;
+
+	intel_private.registers = ioremap(reg_addr, KB(64));
 	if (!intel_private.registers)
 		return -ENOMEM;
 
-	temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-	global_cache_flush();	/* FIXME: ?? */
+	intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
+	intel_private.pte_bus_addr =
+		readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
-	/* we have to call this as early as possible after the MMIO base address is known */
-	intel_i830_init_gtt_entries();
-	if (intel_private.gtt_entries == 0) {
-		iounmap(intel_private.registers);
-		return -ENOMEM;
-	}
+	intel_i830_setup_flush();
 
+	return 0;
+}
+
+static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)
+{
+	agp_bridge->gatt_table_real = NULL;
 	agp_bridge->gatt_table = NULL;
-
-	agp_bridge->gatt_bus_addr = temp;
+	agp_bridge->gatt_bus_addr = 0;
 
 	return 0;
 }
 
-/* Return the gatt table to a sane state. Use the top of stolen
- * memory for the GTT.
- */
-static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
+static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
 {
 	return 0;
 }
 
-static int intel_i830_fetch_size(void)
+static int intel_fake_agp_configure(void)
 {
-	u16 gmch_ctrl;
-	struct aper_size_info_fixed *values;
-
-	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
-
-	if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
-	    agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
-		/* 855GM/852GM/865G has 128MB aperture size */
-		agp_bridge->current_size = (void *) values;
-		agp_bridge->aperture_size_idx = 0;
-		return values[0].size;
-	}
-
-	pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-
-	if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
-		agp_bridge->current_size = (void *) values;
-		agp_bridge->aperture_size_idx = 0;
-		return values[0].size;
-	} else {
-		agp_bridge->current_size = (void *) (values + 1);
-		agp_bridge->aperture_size_idx = 1;
-		return values[1].size;
-	}
-
-	return 0;
-}
-
-static int intel_i830_configure(void)
-{
-	struct aper_size_info_fixed *current_size;
-	u32 temp;
-	u16 gmch_ctrl;
 	int i;
 
-	current_size = A_SIZE_FIX(agp_bridge->current_size);
+	intel_enable_gtt();
 
-	pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
-	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+	agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
 
-	pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-	gmch_ctrl |= I830_GMCH_ENABLED;
-	pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
-	writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
-
-	if (agp_bridge->driver->needs_scratch_page) {
-		for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
-			writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
-		}
-		readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));	/* PCI Posting. */
+	for (i = intel_private.base.gtt_stolen_entries;
+			i < intel_private.base.gtt_total_entries; i++) {
+		intel_private.driver->write_entry(intel_private.scratch_page_dma,
+						  i, 0);
 	}
+	readl(intel_private.gtt+i-1);	/* PCI Posting. */
 
 	global_cache_flush();
 
-	intel_i830_setup_flush();
 	return 0;
 }
 
-static void intel_i830_cleanup(void)
+static bool i830_check_flags(unsigned int flags)
 {
-	iounmap(intel_private.registers);
+	switch (flags) {
+	case 0:
+	case AGP_PHYS_MEMORY:
+	case AGP_USER_CACHED_MEMORY:
+	case AGP_USER_MEMORY:
+		return true;
+	}
+
+	return false;
 }
 
-static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
-				     int type)
+static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
+					unsigned int sg_len,
+					unsigned int pg_start,
+					unsigned int flags)
 {
-	int i, j, num_entries;
-	void *temp;
+	struct scatterlist *sg;
+	unsigned int len, m;
+	int i, j;
+
+	j = pg_start;
+
+	/* sg may merge pages, but we have to separate
+	 * per-page addr for GTT */
+	for_each_sg(sg_list, sg, sg_len, i) {
+		len = sg_dma_len(sg) >> PAGE_SHIFT;
+		for (m = 0; m < len; m++) {
+			dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+			intel_private.driver->write_entry(addr,
+							  j, flags);
+			j++;
+		}
+	}
+	readl(intel_private.gtt+j-1);
+}
+
+static int intel_fake_agp_insert_entries(struct agp_memory *mem,
+					 off_t pg_start, int type)
+{
+	int i, j;
 	int ret = -EINVAL;
-	int mask_type;
 
 	if (mem->page_count == 0)
 		goto out;
 
-	temp = agp_bridge->current_size;
-	num_entries = A_SIZE_FIX(temp)->num_entries;
-
-	if (pg_start < intel_private.gtt_entries) {
+	if (pg_start < intel_private.base.gtt_stolen_entries) {
 		dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-			   "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-			   pg_start, intel_private.gtt_entries);
+			   "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n",
+			   pg_start, intel_private.base.gtt_stolen_entries);
 
 		dev_info(&intel_private.pcidev->dev,
 			 "trying to insert into local/stolen memory\n");
 		goto out_err;
 	}
 
-	if ((pg_start + mem->page_count) > num_entries)
+	if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries)
 		goto out_err;
 
-	/* The i830 can't check the GTT for entries since its read only,
-	 * depend on the caller to make the correct offset decisions.
-	 */
-
 	if (type != mem->type)
 		goto out_err;
 
-	mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-	if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-	    mask_type != INTEL_AGP_CACHED_MEMORY)
+	if (!intel_private.driver->check_flags(type))
 		goto out_err;
 
 	if (!mem->is_flushed)
 		global_cache_flush();
 
-	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		writel(agp_bridge->driver->mask_memory(agp_bridge,
-				page_to_phys(mem->pages[i]), mask_type),
-		       intel_private.registers+I810_PTE_BASE+(j*4));
+	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
+		ret = intel_agp_map_memory(mem);
+		if (ret != 0)
+			return ret;
+
+		intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg,
+					    pg_start, type);
+	} else {
+		for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+			dma_addr_t addr = page_to_phys(mem->pages[i]);
+			intel_private.driver->write_entry(addr,
+							  j, type);
+		}
+		readl(intel_private.gtt+j-1);
 	}
-	readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
 
 out:
 	ret = 0;
@@ -982,29 +1042,39 @@
 	return ret;
 }
 
-static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
-				     int type)
+static int intel_fake_agp_remove_entries(struct agp_memory *mem,
+					 off_t pg_start, int type)
 {
 	int i;
 
 	if (mem->page_count == 0)
 		return 0;
 
-	if (pg_start < intel_private.gtt_entries) {
+	if (pg_start < intel_private.base.gtt_stolen_entries) {
 		dev_info(&intel_private.pcidev->dev,
 			 "trying to disable local/stolen memory\n");
 		return -EINVAL;
 	}
 
+	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2)
+		intel_agp_unmap_memory(mem);
+
 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
-		writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
+		intel_private.driver->write_entry(intel_private.scratch_page_dma,
+						  i, 0);
 	}
-	readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
+	readl(intel_private.gtt+i-1);
 
 	return 0;
 }
 
-static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
+static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge)
+{
+	intel_private.driver->chipset_flush();
+}
+
+static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
+						       int type)
 {
 	if (type == AGP_PHYS_MEMORY)
 		return alloc_agpphysmem_i8xx(pg_count, type);
@@ -1015,9 +1085,9 @@
 static int intel_alloc_chipset_flush_resource(void)
 {
 	int ret;
-	ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
+	ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
 				     PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
-				     pcibios_align_resource, agp_bridge->dev);
+				     pcibios_align_resource, intel_private.bridge_dev);
 
 	return ret;
 }
@@ -1027,11 +1097,11 @@
 	int ret;
 	u32 temp;
 
-	pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
+	pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp);
 	if (!(temp & 0x1)) {
 		intel_alloc_chipset_flush_resource();
 		intel_private.resource_valid = 1;
-		pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+		pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
 	} else {
 		temp &= ~1;
 
@@ -1050,17 +1120,17 @@
 	u32 temp_hi, temp_lo;
 	int ret;
 
-	pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
-	pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
+	pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi);
+	pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo);
 
 	if (!(temp_lo & 0x1)) {
 
 		intel_alloc_chipset_flush_resource();
 
 		intel_private.resource_valid = 1;
-		pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
+		pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4,
 			upper_32_bits(intel_private.ifp_resource.start));
-		pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
+		pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
 	} else {
 		u64 l64;
 
@@ -1083,7 +1153,7 @@
 	if (intel_private.ifp_resource.start)
 		return;
 
-	if (IS_SNB)
+	if (INTEL_GTT_GEN == 6)
 		return;
 
 	/* setup a resource for this object */
@@ -1091,7 +1161,7 @@
 	intel_private.ifp_resource.flags = IORESOURCE_MEM;
 
 	/* Setup chipset flush for 915 */
-	if (IS_I965 || IS_G33 || IS_G4X) {
+	if (IS_G33 || INTEL_GTT_GEN >= 4) {
 		intel_i965_g33_setup_chipset_flush();
 	} else {
 		intel_i915_setup_chipset_flush();
@@ -1104,41 +1174,7 @@
 			"can't ioremap flush page - no chipset flushing\n");
 }
 
-static int intel_i9xx_configure(void)
-{
-	struct aper_size_info_fixed *current_size;
-	u32 temp;
-	u16 gmch_ctrl;
-	int i;
-
-	current_size = A_SIZE_FIX(agp_bridge->current_size);
-
-	pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
-
-	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-
-	pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-	gmch_ctrl |= I830_GMCH_ENABLED;
-	pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
-
-	writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
-	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
-
-	if (agp_bridge->driver->needs_scratch_page) {
-		for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
-			writel(agp_bridge->scratch_page, intel_private.gtt+i);
-		}
-		readl(intel_private.gtt+i-1);	/* PCI Posting. */
-	}
-
-	global_cache_flush();
-
-	intel_i9xx_setup_flush();
-
-	return 0;
-}
-
-static void intel_i915_cleanup(void)
+static void i9xx_cleanup(void)
 {
 	if (intel_private.i9xx_flush_page)
 		iounmap(intel_private.i9xx_flush_page);
@@ -1146,320 +1182,93 @@
 		release_resource(&intel_private.ifp_resource);
 	intel_private.ifp_resource.start = 0;
 	intel_private.resource_valid = 0;
-	iounmap(intel_private.gtt);
-	iounmap(intel_private.registers);
 }
 
-static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
+static void i9xx_chipset_flush(void)
 {
 	if (intel_private.i9xx_flush_page)
 		writel(1, intel_private.i9xx_flush_page);
 }
 
-static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
-				     int type)
-{
-	int num_entries;
-	void *temp;
-	int ret = -EINVAL;
-	int mask_type;
-
-	if (mem->page_count == 0)
-		goto out;
-
-	temp = agp_bridge->current_size;
-	num_entries = A_SIZE_FIX(temp)->num_entries;
-
-	if (pg_start < intel_private.gtt_entries) {
-		dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
-			   "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
-			   pg_start, intel_private.gtt_entries);
-
-		dev_info(&intel_private.pcidev->dev,
-			 "trying to insert into local/stolen memory\n");
-		goto out_err;
-	}
-
-	if ((pg_start + mem->page_count) > num_entries)
-		goto out_err;
-
-	/* The i915 can't check the GTT for entries since it's read only;
-	 * depend on the caller to make the correct offset decisions.
-	 */
-
-	if (type != mem->type)
-		goto out_err;
-
-	mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
-
-	if (!IS_SNB && mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
-	    mask_type != INTEL_AGP_CACHED_MEMORY)
-		goto out_err;
-
-	if (!mem->is_flushed)
-		global_cache_flush();
-
-	intel_agp_insert_sg_entries(mem, pg_start, mask_type);
-
- out:
-	ret = 0;
- out_err:
-	mem->is_flushed = true;
-	return ret;
-}
-
-static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
-				     int type)
-{
-	int i;
-
-	if (mem->page_count == 0)
-		return 0;
-
-	if (pg_start < intel_private.gtt_entries) {
-		dev_info(&intel_private.pcidev->dev,
-			 "trying to disable local/stolen memory\n");
-		return -EINVAL;
-	}
-
-	for (i = pg_start; i < (mem->page_count + pg_start); i++)
-		writel(agp_bridge->scratch_page, intel_private.gtt+i);
-
-	readl(intel_private.gtt+i-1);
-
-	return 0;
-}
-
-/* Return the aperture size by just checking the resource length.  The effect
- * described in the spec of the MSAC registers is just changing of the
- * resource size.
- */
-static int intel_i9xx_fetch_size(void)
-{
-	int num_sizes = ARRAY_SIZE(intel_i830_sizes);
-	int aper_size; /* size in megabytes */
-	int i;
-
-	aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
-
-	for (i = 0; i < num_sizes; i++) {
-		if (aper_size == intel_i830_sizes[i].size) {
-			agp_bridge->current_size = intel_i830_sizes + i;
-			return aper_size;
-		}
-	}
-
-	return 0;
-}
-
-static int intel_i915_get_gtt_size(void)
-{
-	int size;
-
-	if (IS_G33) {
-		u16 gmch_ctrl;
-
-		/* G33's GTT size defined in gmch_ctrl */
-		pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
-		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
-		case I830_GMCH_GMS_STOLEN_512:
-			size = 512;
-			break;
-		case I830_GMCH_GMS_STOLEN_1024:
-			size = 1024;
-			break;
-		case I830_GMCH_GMS_STOLEN_8192:
-			size = 8*1024;
-			break;
-		default:
-			dev_info(&agp_bridge->dev->dev,
-				 "unknown page table size 0x%x, assuming 512KB\n",
-				(gmch_ctrl & I830_GMCH_GMS_MASK));
-			size = 512;
-		}
-	} else {
-		/* On previous hardware, the GTT size was just what was
-		 * required to map the aperture.
-		 */
-		size = agp_bridge->driver->fetch_size();
-	}
-
-	return KB(size);
-}
-
-/* The intel i915 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
-{
-	int page_order;
-	struct aper_size_info_fixed *size;
-	int num_entries;
-	u32 temp, temp2;
-	int gtt_map_size;
-
-	size = agp_bridge->current_size;
-	page_order = size->page_order;
-	num_entries = size->num_entries;
-	agp_bridge->gatt_table_real = NULL;
-
-	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-	pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
-
-	gtt_map_size = intel_i915_get_gtt_size();
-
-	intel_private.gtt = ioremap(temp2, gtt_map_size);
-	if (!intel_private.gtt)
-		return -ENOMEM;
-
-	intel_private.gtt_total_size = gtt_map_size / 4;
-
-	temp &= 0xfff80000;
-
-	intel_private.registers = ioremap(temp, 128 * 4096);
-	if (!intel_private.registers) {
-		iounmap(intel_private.gtt);
-		return -ENOMEM;
-	}
-
-	temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-	global_cache_flush();	/* FIXME: ? */
-
-	/* we have to call this as early as possible after the MMIO base address is known */
-	intel_i830_init_gtt_entries();
-	if (intel_private.gtt_entries == 0) {
-		iounmap(intel_private.gtt);
-		iounmap(intel_private.registers);
-		return -ENOMEM;
-	}
-
-	agp_bridge->gatt_table = NULL;
-
-	agp_bridge->gatt_bus_addr = temp;
-
-	return 0;
-}
-
-/*
- * The i965 supports 36-bit physical addresses, but to keep
- * the format of the GTT the same, the bits that don't fit
- * in a 32-bit word are shifted down to bits 4..7.
- *
- * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
- * is always zero on 32-bit architectures, so no need to make
- * this conditional.
- */
-static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
-					    dma_addr_t addr, int type)
+static void i965_write_entry(dma_addr_t addr, unsigned int entry,
+			     unsigned int flags)
 {
 	/* Shift high bits down */
 	addr |= (addr >> 28) & 0xf0;
-
-	/* Type checking must be done elsewhere */
-	return addr | bridge->driver->masks[type].mask;
+	writel(addr | I810_PTE_VALID, intel_private.gtt + entry);
 }
 
-static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge,
-					    dma_addr_t addr, int type)
+static bool gen6_check_flags(unsigned int flags)
 {
+	return true;
+}
+
+static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
+			     unsigned int flags)
+{
+	unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
+	unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
+	u32 pte_flags;
+
+	if (type_mask == AGP_USER_UNCACHED_MEMORY)
+		pte_flags = GEN6_PTE_UNCACHED;
+	else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
+		pte_flags = GEN6_PTE_LLC;
+		if (gfdt)
+			pte_flags |= GEN6_PTE_GFDT;
+	} else { /* set 'normal'/'cached' to LLC by default */
+		pte_flags = GEN6_PTE_LLC_MLC;
+		if (gfdt)
+			pte_flags |= GEN6_PTE_GFDT;
+	}
+
 	/* gen6 has bit11-4 for physical addr bit39-32 */
 	addr |= (addr >> 28) & 0xff0;
-
-	/* Type checking must be done elsewhere */
-	return addr | bridge->driver->masks[type].mask;
+	writel(addr | pte_flags, intel_private.gtt + entry);
 }
 
-static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
+static void gen6_cleanup(void)
 {
-	u16 snb_gmch_ctl;
+}
 
-	switch (agp_bridge->dev->device) {
-	case PCI_DEVICE_ID_INTEL_GM45_HB:
-	case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
-	case PCI_DEVICE_ID_INTEL_Q45_HB:
-	case PCI_DEVICE_ID_INTEL_G45_HB:
-	case PCI_DEVICE_ID_INTEL_G41_HB:
-	case PCI_DEVICE_ID_INTEL_B43_HB:
-	case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
-	case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
-	case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
-	case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
-		*gtt_offset = *gtt_size = MB(2);
-		break;
-	case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
-	case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
-	case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB:
-		*gtt_offset = MB(2);
+static int i9xx_setup(void)
+{
+	u32 reg_addr;
 
-		pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
-		switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
+	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr);
+
+	reg_addr &= 0xfff80000;
+
+	intel_private.registers = ioremap(reg_addr, 128 * 4096);
+	if (!intel_private.registers)
+		return -ENOMEM;
+
+	if (INTEL_GTT_GEN == 3) {
+		u32 gtt_addr;
+
+		pci_read_config_dword(intel_private.pcidev,
+				      I915_PTEADDR, &gtt_addr);
+		intel_private.gtt_bus_addr = gtt_addr;
+	} else {
+		u32 gtt_offset;
+
+		switch (INTEL_GTT_GEN) {
+		case 5:
+		case 6:
+			gtt_offset = MB(2);
+			break;
+		case 4:
 		default:
-		case SNB_GTT_SIZE_0M:
-			printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
-			*gtt_size = MB(0);
-			break;
-		case SNB_GTT_SIZE_1M:
-			*gtt_size = MB(1);
-			break;
-		case SNB_GTT_SIZE_2M:
-			*gtt_size = MB(2);
+			gtt_offset =  KB(512);
 			break;
 		}
-		break;
-	default:
-		*gtt_offset = *gtt_size = KB(512);
-	}
-}
-
-/* The intel i965 automatically initializes the agp aperture during POST.
- * Use the memory already set aside for in the GTT.
- */
-static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
-{
-	int page_order;
-	struct aper_size_info_fixed *size;
-	int num_entries;
-	u32 temp;
-	int gtt_offset, gtt_size;
-
-	size = agp_bridge->current_size;
-	page_order = size->page_order;
-	num_entries = size->num_entries;
-	agp_bridge->gatt_table_real = NULL;
-
-	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
-
-	temp &= 0xfff00000;
-
-	intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
-
-	intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
-
-	if (!intel_private.gtt)
-		return -ENOMEM;
-
-	intel_private.gtt_total_size = gtt_size / 4;
-
-	intel_private.registers = ioremap(temp, 128 * 4096);
-	if (!intel_private.registers) {
-		iounmap(intel_private.gtt);
-		return -ENOMEM;
+		intel_private.gtt_bus_addr = reg_addr + gtt_offset;
 	}
 
-	temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
-	global_cache_flush();   /* FIXME: ? */
+	intel_private.pte_bus_addr =
+		readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 
-	/* we have to call this as early as possible after the MMIO base address is known */
-	intel_i830_init_gtt_entries();
-	if (intel_private.gtt_entries == 0) {
-		iounmap(intel_private.gtt);
-		iounmap(intel_private.registers);
-		return -ENOMEM;
-	}
-
-	agp_bridge->gatt_table = NULL;
-
-	agp_bridge->gatt_bus_addr = temp;
+	intel_i9xx_setup_flush();
 
 	return 0;
 }
@@ -1475,7 +1284,7 @@
 	.cleanup		= intel_i810_cleanup,
 	.mask_memory		= intel_i810_mask_memory,
 	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
+	.agp_enable		= intel_fake_agp_enable,
 	.cache_flush		= global_cache_flush,
 	.create_gatt_table	= agp_generic_create_gatt_table,
 	.free_gatt_table	= agp_generic_free_gatt_table,
@@ -1490,161 +1299,282 @@
 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 };
 
-static const struct agp_bridge_driver intel_830_driver = {
+static const struct agp_bridge_driver intel_fake_agp_driver = {
 	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
 	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i830_configure,
-	.fetch_size		= intel_i830_fetch_size,
-	.cleanup		= intel_i830_cleanup,
-	.mask_memory		= intel_i810_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
+	.aperture_sizes		= intel_fake_agp_sizes,
+	.num_aperture_sizes	= ARRAY_SIZE(intel_fake_agp_sizes),
+	.configure		= intel_fake_agp_configure,
+	.fetch_size		= intel_fake_agp_fetch_size,
+	.cleanup		= intel_gtt_cleanup,
+	.agp_enable		= intel_fake_agp_enable,
 	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i830_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i830_insert_entries,
-	.remove_memory		= intel_i830_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
+	.create_gatt_table	= intel_fake_agp_create_gatt_table,
+	.free_gatt_table	= intel_fake_agp_free_gatt_table,
+	.insert_memory		= intel_fake_agp_insert_entries,
+	.remove_memory		= intel_fake_agp_remove_entries,
+	.alloc_by_type		= intel_fake_agp_alloc_by_type,
 	.free_by_type		= intel_i810_free_by_type,
 	.agp_alloc_page		= agp_generic_alloc_page,
 	.agp_alloc_pages        = agp_generic_alloc_pages,
 	.agp_destroy_page	= agp_generic_destroy_page,
 	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-	.chipset_flush		= intel_i830_chipset_flush,
+	.chipset_flush		= intel_fake_agp_chipset_flush,
 };
 
-static const struct agp_bridge_driver intel_915_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i9xx_configure,
-	.fetch_size		= intel_i9xx_fetch_size,
-	.cleanup		= intel_i915_cleanup,
-	.mask_memory		= intel_i810_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i915_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i915_insert_entries,
-	.remove_memory		= intel_i915_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_alloc_pages        = agp_generic_alloc_pages,
-	.agp_destroy_page	= agp_generic_destroy_page,
-	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type  = intel_i830_type_to_mask_type,
-	.chipset_flush		= intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-	.agp_map_page		= intel_agp_map_page,
-	.agp_unmap_page		= intel_agp_unmap_page,
-	.agp_map_memory		= intel_agp_map_memory,
-	.agp_unmap_memory	= intel_agp_unmap_memory,
-#endif
+static const struct intel_gtt_driver i81x_gtt_driver = {
+	.gen = 1,
+	.dma_mask_size = 32,
+};
+static const struct intel_gtt_driver i8xx_gtt_driver = {
+	.gen = 2,
+	.setup = i830_setup,
+	.cleanup = i830_cleanup,
+	.write_entry = i830_write_entry,
+	.dma_mask_size = 32,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i830_chipset_flush,
+};
+static const struct intel_gtt_driver i915_gtt_driver = {
+	.gen = 3,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	/* i945 is the last gpu to need phys mem (for overlay and cursors). */
+	.write_entry = i830_write_entry, 
+	.dma_mask_size = 32,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g33_gtt_driver = {
+	.gen = 3,
+	.is_g33 = 1,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver pineview_gtt_driver = {
+	.gen = 3,
+	.is_pineview = 1, .is_g33 = 1,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver i965_gtt_driver = {
+	.gen = 4,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver g4x_gtt_driver = {
+	.gen = 5,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver ironlake_gtt_driver = {
+	.gen = 5,
+	.is_ironlake = 1,
+	.setup = i9xx_setup,
+	.cleanup = i9xx_cleanup,
+	.write_entry = i965_write_entry,
+	.dma_mask_size = 36,
+	.check_flags = i830_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
+};
+static const struct intel_gtt_driver sandybridge_gtt_driver = {
+	.gen = 6,
+	.setup = i9xx_setup,
+	.cleanup = gen6_cleanup,
+	.write_entry = gen6_write_entry,
+	.dma_mask_size = 40,
+	.check_flags = gen6_check_flags,
+	.chipset_flush = i9xx_chipset_flush,
 };
 
-static const struct agp_bridge_driver intel_i965_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i9xx_configure,
-	.fetch_size		= intel_i9xx_fetch_size,
-	.cleanup		= intel_i915_cleanup,
-	.mask_memory		= intel_i965_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i965_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i915_insert_entries,
-	.remove_memory		= intel_i915_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_alloc_pages        = agp_generic_alloc_pages,
-	.agp_destroy_page	= agp_generic_destroy_page,
-	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type	= intel_i830_type_to_mask_type,
-	.chipset_flush		= intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-	.agp_map_page		= intel_agp_map_page,
-	.agp_unmap_page		= intel_agp_unmap_page,
-	.agp_map_memory		= intel_agp_map_memory,
-	.agp_unmap_memory	= intel_agp_unmap_memory,
-#endif
+/* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
+ * driver and gmch_driver must be non-null, and find_gmch will determine
+ * which one should be used if a gmch_chip_id is present.
+ */
+static const struct intel_gtt_driver_description {
+	unsigned int gmch_chip_id;
+	char *name;
+	const struct agp_bridge_driver *gmch_driver;
+	const struct intel_gtt_driver *gtt_driver;
+} intel_gtt_chipsets[] = {
+	{ PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver,
+		&i81x_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver,
+		&i81x_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver,
+		&i81x_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver,
+		&i81x_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82854_IG, "854",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_82865_IG, "865",
+		&intel_fake_agp_driver, &i8xx_gtt_driver},
+	{ PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
+		&intel_fake_agp_driver, &i915_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
+		&intel_fake_agp_driver, &i965_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_G33_IG, "G33",
+		&intel_fake_agp_driver, &g33_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
+		&intel_fake_agp_driver, &g33_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
+		&intel_fake_agp_driver, &g33_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
+		&intel_fake_agp_driver, &pineview_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
+		&intel_fake_agp_driver, &pineview_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_GM45_IG, "GM45",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_B43_IG, "B43",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_B43_1_IG, "B43",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_G41_IG, "G41",
+		&intel_fake_agp_driver, &g4x_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
+	    "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
+	    "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
+	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
+	{ 0, NULL, NULL }
 };
 
-static const struct agp_bridge_driver intel_gen6_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i9xx_configure,
-	.fetch_size		= intel_i9xx_fetch_size,
-	.cleanup		= intel_i915_cleanup,
-	.mask_memory		= intel_gen6_mask_memory,
-	.masks			= intel_gen6_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i965_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i915_insert_entries,
-	.remove_memory		= intel_i915_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_alloc_pages        = agp_generic_alloc_pages,
-	.agp_destroy_page	= agp_generic_destroy_page,
-	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type	= intel_gen6_type_to_mask_type,
-	.chipset_flush		= intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-	.agp_map_page		= intel_agp_map_page,
-	.agp_unmap_page		= intel_agp_unmap_page,
-	.agp_map_memory		= intel_agp_map_memory,
-	.agp_unmap_memory	= intel_agp_unmap_memory,
-#endif
-};
+static int find_gmch(u16 device)
+{
+	struct pci_dev *gmch_device;
 
-static const struct agp_bridge_driver intel_g33_driver = {
-	.owner			= THIS_MODULE,
-	.aperture_sizes		= intel_i830_sizes,
-	.size_type		= FIXED_APER_SIZE,
-	.num_aperture_sizes	= 4,
-	.needs_scratch_page	= true,
-	.configure		= intel_i9xx_configure,
-	.fetch_size		= intel_i9xx_fetch_size,
-	.cleanup		= intel_i915_cleanup,
-	.mask_memory		= intel_i965_mask_memory,
-	.masks			= intel_i810_masks,
-	.agp_enable		= intel_i810_agp_enable,
-	.cache_flush		= global_cache_flush,
-	.create_gatt_table	= intel_i915_create_gatt_table,
-	.free_gatt_table	= intel_i830_free_gatt_table,
-	.insert_memory		= intel_i915_insert_entries,
-	.remove_memory		= intel_i915_remove_entries,
-	.alloc_by_type		= intel_i830_alloc_by_type,
-	.free_by_type		= intel_i810_free_by_type,
-	.agp_alloc_page		= agp_generic_alloc_page,
-	.agp_alloc_pages        = agp_generic_alloc_pages,
-	.agp_destroy_page	= agp_generic_destroy_page,
-	.agp_destroy_pages      = agp_generic_destroy_pages,
-	.agp_type_to_mask_type	= intel_i830_type_to_mask_type,
-	.chipset_flush		= intel_i915_chipset_flush,
-#ifdef USE_PCI_DMA_API
-	.agp_map_page		= intel_agp_map_page,
-	.agp_unmap_page		= intel_agp_unmap_page,
-	.agp_map_memory		= intel_agp_map_memory,
-	.agp_unmap_memory	= intel_agp_unmap_memory,
-#endif
-};
+	gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
+	if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
+		gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
+					     device, gmch_device);
+	}
+
+	if (!gmch_device)
+		return 0;
+
+	intel_private.pcidev = gmch_device;
+	return 1;
+}
+
+int intel_gmch_probe(struct pci_dev *pdev,
+				      struct agp_bridge_data *bridge)
+{
+	int i, mask;
+	bridge->driver = NULL;
+
+	for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) {
+		if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
+			bridge->driver =
+				intel_gtt_chipsets[i].gmch_driver;
+			intel_private.driver = 
+				intel_gtt_chipsets[i].gtt_driver;
+			break;
+		}
+	}
+
+	if (!bridge->driver)
+		return 0;
+
+	bridge->dev_private_data = &intel_private;
+	bridge->dev = pdev;
+
+	intel_private.bridge_dev = pci_dev_get(pdev);
+
+	dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name);
+
+	mask = intel_private.driver->dma_mask_size;
+	if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
+		dev_err(&intel_private.pcidev->dev,
+			"set gfx device dma mask %d-bit failed!\n", mask);
+	else
+		pci_set_consistent_dma_mask(intel_private.pcidev,
+					    DMA_BIT_MASK(mask));
+
+	if (bridge->driver == &intel_810_driver)
+		return 1;
+
+	if (intel_gtt_init() != 0)
+		return 0;
+
+	return 1;
+}
+EXPORT_SYMBOL(intel_gmch_probe);
+
+struct intel_gtt *intel_gtt_get(void)
+{
+	return &intel_private.base;
+}
+EXPORT_SYMBOL(intel_gtt_get);
+
+void intel_gmch_remove(struct pci_dev *pdev)
+{
+	if (intel_private.pcidev)
+		pci_dev_put(intel_private.pcidev);
+	if (intel_private.bridge_dev)
+		pci_dev_put(intel_private.bridge_dev);
+}
+EXPORT_SYMBOL(intel_gmch_remove);
+
+MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 677b275..9d8c892 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -48,7 +48,6 @@
 	{"queues", drm_queues_info, 0},
 	{"bufs", drm_bufs_info, 0},
 	{"gem_names", drm_gem_name_info, DRIVER_GEM},
-	{"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
 	{"vma", drm_vma_info, 0},
 #endif
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 96e9631..fd033eb 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm_edid.h"
 #include "drm_edid_modes.h"
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index cff7317..3ea0692 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -92,12 +92,6 @@
 
 	spin_lock_init(&dev->object_name_lock);
 	idr_init(&dev->object_name_idr);
-	atomic_set(&dev->object_count, 0);
-	atomic_set(&dev->object_memory, 0);
-	atomic_set(&dev->pin_count, 0);
-	atomic_set(&dev->pin_memory, 0);
-	atomic_set(&dev->gtt_count, 0);
-	atomic_set(&dev->gtt_memory, 0);
 
 	mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
 	if (!mm) {
@@ -151,9 +145,6 @@
 	kref_init(&obj->handlecount);
 	obj->size = size;
 
-	atomic_inc(&dev->object_count);
-	atomic_add(obj->size, &dev->object_memory);
-
 	return 0;
 }
 EXPORT_SYMBOL(drm_gem_object_init);
@@ -180,8 +171,6 @@
 	return obj;
 fput:
 	/* Object_init mangles the global counters - readjust them. */
-	atomic_dec(&dev->object_count);
-	atomic_sub(obj->size, &dev->object_memory);
 	fput(obj->filp);
 free:
 	kfree(obj);
@@ -436,10 +425,7 @@
 void
 drm_gem_object_release(struct drm_gem_object *obj)
 {
-	struct drm_device *dev = obj->dev;
 	fput(obj->filp);
-	atomic_dec(&dev->object_count);
-	atomic_sub(obj->size, &dev->object_memory);
 }
 EXPORT_SYMBOL(drm_gem_object_release);
 
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 2ef2c78..5aff08e 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -270,20 +270,6 @@
 	return 0;
 }
 
-int drm_gem_object_info(struct seq_file *m, void* data)
-{
-	struct drm_info_node *node = (struct drm_info_node *) m->private;
-	struct drm_device *dev = node->minor->dev;
-
-	seq_printf(m, "%d objects\n", atomic_read(&dev->object_count));
-	seq_printf(m, "%d object bytes\n", atomic_read(&dev->object_memory));
-	seq_printf(m, "%d pinned\n", atomic_read(&dev->pin_count));
-	seq_printf(m, "%d pin bytes\n", atomic_read(&dev->pin_memory));
-	seq_printf(m, "%d gtt bytes\n", atomic_read(&dev->gtt_memory));
-	seq_printf(m, "%d gtt total\n", dev->gtt_total);
-	return 0;
-}
-
 #if DRM_DEBUG_CODE
 
 int drm_vma_info(struct seq_file *m, void *data)
diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c
index e571de5..9e5b07ef 100644
--- a/drivers/gpu/drm/drm_proc.c
+++ b/drivers/gpu/drm/drm_proc.c
@@ -55,7 +55,6 @@
 	{"queues", drm_queues_info, 0},
 	{"bufs", drm_bufs_info, 0},
 	{"gem_names", drm_gem_name_info, DRIVER_GEM},
-	{"gem_objects", drm_gem_object_info, DRIVER_GEM},
 #if DRM_DEBUG_CODE
 	{"vma", drm_vma_info, 0},
 #endif
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 5c8e534..f6e98dd 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -26,13 +26,13 @@
 	  intel_dvo.o \
 	  intel_ringbuffer.o \
 	  intel_overlay.o \
+	  intel_opregion.o \
 	  dvo_ch7xxx.o \
 	  dvo_ch7017.o \
 	  dvo_ivch.o \
 	  dvo_tfp410.o \
 	  dvo_sil164.o
 
-i915-$(CONFIG_ACPI)	+= i915_opregion.o
 i915-$(CONFIG_COMPAT)   += i915_ioc32.o
 
 obj-$(CONFIG_DRM_I915)  += i915.o
diff --git a/drivers/gpu/drm/i915/dvo_ch7017.c b/drivers/gpu/drm/i915/dvo_ch7017.c
index 14d5980..af70337 100644
--- a/drivers/gpu/drm/i915/dvo_ch7017.c
+++ b/drivers/gpu/drm/i915/dvo_ch7017.c
@@ -165,67 +165,44 @@
 static void ch7017_dump_regs(struct intel_dvo_device *dvo);
 static void ch7017_dpms(struct intel_dvo_device *dvo, int mode);
 
-static bool ch7017_read(struct intel_dvo_device *dvo, int addr, uint8_t *val)
+static bool ch7017_read(struct intel_dvo_device *dvo, u8 addr, u8 *val)
 {
-	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
-	u8 out_buf[2];
-	u8 in_buf[2];
-
 	struct i2c_msg msgs[] = {
 		{
 			.addr = dvo->slave_addr,
 			.flags = 0,
 			.len = 1,
-			.buf = out_buf,
+			.buf = &addr,
 		},
 		{
 			.addr = dvo->slave_addr,
 			.flags = I2C_M_RD,
 			.len = 1,
-			.buf = in_buf,
+			.buf = val,
 		}
 	};
-
-	out_buf[0] = addr;
-	out_buf[1] = 0;
-
-	if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
-		*val= in_buf[0];
-		return true;
-	};
-
-	return false;
+	return i2c_transfer(dvo->i2c_bus, msgs, 2) == 2;
 }
 
-static bool ch7017_write(struct intel_dvo_device *dvo, int addr, uint8_t val)
+static bool ch7017_write(struct intel_dvo_device *dvo, u8 addr, u8 val)
 {
-	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
-	uint8_t out_buf[2];
+	uint8_t buf[2] = { addr, val };
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
 		.flags = 0,
 		.len = 2,
-		.buf = out_buf,
+		.buf = buf,
 	};
-
-	out_buf[0] = addr;
-	out_buf[1] = val;
-
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
-		return true;
-
-	return false;
+	return i2c_transfer(dvo->i2c_bus, &msg, 1) == 1;
 }
 
 /** Probes for a CH7017 on the given bus and slave address. */
 static bool ch7017_init(struct intel_dvo_device *dvo,
 			struct i2c_adapter *adapter)
 {
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	struct ch7017_priv *priv;
-	uint8_t val;
+	const char *str;
+	u8 val;
 
 	priv = kzalloc(sizeof(struct ch7017_priv), GFP_KERNEL);
 	if (priv == NULL)
@@ -237,16 +214,27 @@
 	if (!ch7017_read(dvo, CH7017_DEVICE_ID, &val))
 		goto fail;
 
-	if (val != CH7017_DEVICE_ID_VALUE &&
-	    val != CH7018_DEVICE_ID_VALUE &&
-	    val != CH7019_DEVICE_ID_VALUE) {
+	switch (val) {
+	case CH7017_DEVICE_ID_VALUE:
+		str = "ch7017";
+		break;
+	case CH7018_DEVICE_ID_VALUE:
+		str = "ch7018";
+		break;
+	case CH7019_DEVICE_ID_VALUE:
+		str = "ch7019";
+		break;
+	default:
 		DRM_DEBUG_KMS("ch701x not detected, got %d: from %s "
-				"Slave %d.\n",
-			  val, i2cbus->adapter.name,dvo->slave_addr);
+			      "slave %d.\n",
+			      val, adapter->name,dvo->slave_addr);
 		goto fail;
 	}
 
+	DRM_DEBUG_KMS("%s detected on %s, addr %d\n",
+		      str, adapter->name, dvo->slave_addr);
 	return true;
+
 fail:
 	kfree(priv);
 	return false;
@@ -368,7 +356,7 @@
 	}
 
 	/* XXX: Should actually wait for update power status somehow */
-	udelay(20000);
+	msleep(20);
 }
 
 static void ch7017_dump_regs(struct intel_dvo_device *dvo)
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
index 6f1944b..7eaa94e 100644
--- a/drivers/gpu/drm/i915/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c
@@ -113,7 +113,6 @@
 {
 	struct ch7xxx_priv *ch7xxx= dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[2];
 	u8 in_buf[2];
 
@@ -135,14 +134,14 @@
 	out_buf[0] = addr;
 	out_buf[1] = 0;
 
-	if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+	if (i2c_transfer(adapter, msgs, 2) == 2) {
 		*ch = in_buf[0];
 		return true;
 	};
 
 	if (!ch7xxx->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 	return false;
 }
@@ -152,7 +151,6 @@
 {
 	struct ch7xxx_priv *ch7xxx = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	uint8_t out_buf[2];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -164,12 +162,12 @@
 	out_buf[0] = addr;
 	out_buf[1] = ch;
 
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1)
 		return true;
 
 	if (!ch7xxx->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 
 	return false;
diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c
index a2ec3f4..a12ed94 100644
--- a/drivers/gpu/drm/i915/dvo_ivch.c
+++ b/drivers/gpu/drm/i915/dvo_ivch.c
@@ -167,7 +167,6 @@
 {
 	struct ivch_priv *priv = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[1];
 	u8 in_buf[2];
 
@@ -193,7 +192,7 @@
 
 	out_buf[0] = addr;
 
-	if (i2c_transfer(&i2cbus->adapter, msgs, 3) == 3) {
+	if (i2c_transfer(adapter, msgs, 3) == 3) {
 		*data = (in_buf[1] << 8) | in_buf[0];
 		return true;
 	};
@@ -201,7 +200,7 @@
 	if (!priv->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from "
 				"%s:%02x.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 	return false;
 }
@@ -211,7 +210,6 @@
 {
 	struct ivch_priv *priv = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[3];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -224,12 +222,12 @@
 	out_buf[1] = data & 0xff;
 	out_buf[2] = data >> 8;
 
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1)
 		return true;
 
 	if (!priv->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 
 	return false;
diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c
index 9b8e676..e4b4091 100644
--- a/drivers/gpu/drm/i915/dvo_sil164.c
+++ b/drivers/gpu/drm/i915/dvo_sil164.c
@@ -69,7 +69,6 @@
 {
 	struct sil164_priv *sil = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[2];
 	u8 in_buf[2];
 
@@ -91,14 +90,14 @@
 	out_buf[0] = addr;
 	out_buf[1] = 0;
 
-	if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+	if (i2c_transfer(adapter, msgs, 2) == 2) {
 		*ch = in_buf[0];
 		return true;
 	};
 
 	if (!sil->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 	return false;
 }
@@ -107,7 +106,6 @@
 {
 	struct sil164_priv *sil= dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	uint8_t out_buf[2];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -119,12 +117,12 @@
 	out_buf[0] = addr;
 	out_buf[1] = ch;
 
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1)
 		return true;
 
 	if (!sil->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 
 	return false;
diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c
index 56f6642..8ab2855 100644
--- a/drivers/gpu/drm/i915/dvo_tfp410.c
+++ b/drivers/gpu/drm/i915/dvo_tfp410.c
@@ -94,7 +94,6 @@
 {
 	struct tfp410_priv *tfp = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	u8 out_buf[2];
 	u8 in_buf[2];
 
@@ -116,14 +115,14 @@
 	out_buf[0] = addr;
 	out_buf[1] = 0;
 
-	if (i2c_transfer(&i2cbus->adapter, msgs, 2) == 2) {
+	if (i2c_transfer(adapter, msgs, 2) == 2) {
 		*ch = in_buf[0];
 		return true;
 	};
 
 	if (!tfp->quiet) {
 		DRM_DEBUG_KMS("Unable to read register 0x%02x from %s:%02x.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 	return false;
 }
@@ -132,7 +131,6 @@
 {
 	struct tfp410_priv *tfp = dvo->dev_priv;
 	struct i2c_adapter *adapter = dvo->i2c_bus;
-	struct intel_i2c_chan *i2cbus = container_of(adapter, struct intel_i2c_chan, adapter);
 	uint8_t out_buf[2];
 	struct i2c_msg msg = {
 		.addr = dvo->slave_addr,
@@ -144,12 +142,12 @@
 	out_buf[0] = addr;
 	out_buf[1] = ch;
 
-	if (i2c_transfer(&i2cbus->adapter, &msg, 1) == 1)
+	if (i2c_transfer(adapter, &msg, 1) == 1)
 		return true;
 
 	if (!tfp->quiet) {
 		DRM_DEBUG_KMS("Unable to write register 0x%02x to %s:%d.\n",
-			  addr, i2cbus->adapter.name, dvo->slave_addr);
+			  addr, adapter->name, dvo->slave_addr);
 	}
 
 	return false;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 5e43d70..d598070f 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -40,9 +40,51 @@
 
 #if defined(CONFIG_DEBUG_FS)
 
-#define ACTIVE_LIST	1
-#define FLUSHING_LIST	2
-#define INACTIVE_LIST	3
+enum {
+	RENDER_LIST,
+	BSD_LIST,
+	FLUSHING_LIST,
+	INACTIVE_LIST,
+	PINNED_LIST,
+	DEFERRED_FREE_LIST,
+};
+
+static const char *yesno(int v)
+{
+	return v ? "yes" : "no";
+}
+
+static int i915_capabilities(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	const struct intel_device_info *info = INTEL_INFO(dev);
+
+	seq_printf(m, "gen: %d\n", info->gen);
+#define B(x) seq_printf(m, #x ": %s\n", yesno(info->x))
+	B(is_mobile);
+	B(is_i85x);
+	B(is_i915g);
+	B(is_i945gm);
+	B(is_g33);
+	B(need_gfx_hws);
+	B(is_g4x);
+	B(is_pineview);
+	B(is_broadwater);
+	B(is_crestline);
+	B(is_ironlake);
+	B(has_fbc);
+	B(has_rc6);
+	B(has_pipe_cxsr);
+	B(has_hotplug);
+	B(cursor_needs_physical);
+	B(has_overlay);
+	B(overlay_needs_physical);
+	B(supports_tv);
+#undef B
+
+	return 0;
+}
 
 static const char *get_pin_flag(struct drm_i915_gem_object *obj_priv)
 {
@@ -64,6 +106,27 @@
     }
 }
 
+static void
+describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
+{
+	seq_printf(m, "%p: %s%s %8zd %08x %08x %d%s%s",
+		   &obj->base,
+		   get_pin_flag(obj),
+		   get_tiling_flag(obj),
+		   obj->base.size,
+		   obj->base.read_domains,
+		   obj->base.write_domain,
+		   obj->last_rendering_seqno,
+		   obj->dirty ? " dirty" : "",
+		   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
+	if (obj->base.name)
+		seq_printf(m, " (name: %d)", obj->base.name);
+	if (obj->fence_reg != I915_FENCE_REG_NONE)
+		seq_printf(m, " (fence: %d)", obj->fence_reg);
+	if (obj->gtt_space != NULL)
+		seq_printf(m, " (gtt_offset: %08x)", obj->gtt_offset);
+}
+
 static int i915_gem_object_list_info(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -72,56 +135,84 @@
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv;
-	spinlock_t *lock = NULL;
+	size_t total_obj_size, total_gtt_size;
+	int count, ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	switch (list) {
-	case ACTIVE_LIST:
-		seq_printf(m, "Active:\n");
-		lock = &dev_priv->mm.active_list_lock;
+	case RENDER_LIST:
+		seq_printf(m, "Render:\n");
 		head = &dev_priv->render_ring.active_list;
 		break;
+	case BSD_LIST:
+		seq_printf(m, "BSD:\n");
+		head = &dev_priv->bsd_ring.active_list;
+		break;
 	case INACTIVE_LIST:
 		seq_printf(m, "Inactive:\n");
 		head = &dev_priv->mm.inactive_list;
 		break;
+	case PINNED_LIST:
+		seq_printf(m, "Pinned:\n");
+		head = &dev_priv->mm.pinned_list;
+		break;
 	case FLUSHING_LIST:
 		seq_printf(m, "Flushing:\n");
 		head = &dev_priv->mm.flushing_list;
 		break;
+	case DEFERRED_FREE_LIST:
+		seq_printf(m, "Deferred free:\n");
+		head = &dev_priv->mm.deferred_free_list;
+		break;
 	default:
-		DRM_INFO("Ooops, unexpected list\n");
-		return 0;
+		mutex_unlock(&dev->struct_mutex);
+		return -EINVAL;
 	}
 
-	if (lock)
-		spin_lock(lock);
-	list_for_each_entry(obj_priv, head, list)
-	{
-		seq_printf(m, "    %p: %s %8zd %08x %08x %d%s%s",
-			   &obj_priv->base,
-			   get_pin_flag(obj_priv),
-			   obj_priv->base.size,
-			   obj_priv->base.read_domains,
-			   obj_priv->base.write_domain,
-			   obj_priv->last_rendering_seqno,
-			   obj_priv->dirty ? " dirty" : "",
-			   obj_priv->madv == I915_MADV_DONTNEED ? " purgeable" : "");
-
-		if (obj_priv->base.name)
-			seq_printf(m, " (name: %d)", obj_priv->base.name);
-		if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-			seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
-		if (obj_priv->gtt_space != NULL)
-			seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
-
+	total_obj_size = total_gtt_size = count = 0;
+	list_for_each_entry(obj_priv, head, list) {
+		seq_printf(m, "   ");
+		describe_obj(m, obj_priv);
 		seq_printf(m, "\n");
+		total_obj_size += obj_priv->base.size;
+		total_gtt_size += obj_priv->gtt_space->size;
+		count++;
 	}
+	mutex_unlock(&dev->struct_mutex);
 
-	if (lock)
-	    spin_unlock(lock);
+	seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n",
+		   count, total_obj_size, total_gtt_size);
 	return 0;
 }
 
+static int i915_gem_object_info(struct seq_file *m, void* data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	seq_printf(m, "%u objects\n", dev_priv->mm.object_count);
+	seq_printf(m, "%zu object bytes\n", dev_priv->mm.object_memory);
+	seq_printf(m, "%u pinned\n", dev_priv->mm.pin_count);
+	seq_printf(m, "%zu pin bytes\n", dev_priv->mm.pin_memory);
+	seq_printf(m, "%u objects in gtt\n", dev_priv->mm.gtt_count);
+	seq_printf(m, "%zu gtt bytes\n", dev_priv->mm.gtt_memory);
+	seq_printf(m, "%zu gtt total\n", dev_priv->mm.gtt_total);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+
 static int i915_gem_pageflip_info(struct seq_file *m, void *data)
 {
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -176,6 +267,11 @@
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_request *gem_request;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	seq_printf(m, "Request:\n");
 	list_for_each_entry(gem_request, &dev_priv->render_ring.request_list,
@@ -184,6 +280,8 @@
 			   gem_request->seqno,
 			   (int) (jiffies - gem_request->emitted_jiffies));
 	}
+	mutex_unlock(&dev->struct_mutex);
+
 	return 0;
 }
 
@@ -192,16 +290,24 @@
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	if (dev_priv->render_ring.status_page.page_addr != NULL) {
 		seq_printf(m, "Current sequence: %d\n",
-			   i915_get_gem_seqno(dev,  &dev_priv->render_ring));
+			   dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
 	} else {
 		seq_printf(m, "Current sequence: hws uninitialized\n");
 	}
 	seq_printf(m, "Waiter sequence:  %d\n",
 			dev_priv->mm.waiting_gem_seqno);
 	seq_printf(m, "IRQ sequence:     %d\n", dev_priv->mm.irq_gem_seqno);
+
+	mutex_unlock(&dev->struct_mutex);
+
 	return 0;
 }
 
@@ -211,6 +317,11 @@
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	if (!HAS_PCH_SPLIT(dev)) {
 		seq_printf(m, "Interrupt enable:    %08x\n",
@@ -247,7 +358,7 @@
 		   atomic_read(&dev_priv->irq_received));
 	if (dev_priv->render_ring.status_page.page_addr != NULL) {
 		seq_printf(m, "Current sequence:    %d\n",
-			   i915_get_gem_seqno(dev,  &dev_priv->render_ring));
+			   dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring));
 	} else {
 		seq_printf(m, "Current sequence:    hws uninitialized\n");
 	}
@@ -255,6 +366,8 @@
 		   dev_priv->mm.waiting_gem_seqno);
 	seq_printf(m, "IRQ sequence:        %d\n",
 		   dev_priv->mm.irq_gem_seqno);
+	mutex_unlock(&dev->struct_mutex);
+
 	return 0;
 }
 
@@ -263,7 +376,11 @@
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int i;
+	int i, ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	seq_printf(m, "Reserved fences = %d\n", dev_priv->fence_reg_start);
 	seq_printf(m, "Total fences = %d\n", dev_priv->num_fence_regs);
@@ -289,6 +406,7 @@
 			seq_printf(m, "\n");
 		}
 	}
+	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
 }
@@ -313,16 +431,19 @@
 	return 0;
 }
 
-static void i915_dump_pages(struct seq_file *m, struct page **pages, int page_count)
+static void i915_dump_object(struct seq_file *m,
+			     struct io_mapping *mapping,
+			     struct drm_i915_gem_object *obj_priv)
 {
-	int page, i;
-	uint32_t *mem;
+	int page, page_count, i;
 
+	page_count = obj_priv->base.size / PAGE_SIZE;
 	for (page = 0; page < page_count; page++) {
-		mem = kmap_atomic(pages[page], KM_USER0);
+		u32 *mem = io_mapping_map_wc(mapping,
+					     obj_priv->gtt_offset + page * PAGE_SIZE);
 		for (i = 0; i < PAGE_SIZE; i += 4)
 			seq_printf(m, "%08x :  %08x\n", i, mem[i / 4]);
-		kunmap_atomic(mem, KM_USER0);
+		io_mapping_unmap(mem);
 	}
 }
 
@@ -335,27 +456,21 @@
 	struct drm_i915_gem_object *obj_priv;
 	int ret;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list,
 			list) {
 		obj = &obj_priv->base;
 		if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
-		    ret = i915_gem_object_get_pages(obj, 0);
-		    if (ret) {
-			    DRM_ERROR("Failed to get pages: %d\n", ret);
-			    spin_unlock(&dev_priv->mm.active_list_lock);
-			    return ret;
-		    }
-
-		    seq_printf(m, "--- gtt_offset = 0x%08x\n", obj_priv->gtt_offset);
-		    i915_dump_pages(m, obj_priv->pages, obj->size / PAGE_SIZE);
-
-		    i915_gem_object_put_pages(obj);
+		    seq_printf(m, "--- gtt_offset = 0x%08x\n",
+			       obj_priv->gtt_offset);
+		    i915_dump_object(m, dev_priv->mm.gtt_mapping, obj_priv);
 		}
 	}
 
-	spin_unlock(&dev_priv->mm.active_list_lock);
+	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
 }
@@ -365,20 +480,24 @@
 	struct drm_info_node *node = (struct drm_info_node *) m->private;
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	u8 *virt;
-	uint32_t *ptr, off;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	if (!dev_priv->render_ring.gem_object) {
 		seq_printf(m, "No ringbuffer setup\n");
-		return 0;
-	}
+	} else {
+		u8 *virt = dev_priv->render_ring.virtual_start;
+		uint32_t off;
 
-	virt = dev_priv->render_ring.virtual_start;
-
-	for (off = 0; off < dev_priv->render_ring.size; off += 4) {
-		ptr = (uint32_t *)(virt + off);
-		seq_printf(m, "%08x :  %08x\n", off, *ptr);
+		for (off = 0; off < dev_priv->render_ring.size; off += 4) {
+			uint32_t *ptr = (uint32_t *)(virt + off);
+			seq_printf(m, "%08x :  %08x\n", off, *ptr);
+		}
 	}
+	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
 }
@@ -396,7 +515,7 @@
 	seq_printf(m, "RingHead :  %08x\n", head);
 	seq_printf(m, "RingTail :  %08x\n", tail);
 	seq_printf(m, "RingSize :  %08lx\n", dev_priv->render_ring.size);
-	seq_printf(m, "Acthd :     %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
+	seq_printf(m, "Acthd :     %08x\n", I915_READ(INTEL_INFO(dev)->gen >= 4 ? ACTHD_I965 : ACTHD));
 
 	return 0;
 }
@@ -458,7 +577,7 @@
 	seq_printf(m, "  IPEHR: 0x%08x\n", error->ipehr);
 	seq_printf(m, "  INSTDONE: 0x%08x\n", error->instdone);
 	seq_printf(m, "  ACTHD: 0x%08x\n", error->acthd);
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		seq_printf(m, "  INSTPS: 0x%08x\n", error->instps);
 		seq_printf(m, "  INSTDONE1: 0x%08x\n", error->instdone1);
 	}
@@ -642,6 +761,9 @@
 	} else {
 		seq_printf(m, "FBC disabled: ");
 		switch (dev_priv->no_fbc_reason) {
+		case FBC_NO_OUTPUT:
+			seq_printf(m, "no outputs");
+			break;
 		case FBC_STOLEN_TOO_SMALL:
 			seq_printf(m, "not enough stolen memory");
 			break;
@@ -675,15 +797,17 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	bool sr_enabled = false;
 
-	if (IS_I965GM(dev) || IS_I945G(dev) || IS_I945GM(dev))
+	if (IS_IRONLAKE(dev))
+		sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
+	else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
 		sr_enabled = I915_READ(FW_BLC_SELF) & FW_BLC_SELF_EN;
 	else if (IS_I915GM(dev))
 		sr_enabled = I915_READ(INSTPM) & INSTPM_SELF_EN;
 	else if (IS_PINEVIEW(dev))
 		sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
 
-	seq_printf(m, "self-refresh: %s\n", sr_enabled ? "enabled" :
-		   "disabled");
+	seq_printf(m, "self-refresh: %s\n",
+		   sr_enabled ? "enabled" : "disabled");
 
 	return 0;
 }
@@ -694,10 +818,16 @@
 	struct drm_device *dev = node->minor->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	unsigned long temp, chipset, gfx;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
 
 	temp = i915_mch_val(dev_priv);
 	chipset = i915_chipset_val(dev_priv);
 	gfx = i915_gfx_val(dev_priv);
+	mutex_unlock(&dev->struct_mutex);
 
 	seq_printf(m, "GMCH temp: %ld\n", temp);
 	seq_printf(m, "Chipset power: %ld\n", chipset);
@@ -718,6 +848,68 @@
 	return 0;
 }
 
+static int i915_opregion(struct seq_file *m, void *unused)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_opregion *opregion = &dev_priv->opregion;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	if (opregion->header)
+		seq_write(m, opregion->header, OPREGION_SIZE);
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
+{
+	struct drm_info_node *node = (struct drm_info_node *) m->private;
+	struct drm_device *dev = node->minor->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_fbdev *ifbdev;
+	struct intel_framebuffer *fb;
+	int ret;
+
+	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+	if (ret)
+		return ret;
+
+	ifbdev = dev_priv->fbdev;
+	fb = to_intel_framebuffer(ifbdev->helper.fb);
+
+	seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ",
+		   fb->base.width,
+		   fb->base.height,
+		   fb->base.depth,
+		   fb->base.bits_per_pixel);
+	describe_obj(m, to_intel_bo(fb->obj));
+	seq_printf(m, "\n");
+
+	list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
+		if (&fb->base == ifbdev->helper.fb)
+			continue;
+
+		seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ",
+			   fb->base.width,
+			   fb->base.height,
+			   fb->base.depth,
+			   fb->base.bits_per_pixel);
+		describe_obj(m, to_intel_bo(fb->obj));
+		seq_printf(m, "\n");
+	}
+
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return 0;
+}
+
 static int
 i915_wedged_open(struct inode *inode,
 		 struct file *filp)
@@ -741,6 +933,9 @@
 		       "wedged :  %d\n",
 		       atomic_read(&dev_priv->mm.wedged));
 
+	if (len > sizeof (buf))
+		len = sizeof (buf);
+
 	return simple_read_from_buffer(ubuf, max, ppos, buf, len);
 }
 
@@ -770,7 +965,7 @@
 
 	atomic_set(&dev_priv->mm.wedged, val);
 	if (val) {
-		DRM_WAKEUP(&dev_priv->irq_queue);
+		wake_up_all(&dev_priv->irq_queue);
 		queue_work(dev_priv->wq, &dev_priv->error_work);
 	}
 
@@ -823,9 +1018,14 @@
 }
 
 static struct drm_info_list i915_debugfs_list[] = {
-	{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
+	{"i915_capabilities", i915_capabilities, 0, 0},
+	{"i915_gem_objects", i915_gem_object_info, 0},
+	{"i915_gem_render_active", i915_gem_object_list_info, 0, (void *) RENDER_LIST},
+	{"i915_gem_bsd_active", i915_gem_object_list_info, 0, (void *) BSD_LIST},
 	{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
 	{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
+	{"i915_gem_pinned", i915_gem_object_list_info, 0, (void *) PINNED_LIST},
+	{"i915_gem_deferred_free", i915_gem_object_list_info, 0, (void *) DEFERRED_FREE_LIST},
 	{"i915_gem_pageflip", i915_gem_pageflip_info, 0},
 	{"i915_gem_request", i915_gem_request_info, 0},
 	{"i915_gem_seqno", i915_gem_seqno_info, 0},
@@ -845,6 +1045,8 @@
 	{"i915_gfxec", i915_gfxec, 0},
 	{"i915_fbc_status", i915_fbc_status, 0},
 	{"i915_sr_status", i915_sr_status, 0},
+	{"i915_opregion", i915_opregion, 0},
+	{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 9d67b48..726c373 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -40,8 +40,7 @@
 #include <linux/pnp.h>
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
-
-extern int intel_max_stolen; /* from AGP driver */
+#include <acpi/video.h>
 
 /**
  * Sets up the hardware status page for devices that need a physical address
@@ -64,7 +63,7 @@
 
 	memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
 					     0xf0;
 
@@ -222,7 +221,7 @@
 	DRM_DEBUG_DRIVER("hw status page @ %p\n",
 				ring->status_page.page_addr);
 	if (ring->status_page.gfx_addr != 0)
-		ring->setup_status_page(dev, ring);
+		intel_ring_setup_status_page(dev, ring);
 	else
 		I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
 
@@ -377,7 +376,7 @@
 		return -EINVAL;
 	}
 
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		BEGIN_LP_RING(4);
 		OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
 		OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
@@ -481,7 +480,7 @@
 
 		if (!IS_I830(dev) && !IS_845G(dev)) {
 			BEGIN_LP_RING(2);
-			if (IS_I965G(dev)) {
+			if (INTEL_INFO(dev)->gen >= 4) {
 				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
 				OUT_RING(batch->start);
 			} else {
@@ -888,12 +887,12 @@
 intel_alloc_mchbar_resource(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
 	u32 temp_lo, temp_hi = 0;
 	u64 mchbar_addr;
 	int ret;
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		pci_read_config_dword(dev_priv->bridge_dev, reg + 4, &temp_hi);
 	pci_read_config_dword(dev_priv->bridge_dev, reg, &temp_lo);
 	mchbar_addr = ((u64)temp_hi << 32) | temp_lo;
@@ -920,7 +919,7 @@
 		return ret;
 	}
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		pci_write_config_dword(dev_priv->bridge_dev, reg + 4,
 				       upper_32_bits(dev_priv->mch_res.start));
 
@@ -934,7 +933,7 @@
 intel_setup_mchbar(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
 	u32 temp;
 	bool enabled;
 
@@ -971,7 +970,7 @@
 intel_teardown_mchbar(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	int mchbar_reg = IS_I965G(dev) ? MCHBAR_I965 : MCHBAR_I915;
+	int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
 	u32 temp;
 
 	if (dev_priv->mchbar_need_disable) {
@@ -990,174 +989,6 @@
 		release_resource(&dev_priv->mch_res);
 }
 
-/**
- * i915_probe_agp - get AGP bootup configuration
- * @pdev: PCI device
- * @aperture_size: returns AGP aperture configured size
- * @preallocated_size: returns size of BIOS preallocated AGP space
- *
- * Since Intel integrated graphics are UMA, the BIOS has to set aside
- * some RAM for the framebuffer at early boot.  This code figures out
- * how much was set aside so we can use it for our own purposes.
- */
-static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
-			  uint32_t *preallocated_size,
-			  uint32_t *start)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u16 tmp = 0;
-	unsigned long overhead;
-	unsigned long stolen;
-
-	/* Get the fb aperture size and "stolen" memory amount. */
-	pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &tmp);
-
-	*aperture_size = 1024 * 1024;
-	*preallocated_size = 1024 * 1024;
-
-	switch (dev->pdev->device) {
-	case PCI_DEVICE_ID_INTEL_82830_CGC:
-	case PCI_DEVICE_ID_INTEL_82845G_IG:
-	case PCI_DEVICE_ID_INTEL_82855GM_IG:
-	case PCI_DEVICE_ID_INTEL_82865_IG:
-		if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
-			*aperture_size *= 64;
-		else
-			*aperture_size *= 128;
-		break;
-	default:
-		/* 9xx supports large sizes, just look at the length */
-		*aperture_size = pci_resource_len(dev->pdev, 2);
-		break;
-	}
-
-	/*
-	 * Some of the preallocated space is taken by the GTT
-	 * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
-	 */
-	if (IS_G4X(dev) || IS_PINEVIEW(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev))
-		overhead = 4096;
-	else
-		overhead = (*aperture_size / 1024) + 4096;
-
-	if (IS_GEN6(dev)) {
-		/* SNB has memory control reg at 0x50.w */
-		pci_read_config_word(dev->pdev, SNB_GMCH_CTRL, &tmp);
-
-		switch (tmp & SNB_GMCH_GMS_STOLEN_MASK) {
-		case INTEL_855_GMCH_GMS_DISABLED:
-			DRM_ERROR("video memory is disabled\n");
-			return -1;
-		case SNB_GMCH_GMS_STOLEN_32M:
-			stolen = 32 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_64M:
-			stolen = 64 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_96M:
-			stolen = 96 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_128M:
-			stolen = 128 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_160M:
-			stolen = 160 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_192M:
-			stolen = 192 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_224M:
-			stolen = 224 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_256M:
-			stolen = 256 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_288M:
-			stolen = 288 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_320M:
-			stolen = 320 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_352M:
-			stolen = 352 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_384M:
-			stolen = 384 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_416M:
-			stolen = 416 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_448M:
-			stolen = 448 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_480M:
-			stolen = 480 * 1024 * 1024;
-			break;
-		case SNB_GMCH_GMS_STOLEN_512M:
-			stolen = 512 * 1024 * 1024;
-			break;
-		default:
-			DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
-				  tmp & SNB_GMCH_GMS_STOLEN_MASK);
-			return -1;
-		}
-	} else {
-		switch (tmp & INTEL_GMCH_GMS_MASK) {
-		case INTEL_855_GMCH_GMS_DISABLED:
-			DRM_ERROR("video memory is disabled\n");
-			return -1;
-		case INTEL_855_GMCH_GMS_STOLEN_1M:
-			stolen = 1 * 1024 * 1024;
-			break;
-		case INTEL_855_GMCH_GMS_STOLEN_4M:
-			stolen = 4 * 1024 * 1024;
-			break;
-		case INTEL_855_GMCH_GMS_STOLEN_8M:
-			stolen = 8 * 1024 * 1024;
-			break;
-		case INTEL_855_GMCH_GMS_STOLEN_16M:
-			stolen = 16 * 1024 * 1024;
-			break;
-		case INTEL_855_GMCH_GMS_STOLEN_32M:
-			stolen = 32 * 1024 * 1024;
-			break;
-		case INTEL_915G_GMCH_GMS_STOLEN_48M:
-			stolen = 48 * 1024 * 1024;
-			break;
-		case INTEL_915G_GMCH_GMS_STOLEN_64M:
-			stolen = 64 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_128M:
-			stolen = 128 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_256M:
-			stolen = 256 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_96M:
-			stolen = 96 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_160M:
-			stolen = 160 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_224M:
-			stolen = 224 * 1024 * 1024;
-			break;
-		case INTEL_GMCH_GMS_STOLEN_352M:
-			stolen = 352 * 1024 * 1024;
-			break;
-		default:
-			DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
-				  tmp & INTEL_GMCH_GMS_MASK);
-			return -1;
-		}
-	}
-
-	*preallocated_size = stolen - overhead;
-	*start = overhead;
-
-	return 0;
-}
-
 #define PTE_ADDRESS_MASK		0xfffff000
 #define PTE_ADDRESS_MASK_HIGH		0x000000f0 /* i915+ */
 #define PTE_MAPPING_TYPE_UNCACHED	(0 << 1)
@@ -1181,11 +1012,11 @@
 {
 	unsigned long *gtt;
 	unsigned long entry, phys;
-	int gtt_bar = IS_I9XX(dev) ? 0 : 1;
+	int gtt_bar = IS_GEN2(dev) ? 1 : 0;
 	int gtt_offset, gtt_size;
 
-	if (IS_I965G(dev)) {
-		if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
+		if (IS_G4X(dev) || INTEL_INFO(dev)->gen > 4) {
 			gtt_offset = 2*1024*1024;
 			gtt_size = 2*1024*1024;
 		} else {
@@ -1210,10 +1041,8 @@
 	DRM_DEBUG_DRIVER("GTT addr: 0x%08lx, PTE: 0x%08lx\n", gtt_addr, entry);
 
 	/* Mask out these reserved bits on this hardware. */
-	if (!IS_I9XX(dev) || IS_I915G(dev) || IS_I915GM(dev) ||
-	    IS_I945G(dev) || IS_I945GM(dev)) {
+	if (INTEL_INFO(dev)->gen < 4 && !IS_G33(dev))
 		entry &= ~PTE_ADDRESS_MASK_HIGH;
-	}
 
 	/* If it's not a mapping type we know, then bail. */
 	if ((entry & PTE_MAPPING_TYPE_MASK) != PTE_MAPPING_TYPE_UNCACHED &&
@@ -1252,7 +1081,7 @@
 	unsigned long ll_base = 0;
 
 	/* Leave 1M for line length buffer & misc. */
-	compressed_fb = drm_mm_search_free(&dev_priv->vram, size, 4096, 0);
+	compressed_fb = drm_mm_search_free(&dev_priv->mm.vram, size, 4096, 0);
 	if (!compressed_fb) {
 		dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
 		i915_warn_stolen(dev);
@@ -1273,7 +1102,7 @@
 	}
 
 	if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) {
-		compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096,
+		compressed_llb = drm_mm_search_free(&dev_priv->mm.vram, 4096,
 						    4096, 0);
 		if (!compressed_llb) {
 			i915_warn_stolen(dev);
@@ -1343,10 +1172,8 @@
 		/* i915 resume handler doesn't set to D0 */
 		pci_set_power_state(dev->pdev, PCI_D0);
 		i915_resume(dev);
-		drm_kms_helper_poll_enable(dev);
 	} else {
 		printk(KERN_ERR "i915: switched off\n");
-		drm_kms_helper_poll_disable(dev);
 		i915_suspend(dev, pmm);
 	}
 }
@@ -1363,20 +1190,14 @@
 }
 
 static int i915_load_modeset_init(struct drm_device *dev,
-				  unsigned long prealloc_start,
 				  unsigned long prealloc_size,
 				  unsigned long agp_size)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int fb_bar = IS_I9XX(dev) ? 2 : 0;
 	int ret = 0;
 
-	dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) &
-		0xff000000;
-
-	/* Basic memrange allocator for stolen space (aka vram) */
-	drm_mm_init(&dev_priv->vram, 0, prealloc_size);
-	DRM_INFO("set up %ldM of stolen space\n", prealloc_size / (1024*1024));
+	/* Basic memrange allocator for stolen space (aka mm.vram) */
+	drm_mm_init(&dev_priv->mm.vram, 0, prealloc_size);
 
 	/* We're off and running w/KMS */
 	dev_priv->mm.suspended = 0;
@@ -1443,12 +1264,6 @@
 	/* FIXME: do pre/post-mode set stuff in core KMS code */
 	dev->vblank_disable_allowed = 1;
 
-	/*
-	 * Initialize the hardware status page IRQ location.
-	 */
-
-	I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
-
 	ret = intel_fbdev_init(dev);
 	if (ret)
 		goto cleanup_irq;
@@ -1787,9 +1602,9 @@
 		}
 	}
 
-	div_u64(diff, diff1);
+	diff = div_u64(diff, diff1);
 	ret = ((m * diff) + c);
-	div_u64(ret, 10);
+	ret = div_u64(ret, 10);
 
 	dev_priv->last_count1 = total_count;
 	dev_priv->last_time1 = now;
@@ -1858,7 +1673,7 @@
 
 	/* More magic constants... */
 	diff = diff * 1181;
-	div_u64(diff, diffms * 10);
+	diff = div_u64(diff, diffms * 10);
 	dev_priv->gfx_power = diff;
 }
 
@@ -1907,7 +1722,7 @@
  *   - dev_priv->fmax
  *   - dev_priv->gpu_busy
  */
-DEFINE_SPINLOCK(mchdev_lock);
+static DEFINE_SPINLOCK(mchdev_lock);
 
 /**
  * i915_read_mch_val - return value for IPS use
@@ -2062,7 +1877,7 @@
 	struct drm_i915_private *dev_priv;
 	resource_size_t base, size;
 	int ret = 0, mmio_bar;
-	uint32_t agp_size, prealloc_size, prealloc_start;
+	uint32_t agp_size, prealloc_size;
 	/* i915 has 4 more counters */
 	dev->counters += 4;
 	dev->types[6] = _DRM_STAT_IRQ;
@@ -2079,7 +1894,7 @@
 	dev_priv->info = (struct intel_device_info *) flags;
 
 	/* Add register map (needed for suspend/resume) */
-	mmio_bar = IS_I9XX(dev) ? 0 : 1;
+	mmio_bar = IS_GEN2(dev) ? 1 : 0;
 	base = pci_resource_start(dev->pdev, mmio_bar);
 	size = pci_resource_len(dev->pdev, mmio_bar);
 
@@ -2121,17 +1936,32 @@
 			 "performance may suffer.\n");
 	}
 
-	ret = i915_probe_agp(dev, &agp_size, &prealloc_size, &prealloc_start);
-	if (ret)
+	dev_priv->mm.gtt = intel_gtt_get();
+	if (!dev_priv->mm.gtt) {
+		DRM_ERROR("Failed to initialize GTT\n");
+		ret = -ENODEV;
 		goto out_iomapfree;
-
-	if (prealloc_size > intel_max_stolen) {
-		DRM_INFO("detected %dM stolen memory, trimming to %dM\n",
-			 prealloc_size >> 20, intel_max_stolen >> 20);
-		prealloc_size = intel_max_stolen;
 	}
 
-	dev_priv->wq = create_singlethread_workqueue("i915");
+	prealloc_size = dev_priv->mm.gtt->gtt_stolen_entries << PAGE_SHIFT;
+	agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+
+	/* The i915 workqueue is primarily used for batched retirement of
+	 * requests (and thus managing bo) once the task has been completed
+	 * by the GPU. i915_gem_retire_requests() is called directly when we
+	 * need high-priority retirement, such as waiting for an explicit
+	 * bo.
+	 *
+	 * It is also used for periodic low-priority events, such as
+	 * idle-timers and hangcheck.
+	 *
+	 * All tasks on the workqueue are expected to acquire the dev mutex
+	 * so there is no point in running more than one instance of the
+	 * workqueue at any time: max_active = 1 and NON_REENTRANT.
+	 */
+	dev_priv->wq = alloc_workqueue("i915",
+				       WQ_UNBOUND | WQ_NON_REENTRANT,
+				       1);
 	if (dev_priv->wq == NULL) {
 		DRM_ERROR("Failed to create our workqueue.\n");
 		ret = -ENOMEM;
@@ -2166,6 +1996,8 @@
 
 	/* Try to make sure MCHBAR is enabled before poking at it */
 	intel_setup_mchbar(dev);
+	intel_setup_gmbus(dev);
+	intel_opregion_setup(dev);
 
 	i915_gem_load(dev);
 
@@ -2212,8 +2044,7 @@
 	intel_detect_pch(dev);
 
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-		ret = i915_load_modeset_init(dev, prealloc_start,
-					     prealloc_size, agp_size);
+		ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
 		if (ret < 0) {
 			DRM_ERROR("failed to init modeset\n");
 			goto out_workqueue_free;
@@ -2221,7 +2052,8 @@
 	}
 
 	/* Must be done after probing outputs */
-	intel_opregion_init(dev, 0);
+	intel_opregion_init(dev);
+	acpi_video_register();
 
 	setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
 		    (unsigned long) dev);
@@ -2249,15 +2081,20 @@
 int i915_driver_unload(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	i915_destroy_error_state(dev);
+	int ret;
 
 	spin_lock(&mchdev_lock);
 	i915_mch_dev = NULL;
 	spin_unlock(&mchdev_lock);
 
-	destroy_workqueue(dev_priv->wq);
-	del_timer_sync(&dev_priv->hangcheck_timer);
+	mutex_lock(&dev->struct_mutex);
+	ret = i915_gpu_idle(dev);
+	if (ret)
+		DRM_ERROR("failed to idle hardware: %d\n", ret);
+	mutex_unlock(&dev->struct_mutex);
+
+	/* Cancel the retire work handler, which should be idle now. */
+	cancel_delayed_work_sync(&dev_priv->mm.retire_work);
 
 	io_mapping_free(dev_priv->mm.gtt_mapping);
 	if (dev_priv->mm.gtt_mtrr >= 0) {
@@ -2266,7 +2103,10 @@
 		dev_priv->mm.gtt_mtrr = -1;
 	}
 
+	acpi_video_unregister();
+
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		intel_fbdev_fini(dev);
 		intel_modeset_cleanup(dev);
 
 		/*
@@ -2278,20 +2118,28 @@
 			dev_priv->child_dev = NULL;
 			dev_priv->child_dev_num = 0;
 		}
-		drm_irq_uninstall(dev);
+
 		vga_switcheroo_unregister_client(dev->pdev);
 		vga_client_register(dev->pdev, NULL, NULL, NULL);
 	}
 
+	/* Free error state after interrupts are fully disabled. */
+	del_timer_sync(&dev_priv->hangcheck_timer);
+	cancel_work_sync(&dev_priv->error_work);
+	i915_destroy_error_state(dev);
+
 	if (dev->pdev->msi_enabled)
 		pci_disable_msi(dev->pdev);
 
 	if (dev_priv->regs != NULL)
 		iounmap(dev_priv->regs);
 
-	intel_opregion_free(dev, 0);
+	intel_opregion_fini(dev);
 
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		/* Flush any outstanding unpin_work. */
+		flush_workqueue(dev_priv->wq);
+
 		i915_gem_free_all_phys_object(dev);
 
 		mutex_lock(&dev->struct_mutex);
@@ -2299,34 +2147,35 @@
 		mutex_unlock(&dev->struct_mutex);
 		if (I915_HAS_FBC(dev) && i915_powersave)
 			i915_cleanup_compression(dev);
-		drm_mm_takedown(&dev_priv->vram);
-		i915_gem_lastclose(dev);
+		drm_mm_takedown(&dev_priv->mm.vram);
 
 		intel_cleanup_overlay(dev);
 	}
 
+	intel_teardown_gmbus(dev);
 	intel_teardown_mchbar(dev);
 
+	destroy_workqueue(dev_priv->wq);
+
 	pci_dev_put(dev_priv->bridge_dev);
 	kfree(dev->dev_private);
 
 	return 0;
 }
 
-int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv)
+int i915_driver_open(struct drm_device *dev, struct drm_file *file)
 {
-	struct drm_i915_file_private *i915_file_priv;
+	struct drm_i915_file_private *file_priv;
 
 	DRM_DEBUG_DRIVER("\n");
-	i915_file_priv = (struct drm_i915_file_private *)
-	    kmalloc(sizeof(*i915_file_priv), GFP_KERNEL);
-
-	if (!i915_file_priv)
+	file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
+	if (!file_priv)
 		return -ENOMEM;
 
-	file_priv->driver_priv = i915_file_priv;
+	file->driver_priv = file_priv;
 
-	INIT_LIST_HEAD(&i915_file_priv->mm.request_list);
+	spin_lock_init(&file_priv->mm.lock);
+	INIT_LIST_HEAD(&file_priv->mm.request_list);
 
 	return 0;
 }
@@ -2369,11 +2218,11 @@
 		i915_mem_release(dev, file_priv, dev_priv->agp_heap);
 }
 
-void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
+void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
 {
-	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
 
-	kfree(i915_file_priv);
+	kfree(file_priv);
 }
 
 struct drm_ioctl_desc i915_ioctls[] = {
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 9ed9d23..c3decb2 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -32,6 +32,7 @@
 #include "drm.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #include <linux/console.h>
 #include "drm_crtc_helper.h"
@@ -61,86 +62,108 @@
 	.driver_data = (unsigned long) info }
 
 static const struct intel_device_info intel_i830_info = {
-	.gen = 2, .is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1,
+	.gen = 2, .is_mobile = 1, .cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_845g_info = {
-	.gen = 2, .is_i8xx = 1,
+	.gen = 2,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i85x_info = {
-	.gen = 2, .is_i8xx = 1, .is_i85x = 1, .is_mobile = 1,
+	.gen = 2, .is_i85x = 1, .is_mobile = 1,
 	.cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i865g_info = {
-	.gen = 2, .is_i8xx = 1,
+	.gen = 2,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 
 static const struct intel_device_info intel_i915g_info = {
-	.gen = 3, .is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1,
+	.gen = 3, .is_i915g = 1, .cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i915gm_info = {
-	.gen = 3, .is_i9xx = 1,  .is_mobile = 1,
+	.gen = 3, .is_mobile = 1,
 	.cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
+	.supports_tv = 1,
 };
 static const struct intel_device_info intel_i945g_info = {
-	.gen = 3, .is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1,
+	.gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
 };
 static const struct intel_device_info intel_i945gm_info = {
-	.gen = 3, .is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1,
+	.gen = 3, .is_i945gm = 1, .is_mobile = 1,
 	.has_hotplug = 1, .cursor_needs_physical = 1,
+	.has_overlay = 1, .overlay_needs_physical = 1,
+	.supports_tv = 1,
 };
 
 static const struct intel_device_info intel_i965g_info = {
-	.gen = 4, .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1,
+	.gen = 4, .is_broadwater = 1,
 	.has_hotplug = 1,
+	.has_overlay = 1,
 };
 
 static const struct intel_device_info intel_i965gm_info = {
-	.gen = 4, .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1,
+	.gen = 4, .is_crestline = 1,
 	.is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+	.has_overlay = 1,
+	.supports_tv = 1,
 };
 
 static const struct intel_device_info intel_g33_info = {
-	.gen = 3, .is_g33 = 1, .is_i9xx = 1,
+	.gen = 3, .is_g33 = 1,
 	.need_gfx_hws = 1, .has_hotplug = 1,
+	.has_overlay = 1,
 };
 
 static const struct intel_device_info intel_g45_info = {
-	.gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1,
+	.gen = 4, .is_g4x = 1, .need_gfx_hws = 1,
 	.has_pipe_cxsr = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_gm45_info = {
-	.gen = 4, .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1,
+	.gen = 4, .is_g4x = 1,
 	.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
 	.has_pipe_cxsr = 1, .has_hotplug = 1,
+	.supports_tv = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_pineview_info = {
-	.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1,
+	.gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1,
 	.need_gfx_hws = 1, .has_hotplug = 1,
+	.has_overlay = 1,
 };
 
 static const struct intel_device_info intel_ironlake_d_info = {
-	.gen = 5, .is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1,
+	.gen = 5, .is_ironlake = 1,
 	.need_gfx_hws = 1, .has_pipe_cxsr = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
-	.gen = 5, .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
+	.gen = 5, .is_ironlake = 1, .is_mobile = 1,
 	.need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_d_info = {
-	.gen = 6, .is_i965g = 1, .is_i9xx = 1,
+	.gen = 6,
 	.need_gfx_hws = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
-	.gen = 6, .is_i965g = 1, .is_mobile = 1, .is_i9xx = 1,
+	.gen = 6, .is_mobile = 1,
 	.need_gfx_hws = 1, .has_hotplug = 1,
+	.has_bsd_ring = 1,
 };
 
 static const struct pci_device_id pciidlist[] = {		/* aka */
@@ -237,7 +260,7 @@
 
 	i915_save_state(dev);
 
-	intel_opregion_free(dev, 1);
+	intel_opregion_fini(dev);
 
 	/* Modeset on resume, not lid events */
 	dev_priv->modeset_on_lid = 0;
@@ -258,6 +281,8 @@
 	if (state.event == PM_EVENT_PRETHAW)
 		return 0;
 
+	drm_kms_helper_poll_disable(dev);
+
 	error = i915_drm_freeze(dev);
 	if (error)
 		return error;
@@ -277,8 +302,7 @@
 	int error = 0;
 
 	i915_restore_state(dev);
-
-	intel_opregion_init(dev, 1);
+	intel_opregion_setup(dev);
 
 	/* KMS EnterVT equivalent */
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
@@ -294,6 +318,8 @@
 		drm_helper_resume_force_mode(dev);
 	}
 
+	intel_opregion_init(dev);
+
 	dev_priv->modeset_on_lid = 0;
 
 	return error;
@@ -301,12 +327,79 @@
 
 int i915_resume(struct drm_device *dev)
 {
+	int ret;
+
 	if (pci_enable_device(dev->pdev))
 		return -EIO;
 
 	pci_set_master(dev->pdev);
 
-	return i915_drm_thaw(dev);
+	ret = i915_drm_thaw(dev);
+	if (ret)
+		return ret;
+
+	drm_kms_helper_poll_enable(dev);
+	return 0;
+}
+
+static int i8xx_do_reset(struct drm_device *dev, u8 flags)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (IS_I85X(dev))
+		return -ENODEV;
+
+	I915_WRITE(D_STATE, I915_READ(D_STATE) | DSTATE_GFX_RESET_I830);
+	POSTING_READ(D_STATE);
+
+	if (IS_I830(dev) || IS_845G(dev)) {
+		I915_WRITE(DEBUG_RESET_I830,
+			   DEBUG_RESET_DISPLAY |
+			   DEBUG_RESET_RENDER |
+			   DEBUG_RESET_FULL);
+		POSTING_READ(DEBUG_RESET_I830);
+		msleep(1);
+
+		I915_WRITE(DEBUG_RESET_I830, 0);
+		POSTING_READ(DEBUG_RESET_I830);
+	}
+
+	msleep(1);
+
+	I915_WRITE(D_STATE, I915_READ(D_STATE) & ~DSTATE_GFX_RESET_I830);
+	POSTING_READ(D_STATE);
+
+	return 0;
+}
+
+static int i965_reset_complete(struct drm_device *dev)
+{
+	u8 gdrst;
+	pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+	return gdrst & 0x1;
+}
+
+static int i965_do_reset(struct drm_device *dev, u8 flags)
+{
+	u8 gdrst;
+
+	/*
+	 * Set the domains we want to reset (GRDOM/bits 2 and 3) as
+	 * well as the reset bit (GR/bit 0).  Setting the GR bit
+	 * triggers the reset; when done, the hardware will clear it.
+	 */
+	pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+	pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1);
+
+	return wait_for(i965_reset_complete(dev), 500);
+}
+
+static int ironlake_do_reset(struct drm_device *dev, u8 flags)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+	I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1);
+	return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
 }
 
 /**
@@ -325,54 +418,39 @@
  *   - re-init interrupt state
  *   - re-init display
  */
-int i965_reset(struct drm_device *dev, u8 flags)
+int i915_reset(struct drm_device *dev, u8 flags)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	unsigned long timeout;
-	u8 gdrst;
 	/*
 	 * We really should only reset the display subsystem if we actually
 	 * need to
 	 */
 	bool need_display = true;
+	int ret;
 
 	mutex_lock(&dev->struct_mutex);
 
-	/*
-	 * Clear request list
-	 */
-	i915_gem_retire_requests(dev);
+	i915_gem_reset(dev);
 
-	if (need_display)
-		i915_save_display(dev);
-
-	if (IS_I965G(dev) || IS_G4X(dev)) {
-		/*
-		 * Set the domains we want to reset, then the reset bit (bit 0).
-		 * Clear the reset bit after a while and wait for hardware status
-		 * bit (bit 1) to be set
-		 */
-		pci_read_config_byte(dev->pdev, GDRST, &gdrst);
-		pci_write_config_byte(dev->pdev, GDRST, gdrst | flags | ((flags == GDRST_FULL) ? 0x1 : 0x0));
-		udelay(50);
-		pci_write_config_byte(dev->pdev, GDRST, gdrst & 0xfe);
-
-		/* ...we don't want to loop forever though, 500ms should be plenty */
-	       timeout = jiffies + msecs_to_jiffies(500);
-		do {
-			udelay(100);
-			pci_read_config_byte(dev->pdev, GDRST, &gdrst);
-		} while ((gdrst & 0x1) && time_after(timeout, jiffies));
-
-		if (gdrst & 0x1) {
-			WARN(true, "i915: Failed to reset chip\n");
-			mutex_unlock(&dev->struct_mutex);
-			return -EIO;
-		}
-	} else {
-		DRM_ERROR("Error occurred. Don't know how to reset this chip.\n");
+	ret = -ENODEV;
+	if (get_seconds() - dev_priv->last_gpu_reset < 5) {
+		DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
+	} else switch (INTEL_INFO(dev)->gen) {
+	case 5:
+		ret = ironlake_do_reset(dev, flags);
+		break;
+	case 4:
+		ret = i965_do_reset(dev, flags);
+		break;
+	case 2:
+		ret = i8xx_do_reset(dev, flags);
+		break;
+	}
+	dev_priv->last_gpu_reset = get_seconds();
+	if (ret) {
+		DRM_ERROR("Failed to reset chip.\n");
 		mutex_unlock(&dev->struct_mutex);
-		return -ENODEV;
+		return ret;
 	}
 
 	/* Ok, now get things going again... */
@@ -400,13 +478,19 @@
 		mutex_lock(&dev->struct_mutex);
 	}
 
-	/*
-	 * Display needs restore too...
-	 */
-	if (need_display)
-		i915_restore_display(dev);
-
 	mutex_unlock(&dev->struct_mutex);
+
+	/*
+	 * Perform a full modeset as on later generations, e.g. Ironlake, we may
+	 * need to retrain the display link and cannot just restore the register
+	 * values.
+	 */
+	if (need_display) {
+		mutex_lock(&dev->mode_config.mutex);
+		drm_helper_resume_force_mode(dev);
+		mutex_unlock(&dev->mode_config.mutex);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index af4a263..73ad8bf 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -34,6 +34,8 @@
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
 #include <linux/io-mapping.h>
+#include <linux/i2c.h>
+#include <drm/intel-gtt.h>
 
 /* General customization:
  */
@@ -73,11 +75,9 @@
 #define DRIVER_PATCHLEVEL	0
 
 #define WATCH_COHERENCY	0
-#define WATCH_BUF	0
 #define WATCH_EXEC	0
-#define WATCH_LRU	0
 #define WATCH_RELOC	0
-#define WATCH_INACTIVE	0
+#define WATCH_LISTS	0
 #define WATCH_PWRITE	0
 
 #define I915_GEM_PHYS_CURSOR_0 1
@@ -110,8 +110,9 @@
 	struct opregion_acpi *acpi;
 	struct opregion_swsci *swsci;
 	struct opregion_asle *asle;
-	int enabled;
+	void *vbt;
 };
+#define OPREGION_SIZE            (8*1024)
 
 struct intel_overlay;
 struct intel_overlay_error_state;
@@ -125,13 +126,16 @@
 struct drm_i915_fence_reg {
 	struct drm_gem_object *obj;
 	struct list_head lru_list;
+	bool gpu;
 };
 
 struct sdvo_device_mapping {
+	u8 initialized;
 	u8 dvo_port;
 	u8 slave_addr;
 	u8 dvo_wiring;
-	u8 initialized;
+	u8 i2c_pin;
+	u8 i2c_speed;
 	u8 ddc_pin;
 };
 
@@ -193,13 +197,9 @@
 struct intel_device_info {
 	u8 gen;
 	u8 is_mobile : 1;
-	u8 is_i8xx : 1;
 	u8 is_i85x : 1;
 	u8 is_i915g : 1;
-	u8 is_i9xx : 1;
 	u8 is_i945gm : 1;
-	u8 is_i965g : 1;
-	u8 is_i965gm : 1;
 	u8 is_g33 : 1;
 	u8 need_gfx_hws : 1;
 	u8 is_g4x : 1;
@@ -212,9 +212,14 @@
 	u8 has_pipe_cxsr : 1;
 	u8 has_hotplug : 1;
 	u8 cursor_needs_physical : 1;
+	u8 has_overlay : 1;
+	u8 overlay_needs_physical : 1;
+	u8 supports_tv : 1;
+	u8 has_bsd_ring : 1;
 };
 
 enum no_fbc_reason {
+	FBC_NO_OUTPUT, /* no outputs enabled to compress */
 	FBC_STOLEN_TOO_SMALL, /* not enough space to hold compressed buffers */
 	FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */
 	FBC_MODE_TOO_LARGE, /* mode too large for compression */
@@ -241,6 +246,12 @@
 
 	void __iomem *regs;
 
+	struct intel_gmbus {
+		struct i2c_adapter adapter;
+		struct i2c_adapter *force_bit;
+		u32 reg0;
+	} *gmbus;
+
 	struct pci_dev *bridge_dev;
 	struct intel_ring_buffer render_ring;
 	struct intel_ring_buffer bsd_ring;
@@ -263,6 +274,9 @@
 	int front_offset;
 	int current_page;
 	int page_flipping;
+#define I915_DEBUG_READ (1<<0)
+#define I915_DEBUG_WRITE (1<<1)
+	unsigned long debug_flags;
 
 	wait_queue_head_t irq_queue;
 	atomic_t irq_received;
@@ -289,24 +303,21 @@
 	unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
 	int vblank_pipe;
 	int num_pipe;
-	u32 flush_rings;
-#define FLUSH_RENDER_RING	0x1
-#define FLUSH_BSD_RING		0x2
 
 	/* For hangcheck timer */
-#define DRM_I915_HANGCHECK_PERIOD 75 /* in jiffies */
+#define DRM_I915_HANGCHECK_PERIOD 250 /* in ms */
 	struct timer_list hangcheck_timer;
 	int hangcheck_count;
 	uint32_t last_acthd;
 	uint32_t last_instdone;
 	uint32_t last_instdone1;
 
-	struct drm_mm vram;
-
 	unsigned long cfb_size;
 	unsigned long cfb_pitch;
+	unsigned long cfb_offset;
 	int cfb_fence;
 	int cfb_plane;
+	int cfb_y;
 
 	int irq_enabled;
 
@@ -316,8 +327,7 @@
 	struct intel_overlay *overlay;
 
 	/* LVDS info */
-	int backlight_duty_cycle;  /* restore backlight to this value */
-	bool panel_wants_dither;
+	int backlight_level;  /* restore backlight to this value */
 	struct drm_display_mode *panel_fixed_mode;
 	struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
 	struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
@@ -328,13 +338,22 @@
 	unsigned int lvds_vbt:1;
 	unsigned int int_crt_support:1;
 	unsigned int lvds_use_ssc:1;
-	unsigned int edp_support:1;
 	int lvds_ssc_freq;
-	int edp_bpp;
+
+	struct {
+		u8 rate:4;
+		u8 lanes:4;
+		u8 preemphasis:4;
+		u8 vswing:4;
+
+		u8 initialized:1;
+		u8 support:1;
+		u8 bpp:6;
+	} edp;
 
 	struct notifier_block lid_notifier;
 
-	int crt_ddc_bus; /* 0 = unknown, else GPIO to use for CRT DDC */
+	int crt_ddc_pin;
 	struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
 	int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
 	int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -344,6 +363,7 @@
 	spinlock_t error_lock;
 	struct drm_i915_error_state *first_error;
 	struct work_struct error_work;
+	struct completion error_completion;
 	struct workqueue_struct *wq;
 
 	/* Display functions */
@@ -507,6 +527,11 @@
 	u32 saveMCHBAR_RENDER_STANDBY;
 
 	struct {
+		/** Bridge to intel-gtt-ko */
+		struct intel_gtt *gtt;
+		/** Memory allocator for GTT stolen memory */
+		struct drm_mm vram;
+		/** Memory allocator for GTT */
 		struct drm_mm gtt_space;
 
 		struct io_mapping *gtt_mapping;
@@ -521,8 +546,6 @@
 		 */
 		struct list_head shrink_list;
 
-		spinlock_t active_list_lock;
-
 		/**
 		 * List of objects which are not in the ringbuffer but which
 		 * still have a write_domain which needs to be flushed before
@@ -555,6 +578,12 @@
 		 */
 		struct list_head inactive_list;
 
+		/**
+		 * LRU list of objects which are not in the ringbuffer but
+		 * are still pinned in the GTT.
+		 */
+		struct list_head pinned_list;
+
 		/** LRU list of objects with fence regs on them. */
 		struct list_head fence_list;
 
@@ -611,6 +640,17 @@
 
 		/* storage for physical objects */
 		struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
+
+		uint32_t flush_rings;
+
+		/* accounting, useful for userland debugging */
+		size_t object_memory;
+		size_t pin_memory;
+		size_t gtt_memory;
+		size_t gtt_total;
+		u32 object_count;
+		u32 pin_count;
+		u32 gtt_count;
 	} mm;
 	struct sdvo_device_mapping sdvo_mappings[2];
 	/* indicate whether the LVDS_BORDER should be enabled or not */
@@ -626,8 +666,6 @@
 	/* Reclocking support */
 	bool render_reclock_avail;
 	bool lvds_downclock_avail;
-	/* indicate whether the LVDS EDID is OK */
-	bool lvds_edid_good;
 	/* indicates the reduced downclock for LVDS*/
 	int lvds_downclock;
 	struct work_struct idle_work;
@@ -661,6 +699,8 @@
 	struct drm_mm_node *compressed_fb;
 	struct drm_mm_node *compressed_llb;
 
+	unsigned long last_gpu_reset;
+
 	/* list of fbdev register on this device */
 	struct intel_fbdev *fbdev;
 } drm_i915_private_t;
@@ -816,12 +856,14 @@
 	/** global list entry for this request */
 	struct list_head list;
 
+	struct drm_i915_file_private *file_priv;
 	/** file_priv list entry for this request */
 	struct list_head client_list;
 };
 
 struct drm_i915_file_private {
 	struct {
+		struct spinlock lock;
 		struct list_head request_list;
 	} mm;
 };
@@ -862,7 +904,7 @@
 extern int i915_emit_box(struct drm_device *dev,
 			 struct drm_clip_rect *boxes,
 			 int i, int DR1, int DR4);
-extern int i965_reset(struct drm_device *dev, u8 flags);
+extern int i915_reset(struct drm_device *dev, u8 flags);
 extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
@@ -871,7 +913,6 @@
 
 /* i915_irq.c */
 void i915_hangcheck_elapsed(unsigned long data);
-void i915_destroy_error_state(struct drm_device *dev);
 extern int i915_irq_emit(struct drm_device *dev, void *data,
 			 struct drm_file *file_priv);
 extern int i915_irq_wait(struct drm_device *dev, void *data,
@@ -908,6 +949,12 @@
 
 void intel_enable_asle (struct drm_device *dev);
 
+#ifdef CONFIG_DEBUG_FS
+extern void i915_destroy_error_state(struct drm_device *dev);
+#else
+#define i915_destroy_error_state(x)
+#endif
+
 
 /* i915_mem.c */
 extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -922,6 +969,7 @@
 extern void i915_mem_release(struct drm_device * dev,
 			     struct drm_file *file_priv, struct mem_block *heap);
 /* i915_gem.c */
+int i915_gem_check_is_wedged(struct drm_device *dev);
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file_priv);
 int i915_gem_create_ioctl(struct drm_device *dev, void *data,
@@ -972,13 +1020,22 @@
 int i915_gem_object_unbind(struct drm_gem_object *obj);
 void i915_gem_release_mmap(struct drm_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
-uint32_t i915_get_gem_seqno(struct drm_device *dev,
-		struct intel_ring_buffer *ring);
-bool i915_seqno_passed(uint32_t seq1, uint32_t seq2);
-int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
-int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
+
+/**
+ * Returns true if seq1 is later than seq2.
+ */
+static inline bool
+i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+{
+	return (int32_t)(seq1 - seq2) >= 0;
+}
+
+int i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+				  bool interruptible);
+int i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+				  bool interruptible);
 void i915_gem_retire_requests(struct drm_device *dev);
-void i915_gem_retire_work_handler(struct work_struct *work);
+void i915_gem_reset(struct drm_device *dev);
 void i915_gem_clflush_object(struct drm_gem_object *obj);
 int i915_gem_object_set_domain(struct drm_gem_object *obj,
 			       uint32_t read_domains,
@@ -990,16 +1047,18 @@
 int i915_gpu_idle(struct drm_device *dev);
 int i915_gem_idle(struct drm_device *dev);
 uint32_t i915_add_request(struct drm_device *dev,
-		struct drm_file *file_priv,
-		uint32_t flush_domains,
-		struct intel_ring_buffer *ring);
+			  struct drm_file *file_priv,
+			  struct drm_i915_gem_request *request,
+			  struct intel_ring_buffer *ring);
 int i915_do_wait_request(struct drm_device *dev,
-		uint32_t seqno, int interruptible,
-		struct intel_ring_buffer *ring);
+			 uint32_t seqno,
+			 bool interruptible,
+			 struct intel_ring_buffer *ring);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
 				      int write);
-int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
+int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+					 bool pipelined);
 int i915_gem_attach_phys_object(struct drm_device *dev,
 				struct drm_gem_object *obj,
 				int id,
@@ -1007,10 +1066,7 @@
 void i915_gem_detach_phys_object(struct drm_device *dev,
 				 struct drm_gem_object *obj);
 void i915_gem_free_all_phys_object(struct drm_device *dev);
-int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
-void i915_gem_object_put_pages(struct drm_gem_object *obj);
 void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv);
-int i915_gem_object_flush_write_domain(struct drm_gem_object *obj);
 
 void i915_gem_shrinker_init(void);
 void i915_gem_shrinker_exit(void);
@@ -1032,15 +1088,14 @@
 /* i915_gem_debug.c */
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
 			  const char *where, uint32_t mark);
-#if WATCH_INACTIVE
-void i915_verify_inactive(struct drm_device *dev, char *file, int line);
+#if WATCH_LISTS
+int i915_verify_lists(struct drm_device *dev);
 #else
-#define i915_verify_inactive(dev, file, line)
+#define i915_verify_lists(dev) 0
 #endif
 void i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle);
 void i915_gem_dump_object(struct drm_gem_object *obj, int len,
 			  const char *where, uint32_t mark);
-void i915_dump_lru(struct drm_device *dev, const char *where);
 
 /* i915_debugfs.c */
 int i915_debugfs_init(struct drm_minor *minor);
@@ -1054,19 +1109,31 @@
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
 
+/* intel_i2c.c */
+extern int intel_setup_gmbus(struct drm_device *dev);
+extern void intel_teardown_gmbus(struct drm_device *dev);
+extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
+extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
+extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
+{
+	return container_of(adapter, struct intel_gmbus, adapter)->force_bit;
+}
+extern void intel_i2c_reset(struct drm_device *dev);
+
+/* intel_opregion.c */
+extern int intel_opregion_setup(struct drm_device *dev);
 #ifdef CONFIG_ACPI
-/* i915_opregion.c */
-extern int intel_opregion_init(struct drm_device *dev, int resume);
-extern void intel_opregion_free(struct drm_device *dev, int suspend);
-extern void opregion_asle_intr(struct drm_device *dev);
-extern void ironlake_opregion_gse_intr(struct drm_device *dev);
-extern void opregion_enable_asle(struct drm_device *dev);
+extern void intel_opregion_init(struct drm_device *dev);
+extern void intel_opregion_fini(struct drm_device *dev);
+extern void intel_opregion_asle_intr(struct drm_device *dev);
+extern void intel_opregion_gse_intr(struct drm_device *dev);
+extern void intel_opregion_enable_asle(struct drm_device *dev);
 #else
-static inline int intel_opregion_init(struct drm_device *dev, int resume) { return 0; }
-static inline void intel_opregion_free(struct drm_device *dev, int suspend) { return; }
-static inline void opregion_asle_intr(struct drm_device *dev) { return; }
-static inline void ironlake_opregion_gse_intr(struct drm_device *dev) { return; }
-static inline void opregion_enable_asle(struct drm_device *dev) { return; }
+static inline void intel_opregion_init(struct drm_device *dev) { return; }
+static inline void intel_opregion_fini(struct drm_device *dev) { return; }
+static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
+static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
 #endif
 
 /* modesetting */
@@ -1084,8 +1151,10 @@
 extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
 
 /* overlay */
+#ifdef CONFIG_DEBUG_FS
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
 extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+#endif
 
 /**
  * Lock test for when it's just for synchronization of ring access.
@@ -1099,8 +1168,26 @@
 		LOCK_TEST_WITH_RETURN(dev, file_priv);			\
 } while (0)
 
-#define I915_READ(reg)          readl(dev_priv->regs + (reg))
-#define I915_WRITE(reg, val)     writel(val, dev_priv->regs + (reg))
+static inline u32 i915_read(struct drm_i915_private *dev_priv, u32 reg)
+{
+	u32 val;
+
+	val = readl(dev_priv->regs + reg);
+	if (dev_priv->debug_flags & I915_DEBUG_READ)
+		printk(KERN_ERR "read 0x%08x from 0x%08x\n", val, reg);
+	return val;
+}
+
+static inline void i915_write(struct drm_i915_private *dev_priv, u32 reg,
+			      u32 val)
+{
+	writel(val, dev_priv->regs + reg);
+	if (dev_priv->debug_flags & I915_DEBUG_WRITE)
+		printk(KERN_ERR "wrote 0x%08x to 0x%08x\n", val, reg);
+}
+
+#define I915_READ(reg)          i915_read(dev_priv, (reg))
+#define I915_WRITE(reg, val)    i915_write(dev_priv, (reg), (val))
 #define I915_READ16(reg)	readw(dev_priv->regs + (reg))
 #define I915_WRITE16(reg, val)	writel(val, dev_priv->regs + (reg))
 #define I915_READ8(reg)		readb(dev_priv->regs + (reg))
@@ -1110,6 +1197,11 @@
 #define POSTING_READ(reg)	(void)I915_READ(reg)
 #define POSTING_READ16(reg)	(void)I915_READ16(reg)
 
+#define I915_DEBUG_ENABLE_IO() (dev_priv->debug_flags |= I915_DEBUG_READ | \
+				I915_DEBUG_WRITE)
+#define I915_DEBUG_DISABLE_IO() (dev_priv->debug_flags &= ~(I915_DEBUG_READ | \
+							    I915_DEBUG_WRITE))
+
 #define I915_VERBOSE 0
 
 #define BEGIN_LP_RING(n)  do { \
@@ -1166,8 +1258,6 @@
 #define IS_I915GM(dev)		((dev)->pci_device == 0x2592)
 #define IS_I945G(dev)		((dev)->pci_device == 0x2772)
 #define IS_I945GM(dev)		(INTEL_INFO(dev)->is_i945gm)
-#define IS_I965G(dev)		(INTEL_INFO(dev)->is_i965g)
-#define IS_I965GM(dev)		(INTEL_INFO(dev)->is_i965gm)
 #define IS_BROADWATER(dev)	(INTEL_INFO(dev)->is_broadwater)
 #define IS_CRESTLINE(dev)	(INTEL_INFO(dev)->is_crestline)
 #define IS_GM45(dev)		((dev)->pci_device == 0x2A42)
@@ -1179,7 +1269,6 @@
 #define IS_IRONLAKE_D(dev)	((dev)->pci_device == 0x0042)
 #define IS_IRONLAKE_M(dev)	((dev)->pci_device == 0x0046)
 #define IS_IRONLAKE(dev)	(INTEL_INFO(dev)->is_ironlake)
-#define IS_I9XX(dev)		(INTEL_INFO(dev)->is_i9xx)
 #define IS_MOBILE(dev)		(INTEL_INFO(dev)->is_mobile)
 
 #define IS_GEN2(dev)	(INTEL_INFO(dev)->gen == 2)
@@ -1188,26 +1277,27 @@
 #define IS_GEN5(dev)	(INTEL_INFO(dev)->gen == 5)
 #define IS_GEN6(dev)	(INTEL_INFO(dev)->gen == 6)
 
-#define HAS_BSD(dev)            (IS_IRONLAKE(dev) || IS_G4X(dev))
+#define HAS_BSD(dev)            (INTEL_INFO(dev)->has_bsd_ring)
 #define I915_NEED_GFX_HWS(dev)	(INTEL_INFO(dev)->need_gfx_hws)
 
+#define HAS_OVERLAY(dev) 		(INTEL_INFO(dev)->has_overlay)
+#define OVERLAY_NEEDS_PHYSICAL(dev)	(INTEL_INFO(dev)->overlay_needs_physical)
+
 /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
  * rows, which changed the alignment requirements and fence programming.
  */
-#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
+#define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \
 						      IS_I915GM(dev)))
-#define SUPPORTS_DIGITAL_OUTPUTS(dev)	(IS_I9XX(dev) && !IS_PINEVIEW(dev))
+#define SUPPORTS_DIGITAL_OUTPUTS(dev)	(!IS_GEN2(dev) && !IS_PINEVIEW(dev))
 #define SUPPORTS_INTEGRATED_HDMI(dev)	(IS_G4X(dev) || IS_IRONLAKE(dev))
 #define SUPPORTS_INTEGRATED_DP(dev)	(IS_G4X(dev) || IS_IRONLAKE(dev))
 #define SUPPORTS_EDP(dev)		(IS_IRONLAKE_M(dev))
-#define SUPPORTS_TV(dev)		(IS_I9XX(dev) && IS_MOBILE(dev) && \
-					!IS_IRONLAKE(dev) && !IS_PINEVIEW(dev) && \
-					!IS_GEN6(dev))
+#define SUPPORTS_TV(dev)		(INTEL_INFO(dev)->supports_tv)
 #define I915_HAS_HOTPLUG(dev)		 (INTEL_INFO(dev)->has_hotplug)
 /* dsparb controlled by hw only */
 #define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IRONLAKE(dev))
 
-#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IRONLAKE(dev))
+#define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
 #define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 #define I915_HAS_RC6(dev) (INTEL_INFO(dev)->has_rc6)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index cf4ffbe..29e97c0 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -37,7 +37,9 @@
 #include <linux/intel-gtt.h>
 
 static uint32_t i915_gem_get_gtt_alignment(struct drm_gem_object *obj);
-static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
+
+static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
+						  bool pipelined);
 static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
 static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
 static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj,
@@ -46,7 +48,8 @@
 						     uint64_t offset,
 						     uint64_t size);
 static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj);
-static int i915_gem_object_wait_rendering(struct drm_gem_object *obj);
+static int i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+					  bool interruptible);
 static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
 					   unsigned alignment);
 static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
@@ -55,9 +58,111 @@
 				struct drm_file *file_priv);
 static void i915_gem_free_object_tail(struct drm_gem_object *obj);
 
+static int
+i915_gem_object_get_pages(struct drm_gem_object *obj,
+			  gfp_t gfpmask);
+
+static void
+i915_gem_object_put_pages(struct drm_gem_object *obj);
+
 static LIST_HEAD(shrink_list);
 static DEFINE_SPINLOCK(shrink_list_lock);
 
+/* some bookkeeping */
+static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
+				  size_t size)
+{
+	dev_priv->mm.object_count++;
+	dev_priv->mm.object_memory += size;
+}
+
+static void i915_gem_info_remove_obj(struct drm_i915_private *dev_priv,
+				     size_t size)
+{
+	dev_priv->mm.object_count--;
+	dev_priv->mm.object_memory -= size;
+}
+
+static void i915_gem_info_add_gtt(struct drm_i915_private *dev_priv,
+				  size_t size)
+{
+	dev_priv->mm.gtt_count++;
+	dev_priv->mm.gtt_memory += size;
+}
+
+static void i915_gem_info_remove_gtt(struct drm_i915_private *dev_priv,
+				     size_t size)
+{
+	dev_priv->mm.gtt_count--;
+	dev_priv->mm.gtt_memory -= size;
+}
+
+static void i915_gem_info_add_pin(struct drm_i915_private *dev_priv,
+				  size_t size)
+{
+	dev_priv->mm.pin_count++;
+	dev_priv->mm.pin_memory += size;
+}
+
+static void i915_gem_info_remove_pin(struct drm_i915_private *dev_priv,
+				     size_t size)
+{
+	dev_priv->mm.pin_count--;
+	dev_priv->mm.pin_memory -= size;
+}
+
+int
+i915_gem_check_is_wedged(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct completion *x = &dev_priv->error_completion;
+	unsigned long flags;
+	int ret;
+
+	if (!atomic_read(&dev_priv->mm.wedged))
+		return 0;
+
+	ret = wait_for_completion_interruptible(x);
+	if (ret)
+		return ret;
+
+	/* Success, we reset the GPU! */
+	if (!atomic_read(&dev_priv->mm.wedged))
+		return 0;
+
+	/* GPU is hung, bump the completion count to account for
+	 * the token we just consumed so that we never hit zero and
+	 * end up waiting upon a subsequent completion event that
+	 * will never happen.
+	 */
+	spin_lock_irqsave(&x->wait.lock, flags);
+	x->done++;
+	spin_unlock_irqrestore(&x->wait.lock, flags);
+	return -EIO;
+}
+
+static int i915_mutex_lock_interruptible(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	ret = i915_gem_check_is_wedged(dev);
+	if (ret)
+		return ret;
+
+	ret = mutex_lock_interruptible(&dev->struct_mutex);
+	if (ret)
+		return ret;
+
+	if (atomic_read(&dev_priv->mm.wedged)) {
+		mutex_unlock(&dev->struct_mutex);
+		return -EAGAIN;
+	}
+
+	WARN_ON(i915_verify_lists(dev));
+	return 0;
+}
+
 static inline bool
 i915_gem_object_is_inactive(struct drm_i915_gem_object *obj_priv)
 {
@@ -66,7 +171,8 @@
 		obj_priv->pin_count == 0;
 }
 
-int i915_gem_do_init(struct drm_device *dev, unsigned long start,
+int i915_gem_do_init(struct drm_device *dev,
+		     unsigned long start,
 		     unsigned long end)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -80,7 +186,7 @@
 	drm_mm_init(&dev_priv->mm.gtt_space, start,
 		    end - start);
 
-	dev->gtt_total = (uint32_t) (end - start);
+	dev_priv->mm.gtt_total = end - start;
 
 	return 0;
 }
@@ -103,14 +209,16 @@
 i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 			    struct drm_file *file_priv)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_get_aperture *args = data;
 
 	if (!(dev->driver->driver_features & DRIVER_GEM))
 		return -ENODEV;
 
-	args->aper_size = dev->gtt_total;
-	args->aper_available_size = (args->aper_size -
-				     atomic_read(&dev->pin_memory));
+	mutex_lock(&dev->struct_mutex);
+	args->aper_size = dev_priv->mm.gtt_total;
+	args->aper_available_size = args->aper_size - dev_priv->mm.pin_memory;
+	mutex_unlock(&dev->struct_mutex);
 
 	return 0;
 }
@@ -265,7 +373,9 @@
 	user_data = (char __user *) (uintptr_t) args->data_ptr;
 	remain = args->size;
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
 
 	ret = i915_gem_object_get_pages(obj, 0);
 	if (ret != 0)
@@ -384,7 +494,9 @@
 
 	do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		goto fail_put_user_pages;
 
 	ret = i915_gem_object_get_pages_or_evict(obj);
 	if (ret)
@@ -464,21 +576,27 @@
 	struct drm_i915_gem_pread *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
-	int ret;
+	int ret = 0;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
 		return -ENOENT;
 	obj_priv = to_intel_bo(obj);
 
-	/* Bounds check source.
-	 *
-	 * XXX: This could use review for overflow issues...
-	 */
-	if (args->offset > obj->size || args->size > obj->size ||
-	    args->offset + args->size > obj->size) {
-		drm_gem_object_unreference_unlocked(obj);
-		return -EINVAL;
+	/* Bounds check source.  */
+	if (args->offset > obj->size || args->size > obj->size - args->offset) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (args->size == 0)
+		goto out;
+
+	if (!access_ok(VERIFY_WRITE,
+		       (char __user *)(uintptr_t)args->data_ptr,
+		       args->size)) {
+		ret = -EFAULT;
+		goto out;
 	}
 
 	if (i915_gem_object_needs_bit17_swizzle(obj)) {
@@ -490,8 +608,8 @@
 							file_priv);
 	}
 
+out:
 	drm_gem_object_unreference_unlocked(obj);
-
 	return ret;
 }
 
@@ -580,11 +698,11 @@
 
 	user_data = (char __user *) (uintptr_t) args->data_ptr;
 	remain = args->size;
-	if (!access_ok(VERIFY_READ, user_data, remain))
-		return -EFAULT;
 
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
 
-	mutex_lock(&dev->struct_mutex);
 	ret = i915_gem_object_pin(obj, 0);
 	if (ret) {
 		mutex_unlock(&dev->struct_mutex);
@@ -679,7 +797,10 @@
 		goto out_unpin_pages;
 	}
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		goto out_unpin_pages;
+
 	ret = i915_gem_object_pin(obj, 0);
 	if (ret)
 		goto out_unlock;
@@ -753,7 +874,9 @@
 	user_data = (char __user *) (uintptr_t) args->data_ptr;
 	remain = args->size;
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		return ret;
 
 	ret = i915_gem_object_get_pages(obj, 0);
 	if (ret != 0)
@@ -849,7 +972,9 @@
 
 	do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
+		goto fail_put_user_pages;
 
 	ret = i915_gem_object_get_pages_or_evict(obj);
 	if (ret)
@@ -934,14 +1059,20 @@
 		return -ENOENT;
 	obj_priv = to_intel_bo(obj);
 
-	/* Bounds check destination.
-	 *
-	 * XXX: This could use review for overflow issues...
-	 */
-	if (args->offset > obj->size || args->size > obj->size ||
-	    args->offset + args->size > obj->size) {
-		drm_gem_object_unreference_unlocked(obj);
-		return -EINVAL;
+	/* Bounds check destination. */
+	if (args->offset > obj->size || args->size > obj->size - args->offset) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (args->size == 0)
+		goto out;
+
+	if (!access_ok(VERIFY_READ,
+		       (char __user *)(uintptr_t)args->data_ptr,
+		       args->size)) {
+		ret = -EFAULT;
+		goto out;
 	}
 
 	/* We can only do the GTT pwrite on untiled buffers, as otherwise
@@ -953,7 +1084,7 @@
 	if (obj_priv->phys_obj)
 		ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
 	else if (obj_priv->tiling_mode == I915_TILING_NONE &&
-		 dev->gtt_total != 0 &&
+		 obj_priv->gtt_space &&
 		 obj->write_domain != I915_GEM_DOMAIN_CPU) {
 		ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv);
 		if (ret == -EFAULT) {
@@ -975,8 +1106,8 @@
 		DRM_INFO("pwrite failed %d\n", ret);
 #endif
 
+out:
 	drm_gem_object_unreference_unlocked(obj);
-
 	return ret;
 }
 
@@ -1017,14 +1148,14 @@
 		return -ENOENT;
 	obj_priv = to_intel_bo(obj);
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
+	}
 
 	intel_mark_busy(dev, obj);
 
-#if WATCH_BUF
-	DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
-		 obj, obj->size, read_domains, write_domain);
-#endif
 	if (read_domains & I915_GEM_DOMAIN_GTT) {
 		ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
 
@@ -1048,7 +1179,6 @@
 		ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
 	}
 
-	
 	/* Maintain LRU order of "inactive" objects */
 	if (ret == 0 && i915_gem_object_is_inactive(obj_priv))
 		list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
@@ -1067,27 +1197,23 @@
 {
 	struct drm_i915_gem_sw_finish *args = data;
 	struct drm_gem_object *obj;
-	struct drm_i915_gem_object *obj_priv;
 	int ret = 0;
 
 	if (!(dev->driver->driver_features & DRIVER_GEM))
 		return -ENODEV;
 
-	mutex_lock(&dev->struct_mutex);
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
-	if (obj == NULL) {
-		mutex_unlock(&dev->struct_mutex);
+	if (obj == NULL)
 		return -ENOENT;
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
 	}
 
-#if WATCH_BUF
-	DRM_INFO("%s: sw_finish %d (%p %zd)\n",
-		 __func__, args->handle, obj, obj->size);
-#endif
-	obj_priv = to_intel_bo(obj);
-
 	/* Pinned buffers may be scanout, so flush the cache */
-	if (obj_priv->pin_count)
+	if (to_intel_bo(obj)->pin_count)
 		i915_gem_object_flush_cpu_write_domain(obj);
 
 	drm_gem_object_unreference(obj);
@@ -1179,7 +1305,7 @@
 
 	/* Need a new fence register? */
 	if (obj_priv->tiling_mode != I915_TILING_NONE) {
-		ret = i915_gem_object_get_fence_reg(obj);
+		ret = i915_gem_object_get_fence_reg(obj, true);
 		if (ret)
 			goto unlock;
 	}
@@ -1244,7 +1370,7 @@
 						    obj->size / PAGE_SIZE, 0, 0);
 	if (!list->file_offset_node) {
 		DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
-		ret = -ENOMEM;
+		ret = -ENOSPC;
 		goto out_free_list;
 	}
 
@@ -1256,9 +1382,9 @@
 	}
 
 	list->hash.key = list->file_offset_node->start;
-	if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
+	ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
+	if (ret) {
 		DRM_ERROR("failed to add to map hash\n");
-		ret = -ENOMEM;
 		goto out_free_mm;
 	}
 
@@ -1343,14 +1469,14 @@
 	 * Minimum alignment is 4k (GTT page size), but might be greater
 	 * if a fence register is needed for the object.
 	 */
-	if (IS_I965G(dev) || obj_priv->tiling_mode == I915_TILING_NONE)
+	if (INTEL_INFO(dev)->gen >= 4 || obj_priv->tiling_mode == I915_TILING_NONE)
 		return 4096;
 
 	/*
 	 * Previous chips need to be aligned to the size of the smallest
 	 * fence register that can contain the object.
 	 */
-	if (IS_I9XX(dev))
+	if (INTEL_INFO(dev)->gen == 3)
 		start = 1024*1024;
 	else
 		start = 512*1024;
@@ -1392,7 +1518,11 @@
 	if (obj == NULL)
 		return -ENOENT;
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
+	}
 
 	obj_priv = to_intel_bo(obj);
 
@@ -1434,7 +1564,7 @@
 	return 0;
 }
 
-void
+static void
 i915_gem_object_put_pages(struct drm_gem_object *obj)
 {
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1468,13 +1598,24 @@
 	obj_priv->pages = NULL;
 }
 
+static uint32_t
+i915_gem_next_request_seqno(struct drm_device *dev,
+			    struct intel_ring_buffer *ring)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	ring->outstanding_lazy_request = true;
+	return dev_priv->next_seqno;
+}
+
 static void
-i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
+i915_gem_object_move_to_active(struct drm_gem_object *obj,
 			       struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = obj->dev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+	uint32_t seqno = i915_gem_next_request_seqno(dev, ring);
+
 	BUG_ON(ring == NULL);
 	obj_priv->ring = ring;
 
@@ -1483,10 +1624,9 @@
 		drm_gem_object_reference(obj);
 		obj_priv->active = 1;
 	}
+
 	/* Move from whatever list we were on to the tail of execution. */
-	spin_lock(&dev_priv->mm.active_list_lock);
 	list_move_tail(&obj_priv->list, &ring->active_list);
-	spin_unlock(&dev_priv->mm.active_list_lock);
 	obj_priv->last_rendering_seqno = seqno;
 }
 
@@ -1536,9 +1676,8 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
 	if (obj_priv->pin_count != 0)
-		list_del_init(&obj_priv->list);
+		list_move_tail(&obj_priv->list, &dev_priv->mm.pinned_list);
 	else
 		list_move_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
 
@@ -1550,12 +1689,12 @@
 		obj_priv->active = 0;
 		drm_gem_object_unreference(obj);
 	}
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	WARN_ON(i915_verify_lists(dev));
 }
 
 static void
 i915_gem_process_flushing_list(struct drm_device *dev,
-			       uint32_t flush_domains, uint32_t seqno,
+			       uint32_t flush_domains,
 			       struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -1566,14 +1705,13 @@
 				 gpu_write_list) {
 		struct drm_gem_object *obj = &obj_priv->base;
 
-		if ((obj->write_domain & flush_domains) ==
-		    obj->write_domain &&
-		    obj_priv->ring->ring_flag == ring->ring_flag) {
+		if (obj->write_domain & flush_domains &&
+		    obj_priv->ring == ring) {
 			uint32_t old_write_domain = obj->write_domain;
 
 			obj->write_domain = 0;
 			list_del_init(&obj_priv->gpu_write_list);
-			i915_gem_object_move_to_active(obj, seqno, ring);
+			i915_gem_object_move_to_active(obj, ring);
 
 			/* update the fence lru list */
 			if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
@@ -1591,23 +1729,27 @@
 }
 
 uint32_t
-i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
-		 uint32_t flush_domains, struct intel_ring_buffer *ring)
+i915_add_request(struct drm_device *dev,
+		 struct drm_file *file,
+		 struct drm_i915_gem_request *request,
+		 struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_i915_file_private *i915_file_priv = NULL;
-	struct drm_i915_gem_request *request;
+	struct drm_i915_file_private *file_priv = NULL;
 	uint32_t seqno;
 	int was_empty;
 
-	if (file_priv != NULL)
-		i915_file_priv = file_priv->driver_priv;
+	if (file != NULL)
+		file_priv = file->driver_priv;
 
-	request = kzalloc(sizeof(*request), GFP_KERNEL);
-	if (request == NULL)
-		return 0;
+	if (request == NULL) {
+		request = kzalloc(sizeof(*request), GFP_KERNEL);
+		if (request == NULL)
+			return 0;
+	}
 
-	seqno = ring->add_request(dev, ring, file_priv, flush_domains);
+	seqno = ring->add_request(dev, ring, 0);
+	ring->outstanding_lazy_request = false;
 
 	request->seqno = seqno;
 	request->ring = ring;
@@ -1615,23 +1757,20 @@
 	was_empty = list_empty(&ring->request_list);
 	list_add_tail(&request->list, &ring->request_list);
 
-	if (i915_file_priv) {
+	if (file_priv) {
+		spin_lock(&file_priv->mm.lock);
+		request->file_priv = file_priv;
 		list_add_tail(&request->client_list,
-			      &i915_file_priv->mm.request_list);
-	} else {
-		INIT_LIST_HEAD(&request->client_list);
+			      &file_priv->mm.request_list);
+		spin_unlock(&file_priv->mm.lock);
 	}
 
-	/* Associate any objects on the flushing list matching the write
-	 * domain we're flushing with our flush.
-	 */
-	if (flush_domains != 0) 
-		i915_gem_process_flushing_list(dev, flush_domains, seqno, ring);
-
 	if (!dev_priv->mm.suspended) {
-		mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+		mod_timer(&dev_priv->hangcheck_timer,
+			  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 		if (was_empty)
-			queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+			queue_delayed_work(dev_priv->wq,
+					   &dev_priv->mm.retire_work, HZ);
 	}
 	return seqno;
 }
@@ -1642,91 +1781,105 @@
  * Ensures that all commands in the ring are finished
  * before signalling the CPU
  */
-static uint32_t
+static void
 i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring)
 {
 	uint32_t flush_domains = 0;
 
 	/* The sampler always gets flushed on i965 (sigh) */
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		flush_domains |= I915_GEM_DOMAIN_SAMPLER;
 
 	ring->flush(dev, ring,
 			I915_GEM_DOMAIN_COMMAND, flush_domains);
-	return flush_domains;
 }
 
-/**
- * Moves buffers associated only with the given active seqno from the active
- * to inactive list, potentially freeing them.
- */
-static void
-i915_gem_retire_request(struct drm_device *dev,
-			struct drm_i915_gem_request *request)
+static inline void
+i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
 {
-	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *file_priv = request->file_priv;
 
-	trace_i915_gem_request_retire(dev, request->seqno);
+	if (!file_priv)
+		return;
 
-	/* Move any buffers on the active list that are no longer referenced
-	 * by the ringbuffer to the flushing/inactive lists as appropriate.
-	 */
-	spin_lock(&dev_priv->mm.active_list_lock);
-	while (!list_empty(&request->ring->active_list)) {
-		struct drm_gem_object *obj;
+	spin_lock(&file_priv->mm.lock);
+	list_del(&request->client_list);
+	request->file_priv = NULL;
+	spin_unlock(&file_priv->mm.lock);
+}
+
+static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
+				      struct intel_ring_buffer *ring)
+{
+	while (!list_empty(&ring->request_list)) {
+		struct drm_i915_gem_request *request;
+
+		request = list_first_entry(&ring->request_list,
+					   struct drm_i915_gem_request,
+					   list);
+
+		list_del(&request->list);
+		i915_gem_request_remove_from_client(request);
+		kfree(request);
+	}
+
+	while (!list_empty(&ring->active_list)) {
 		struct drm_i915_gem_object *obj_priv;
 
-		obj_priv = list_first_entry(&request->ring->active_list,
+		obj_priv = list_first_entry(&ring->active_list,
 					    struct drm_i915_gem_object,
 					    list);
-		obj = &obj_priv->base;
 
-		/* If the seqno being retired doesn't match the oldest in the
-		 * list, then the oldest in the list must still be newer than
-		 * this seqno.
-		 */
-		if (obj_priv->last_rendering_seqno != request->seqno)
-			goto out;
-
-#if WATCH_LRU
-		DRM_INFO("%s: retire %d moves to inactive list %p\n",
-			 __func__, request->seqno, obj);
-#endif
-
-		if (obj->write_domain != 0)
-			i915_gem_object_move_to_flushing(obj);
-		else {
-			/* Take a reference on the object so it won't be
-			 * freed while the spinlock is held.  The list
-			 * protection for this spinlock is safe when breaking
-			 * the lock like this since the next thing we do
-			 * is just get the head of the list again.
-			 */
-			drm_gem_object_reference(obj);
-			i915_gem_object_move_to_inactive(obj);
-			spin_unlock(&dev_priv->mm.active_list_lock);
-			drm_gem_object_unreference(obj);
-			spin_lock(&dev_priv->mm.active_list_lock);
-		}
+		obj_priv->base.write_domain = 0;
+		list_del_init(&obj_priv->gpu_write_list);
+		i915_gem_object_move_to_inactive(&obj_priv->base);
 	}
-out:
-	spin_unlock(&dev_priv->mm.active_list_lock);
 }
 
-/**
- * Returns true if seq1 is later than seq2.
- */
-bool
-i915_seqno_passed(uint32_t seq1, uint32_t seq2)
+void i915_gem_reset(struct drm_device *dev)
 {
-	return (int32_t)(seq1 - seq2) >= 0;
-}
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_gem_object *obj_priv;
+	int i;
 
-uint32_t
-i915_get_gem_seqno(struct drm_device *dev,
-		   struct intel_ring_buffer *ring)
-{
-	return ring->get_gem_seqno(dev, ring);
+	i915_gem_reset_ring_lists(dev_priv, &dev_priv->render_ring);
+	if (HAS_BSD(dev))
+		i915_gem_reset_ring_lists(dev_priv, &dev_priv->bsd_ring);
+
+	/* Remove anything from the flushing lists. The GPU cache is likely
+	 * to be lost on reset along with the data, so simply move the
+	 * lost bo to the inactive list.
+	 */
+	while (!list_empty(&dev_priv->mm.flushing_list)) {
+		obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
+					    struct drm_i915_gem_object,
+					    list);
+
+		obj_priv->base.write_domain = 0;
+		list_del_init(&obj_priv->gpu_write_list);
+		i915_gem_object_move_to_inactive(&obj_priv->base);
+	}
+
+	/* Move everything out of the GPU domains to ensure we do any
+	 * necessary invalidation upon reuse.
+	 */
+	list_for_each_entry(obj_priv,
+			    &dev_priv->mm.inactive_list,
+			    list)
+	{
+		obj_priv->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
+	}
+
+	/* The fence registers are invalidated so clear them out */
+	for (i = 0; i < 16; i++) {
+		struct drm_i915_fence_reg *reg;
+
+		reg = &dev_priv->fence_regs[i];
+		if (!reg->obj)
+			continue;
+
+		i915_gem_clear_fence_reg(reg->obj);
+	}
 }
 
 /**
@@ -1739,38 +1892,58 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	uint32_t seqno;
 
-	if (!ring->status_page.page_addr
-			|| list_empty(&ring->request_list))
+	if (!ring->status_page.page_addr ||
+	    list_empty(&ring->request_list))
 		return;
 
-	seqno = i915_get_gem_seqno(dev, ring);
+	WARN_ON(i915_verify_lists(dev));
 
+	seqno = ring->get_seqno(dev, ring);
 	while (!list_empty(&ring->request_list)) {
 		struct drm_i915_gem_request *request;
-		uint32_t retiring_seqno;
 
 		request = list_first_entry(&ring->request_list,
 					   struct drm_i915_gem_request,
 					   list);
-		retiring_seqno = request->seqno;
 
-		if (i915_seqno_passed(seqno, retiring_seqno) ||
-		    atomic_read(&dev_priv->mm.wedged)) {
-			i915_gem_retire_request(dev, request);
-
-			list_del(&request->list);
-			list_del(&request->client_list);
-			kfree(request);
-		} else
+		if (!i915_seqno_passed(seqno, request->seqno))
 			break;
+
+		trace_i915_gem_request_retire(dev, request->seqno);
+
+		list_del(&request->list);
+		i915_gem_request_remove_from_client(request);
+		kfree(request);
+	}
+
+	/* Move any buffers on the active list that are no longer referenced
+	 * by the ringbuffer to the flushing/inactive lists as appropriate.
+	 */
+	while (!list_empty(&ring->active_list)) {
+		struct drm_gem_object *obj;
+		struct drm_i915_gem_object *obj_priv;
+
+		obj_priv = list_first_entry(&ring->active_list,
+					    struct drm_i915_gem_object,
+					    list);
+
+		if (!i915_seqno_passed(seqno, obj_priv->last_rendering_seqno))
+			break;
+
+		obj = &obj_priv->base;
+		if (obj->write_domain != 0)
+			i915_gem_object_move_to_flushing(obj);
+		else
+			i915_gem_object_move_to_inactive(obj);
 	}
 
 	if (unlikely (dev_priv->trace_irq_seqno &&
 		      i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
-
 		ring->user_irq_put(dev, ring);
 		dev_priv->trace_irq_seqno = 0;
 	}
+
+	WARN_ON(i915_verify_lists(dev));
 }
 
 void
@@ -1797,7 +1970,7 @@
 		i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring);
 }
 
-void
+static void
 i915_gem_retire_work_handler(struct work_struct *work)
 {
 	drm_i915_private_t *dev_priv;
@@ -1807,7 +1980,12 @@
 				mm.retire_work.work);
 	dev = dev_priv->dev;
 
-	mutex_lock(&dev->struct_mutex);
+	/* Come back later if the device is busy... */
+	if (!mutex_trylock(&dev->struct_mutex)) {
+		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
+		return;
+	}
+
 	i915_gem_retire_requests(dev);
 
 	if (!dev_priv->mm.suspended &&
@@ -1820,7 +1998,7 @@
 
 int
 i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
-		int interruptible, struct intel_ring_buffer *ring)
+		     bool interruptible, struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 ier;
@@ -1829,9 +2007,16 @@
 	BUG_ON(seqno == 0);
 
 	if (atomic_read(&dev_priv->mm.wedged))
-		return -EIO;
+		return -EAGAIN;
 
-	if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) {
+	if (ring->outstanding_lazy_request) {
+		seqno = i915_add_request(dev, NULL, NULL, ring);
+		if (seqno == 0)
+			return -ENOMEM;
+	}
+	BUG_ON(seqno == dev_priv->next_seqno);
+
+	if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
 		if (HAS_PCH_SPLIT(dev))
 			ier = I915_READ(DEIER) | I915_READ(GTIER);
 		else
@@ -1850,12 +2035,12 @@
 		if (interruptible)
 			ret = wait_event_interruptible(ring->irq_queue,
 				i915_seqno_passed(
-					ring->get_gem_seqno(dev, ring), seqno)
+					ring->get_seqno(dev, ring), seqno)
 				|| atomic_read(&dev_priv->mm.wedged));
 		else
 			wait_event(ring->irq_queue,
 				i915_seqno_passed(
-					ring->get_gem_seqno(dev, ring), seqno)
+					ring->get_seqno(dev, ring), seqno)
 				|| atomic_read(&dev_priv->mm.wedged));
 
 		ring->user_irq_put(dev, ring);
@@ -1864,11 +2049,12 @@
 		trace_i915_gem_request_wait_end(dev, seqno);
 	}
 	if (atomic_read(&dev_priv->mm.wedged))
-		ret = -EIO;
+		ret = -EAGAIN;
 
 	if (ret && ret != -ERESTARTSYS)
-		DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
-			  __func__, ret, seqno, ring->get_gem_seqno(dev, ring));
+		DRM_ERROR("%s returns %d (awaiting %d at %d, next %d)\n",
+			  __func__, ret, seqno, ring->get_seqno(dev, ring),
+			  dev_priv->next_seqno);
 
 	/* Directly dispatch request retiring.  While we have the work queue
 	 * to handle this, the waiter on a request often wants an associated
@@ -1887,27 +2073,44 @@
  */
 static int
 i915_wait_request(struct drm_device *dev, uint32_t seqno,
-		struct intel_ring_buffer *ring)
+		  struct intel_ring_buffer *ring)
 {
 	return i915_do_wait_request(dev, seqno, 1, ring);
 }
 
 static void
+i915_gem_flush_ring(struct drm_device *dev,
+		    struct drm_file *file_priv,
+		    struct intel_ring_buffer *ring,
+		    uint32_t invalidate_domains,
+		    uint32_t flush_domains)
+{
+	ring->flush(dev, ring, invalidate_domains, flush_domains);
+	i915_gem_process_flushing_list(dev, flush_domains, ring);
+}
+
+static void
 i915_gem_flush(struct drm_device *dev,
+	       struct drm_file *file_priv,
 	       uint32_t invalidate_domains,
-	       uint32_t flush_domains)
+	       uint32_t flush_domains,
+	       uint32_t flush_rings)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
+
 	if (flush_domains & I915_GEM_DOMAIN_CPU)
 		drm_agp_chipset_flush(dev);
-	dev_priv->render_ring.flush(dev, &dev_priv->render_ring,
-			invalidate_domains,
-			flush_domains);
 
-	if (HAS_BSD(dev))
-		dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring,
-				invalidate_domains,
-				flush_domains);
+	if ((flush_domains | invalidate_domains) & I915_GEM_GPU_DOMAINS) {
+		if (flush_rings & RING_RENDER)
+			i915_gem_flush_ring(dev, file_priv,
+					    &dev_priv->render_ring,
+					    invalidate_domains, flush_domains);
+		if (flush_rings & RING_BSD)
+			i915_gem_flush_ring(dev, file_priv,
+					    &dev_priv->bsd_ring,
+					    invalidate_domains, flush_domains);
+	}
 }
 
 /**
@@ -1915,7 +2118,8 @@
  * safe to unbind from the GTT or access from the CPU.
  */
 static int
-i915_gem_object_wait_rendering(struct drm_gem_object *obj)
+i915_gem_object_wait_rendering(struct drm_gem_object *obj,
+			       bool interruptible)
 {
 	struct drm_device *dev = obj->dev;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
@@ -1930,13 +2134,11 @@
 	 * it.
 	 */
 	if (obj_priv->active) {
-#if WATCH_BUF
-		DRM_INFO("%s: object %p wait for seqno %08x\n",
-			  __func__, obj, obj_priv->last_rendering_seqno);
-#endif
-		ret = i915_wait_request(dev,
-				obj_priv->last_rendering_seqno, obj_priv->ring);
-		if (ret != 0)
+		ret = i915_do_wait_request(dev,
+					   obj_priv->last_rendering_seqno,
+					   interruptible,
+					   obj_priv->ring);
+		if (ret)
 			return ret;
 	}
 
@@ -1950,14 +2152,10 @@
 i915_gem_object_unbind(struct drm_gem_object *obj)
 {
 	struct drm_device *dev = obj->dev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 	int ret = 0;
 
-#if WATCH_BUF
-	DRM_INFO("%s:%d %p\n", __func__, __LINE__, obj);
-	DRM_INFO("gtt_space %p\n", obj_priv->gtt_space);
-#endif
 	if (obj_priv->gtt_space == NULL)
 		return 0;
 
@@ -1982,33 +2180,26 @@
 	 * should be safe and we need to cleanup or else we might
 	 * cause memory corruption through use-after-free.
 	 */
+	if (ret) {
+		i915_gem_clflush_object(obj);
+		obj->read_domains = obj->write_domain = I915_GEM_DOMAIN_CPU;
+	}
 
 	/* release the fence reg _after_ flushing */
 	if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
 		i915_gem_clear_fence_reg(obj);
 
-	if (obj_priv->agp_mem != NULL) {
-		drm_unbind_agp(obj_priv->agp_mem);
-		drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
-		obj_priv->agp_mem = NULL;
-	}
+	drm_unbind_agp(obj_priv->agp_mem);
+	drm_free_agp(obj_priv->agp_mem, obj->size / PAGE_SIZE);
 
 	i915_gem_object_put_pages(obj);
 	BUG_ON(obj_priv->pages_refcount);
 
-	if (obj_priv->gtt_space) {
-		atomic_dec(&dev->gtt_count);
-		atomic_sub(obj->size, &dev->gtt_memory);
+	i915_gem_info_remove_gtt(dev_priv, obj->size);
+	list_del_init(&obj_priv->list);
 
-		drm_mm_put_block(obj_priv->gtt_space);
-		obj_priv->gtt_space = NULL;
-	}
-
-	/* Remove ourselves from the LRU list if present. */
-	spin_lock(&dev_priv->mm.active_list_lock);
-	if (!list_empty(&obj_priv->list))
-		list_del_init(&obj_priv->list);
-	spin_unlock(&dev_priv->mm.active_list_lock);
+	drm_mm_put_block(obj_priv->gtt_space);
+	obj_priv->gtt_space = NULL;
 
 	if (i915_gem_object_is_purgeable(obj_priv))
 		i915_gem_object_truncate(obj);
@@ -2018,48 +2209,45 @@
 	return ret;
 }
 
+static int i915_ring_idle(struct drm_device *dev,
+			  struct intel_ring_buffer *ring)
+{
+	i915_gem_flush_ring(dev, NULL, ring,
+			    I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+	return i915_wait_request(dev,
+				 i915_gem_next_request_seqno(dev, ring),
+				 ring);
+}
+
 int
 i915_gpu_idle(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	bool lists_empty;
-	uint32_t seqno1, seqno2;
 	int ret;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
 		       list_empty(&dev_priv->render_ring.active_list) &&
 		       (!HAS_BSD(dev) ||
 			list_empty(&dev_priv->bsd_ring.active_list)));
-	spin_unlock(&dev_priv->mm.active_list_lock);
-
 	if (lists_empty)
 		return 0;
 
 	/* Flush everything onto the inactive list. */
-	i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
-	seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
-			&dev_priv->render_ring);
-	if (seqno1 == 0)
-		return -ENOMEM;
-	ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring);
+	ret = i915_ring_idle(dev, &dev_priv->render_ring);
+	if (ret)
+		return ret;
 
 	if (HAS_BSD(dev)) {
-		seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
-				&dev_priv->bsd_ring);
-		if (seqno2 == 0)
-			return -ENOMEM;
-
-		ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring);
+		ret = i915_ring_idle(dev, &dev_priv->bsd_ring);
 		if (ret)
 			return ret;
 	}
 
-
-	return ret;
+	return 0;
 }
 
-int
+static int
 i915_gem_object_get_pages(struct drm_gem_object *obj,
 			  gfp_t gfpmask)
 {
@@ -2239,7 +2427,8 @@
 	I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
 }
 
-static int i915_find_fence_reg(struct drm_device *dev)
+static int i915_find_fence_reg(struct drm_device *dev,
+			       bool interruptible)
 {
 	struct drm_i915_fence_reg *reg = NULL;
 	struct drm_i915_gem_object *obj_priv = NULL;
@@ -2284,7 +2473,7 @@
 	 * private reference to obj like the other callers of put_fence_reg
 	 * (set_tiling ioctl) do. */
 	drm_gem_object_reference(obj);
-	ret = i915_gem_object_put_fence_reg(obj);
+	ret = i915_gem_object_put_fence_reg(obj, interruptible);
 	drm_gem_object_unreference(obj);
 	if (ret != 0)
 		return ret;
@@ -2306,7 +2495,8 @@
  * and tiling format.
  */
 int
-i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_get_fence_reg(struct drm_gem_object *obj,
+			      bool interruptible)
 {
 	struct drm_device *dev = obj->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2341,7 +2531,7 @@
 		break;
 	}
 
-	ret = i915_find_fence_reg(dev);
+	ret = i915_find_fence_reg(dev, interruptible);
 	if (ret < 0)
 		return ret;
 
@@ -2400,7 +2590,7 @@
 		I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
 		break;
 	case 3:
-		if (obj_priv->fence_reg > 8)
+		if (obj_priv->fence_reg >= 8)
 			fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg - 8) * 4;
 		else
 	case 2:
@@ -2419,15 +2609,19 @@
  * i915_gem_object_put_fence_reg - waits on outstanding fenced access
  * to the buffer to finish, and then resets the fence register.
  * @obj: tiled object holding a fence register.
+ * @bool: whether the wait upon the fence is interruptible
  *
  * Zeroes out the fence register itself and clears out the associated
  * data structures in dev_priv and obj_priv.
  */
 int
-i915_gem_object_put_fence_reg(struct drm_gem_object *obj)
+i915_gem_object_put_fence_reg(struct drm_gem_object *obj,
+			      bool interruptible)
 {
 	struct drm_device *dev = obj->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+	struct drm_i915_fence_reg *reg;
 
 	if (obj_priv->fence_reg == I915_FENCE_REG_NONE)
 		return 0;
@@ -2442,20 +2636,23 @@
 	 * therefore we must wait for any outstanding access to complete
 	 * before clearing the fence.
 	 */
-	if (!IS_I965G(dev)) {
+	reg = &dev_priv->fence_regs[obj_priv->fence_reg];
+	if (reg->gpu) {
 		int ret;
 
-		ret = i915_gem_object_flush_gpu_write_domain(obj);
-		if (ret != 0)
+		ret = i915_gem_object_flush_gpu_write_domain(obj, true);
+		if (ret)
 			return ret;
 
-		ret = i915_gem_object_wait_rendering(obj);
-		if (ret != 0)
+		ret = i915_gem_object_wait_rendering(obj, interruptible);
+		if (ret)
 			return ret;
+
+		reg->gpu = false;
 	}
 
 	i915_gem_object_flush_gtt_write_domain(obj);
-	i915_gem_clear_fence_reg (obj);
+	i915_gem_clear_fence_reg(obj);
 
 	return 0;
 }
@@ -2488,7 +2685,7 @@
 	/* If the object is bigger than the entire aperture, reject it early
 	 * before evicting everything in a vain attempt to find space.
 	 */
-	if (obj->size > dev->gtt_total) {
+	if (obj->size > dev_priv->mm.gtt_total) {
 		DRM_ERROR("Attempting to bind an object larger than the aperture\n");
 		return -E2BIG;
 	}
@@ -2506,9 +2703,6 @@
 		/* If the gtt is empty and we're still having trouble
 		 * fitting our object in, we're out of memory.
 		 */
-#if WATCH_LRU
-		DRM_INFO("%s: GTT full, evicting something\n", __func__);
-#endif
 		ret = i915_gem_evict_something(dev, obj->size, alignment);
 		if (ret)
 			return ret;
@@ -2516,10 +2710,6 @@
 		goto search_free;
 	}
 
-#if WATCH_BUF
-	DRM_INFO("Binding object of size %zd at 0x%08x\n",
-		 obj->size, obj_priv->gtt_offset);
-#endif
 	ret = i915_gem_object_get_pages(obj, gfpmask);
 	if (ret) {
 		drm_mm_put_block(obj_priv->gtt_space);
@@ -2564,11 +2754,10 @@
 
 		goto search_free;
 	}
-	atomic_inc(&dev->gtt_count);
-	atomic_add(obj->size, &dev->gtt_memory);
 
 	/* keep track of bounds object by adding it to the inactive list */
 	list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
+	i915_gem_info_add_gtt(dev_priv, obj->size);
 
 	/* Assert that the object is not currently in any GPU domain. As it
 	 * wasn't in the GTT, there shouldn't be any way it could have been in
@@ -2601,25 +2790,30 @@
 
 /** Flushes any GPU write domain for the object if it's dirty. */
 static int
-i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
+i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj,
+				       bool pipelined)
 {
 	struct drm_device *dev = obj->dev;
 	uint32_t old_write_domain;
-	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
 	if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
 		return 0;
 
 	/* Queue the GPU write cache flushing we need. */
 	old_write_domain = obj->write_domain;
-	i915_gem_flush(dev, 0, obj->write_domain);
-	if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0)
-		return -ENOMEM;
+	i915_gem_flush_ring(dev, NULL,
+			    to_intel_bo(obj)->ring,
+			    0, obj->write_domain);
+	BUG_ON(obj->write_domain);
 
 	trace_i915_gem_object_change_domain(obj,
 					    obj->read_domains,
 					    old_write_domain);
-	return 0;
+
+	if (pipelined)
+		return 0;
+
+	return i915_gem_object_wait_rendering(obj, true);
 }
 
 /** Flushes the GTT write domain for the object if it's dirty. */
@@ -2663,26 +2857,6 @@
 					    old_write_domain);
 }
 
-int
-i915_gem_object_flush_write_domain(struct drm_gem_object *obj)
-{
-	int ret = 0;
-
-	switch (obj->write_domain) {
-	case I915_GEM_DOMAIN_GTT:
-		i915_gem_object_flush_gtt_write_domain(obj);
-		break;
-	case I915_GEM_DOMAIN_CPU:
-		i915_gem_object_flush_cpu_write_domain(obj);
-		break;
-	default:
-		ret = i915_gem_object_flush_gpu_write_domain(obj);
-		break;
-	}
-
-	return ret;
-}
-
 /**
  * Moves a single object to the GTT read, and possibly write domain.
  *
@@ -2700,32 +2874,28 @@
 	if (obj_priv->gtt_space == NULL)
 		return -EINVAL;
 
-	ret = i915_gem_object_flush_gpu_write_domain(obj);
+	ret = i915_gem_object_flush_gpu_write_domain(obj, false);
 	if (ret != 0)
 		return ret;
 
-	/* Wait on any GPU rendering and flushing to occur. */
-	ret = i915_gem_object_wait_rendering(obj);
-	if (ret != 0)
-		return ret;
+	i915_gem_object_flush_cpu_write_domain(obj);
+
+	if (write) {
+		ret = i915_gem_object_wait_rendering(obj, true);
+		if (ret)
+			return ret;
+	}
 
 	old_write_domain = obj->write_domain;
 	old_read_domains = obj->read_domains;
 
-	/* If we're writing through the GTT domain, then CPU and GPU caches
-	 * will need to be invalidated at next use.
-	 */
-	if (write)
-		obj->read_domains &= I915_GEM_DOMAIN_GTT;
-
-	i915_gem_object_flush_cpu_write_domain(obj);
-
 	/* It should now be out of any other write domains, and we can update
 	 * the domain values for our changes.
 	 */
 	BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
 	obj->read_domains |= I915_GEM_DOMAIN_GTT;
 	if (write) {
+		obj->read_domains = I915_GEM_DOMAIN_GTT;
 		obj->write_domain = I915_GEM_DOMAIN_GTT;
 		obj_priv->dirty = 1;
 	}
@@ -2742,51 +2912,36 @@
  * wait, as in modesetting process we're not supposed to be interrupted.
  */
 int
-i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
+i915_gem_object_set_to_display_plane(struct drm_gem_object *obj,
+				     bool pipelined)
 {
-	struct drm_device *dev = obj->dev;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
-	uint32_t old_write_domain, old_read_domains;
+	uint32_t old_read_domains;
 	int ret;
 
 	/* Not valid to be called on unbound objects. */
 	if (obj_priv->gtt_space == NULL)
 		return -EINVAL;
 
-	ret = i915_gem_object_flush_gpu_write_domain(obj);
+	ret = i915_gem_object_flush_gpu_write_domain(obj, true);
 	if (ret)
 		return ret;
 
-	/* Wait on any GPU rendering and flushing to occur. */
-	if (obj_priv->active) {
-#if WATCH_BUF
-		DRM_INFO("%s: object %p wait for seqno %08x\n",
-			  __func__, obj, obj_priv->last_rendering_seqno);
-#endif
-		ret = i915_do_wait_request(dev,
-				obj_priv->last_rendering_seqno,
-				0,
-				obj_priv->ring);
-		if (ret != 0)
+	/* Currently, we are always called from an non-interruptible context. */
+	if (!pipelined) {
+		ret = i915_gem_object_wait_rendering(obj, false);
+		if (ret)
 			return ret;
 	}
 
 	i915_gem_object_flush_cpu_write_domain(obj);
 
-	old_write_domain = obj->write_domain;
 	old_read_domains = obj->read_domains;
-
-	/* It should now be out of any other write domains, and we can update
-	 * the domain values for our changes.
-	 */
-	BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
-	obj->read_domains = I915_GEM_DOMAIN_GTT;
-	obj->write_domain = I915_GEM_DOMAIN_GTT;
-	obj_priv->dirty = 1;
+	obj->read_domains |= I915_GEM_DOMAIN_GTT;
 
 	trace_i915_gem_object_change_domain(obj,
 					    old_read_domains,
-					    old_write_domain);
+					    obj->write_domain);
 
 	return 0;
 }
@@ -2803,12 +2958,7 @@
 	uint32_t old_write_domain, old_read_domains;
 	int ret;
 
-	ret = i915_gem_object_flush_gpu_write_domain(obj);
-	if (ret)
-		return ret;
-
-	/* Wait on any GPU rendering and flushing to occur. */
-	ret = i915_gem_object_wait_rendering(obj);
+	ret = i915_gem_object_flush_gpu_write_domain(obj, false);
 	if (ret != 0)
 		return ret;
 
@@ -2819,6 +2969,12 @@
 	 */
 	i915_gem_object_set_to_full_cpu_read_domain(obj);
 
+	if (write) {
+		ret = i915_gem_object_wait_rendering(obj, true);
+		if (ret)
+			return ret;
+	}
+
 	old_write_domain = obj->write_domain;
 	old_read_domains = obj->read_domains;
 
@@ -2838,7 +2994,7 @@
 	 * need to be invalidated at next use.
 	 */
 	if (write) {
-		obj->read_domains &= I915_GEM_DOMAIN_CPU;
+		obj->read_domains = I915_GEM_DOMAIN_CPU;
 		obj->write_domain = I915_GEM_DOMAIN_CPU;
 	}
 
@@ -2964,7 +3120,7 @@
 i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
 {
 	struct drm_device		*dev = obj->dev;
-	drm_i915_private_t		*dev_priv = dev->dev_private;
+	struct drm_i915_private		*dev_priv = dev->dev_private;
 	struct drm_i915_gem_object	*obj_priv = to_intel_bo(obj);
 	uint32_t			invalidate_domains = 0;
 	uint32_t			flush_domains = 0;
@@ -2975,12 +3131,6 @@
 
 	intel_mark_busy(dev, obj);
 
-#if WATCH_BUF
-	DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
-		 __func__, obj,
-		 obj->read_domains, obj->pending_read_domains,
-		 obj->write_domain, obj->pending_write_domain);
-#endif
 	/*
 	 * If the object isn't moving to a new write domain,
 	 * let the object stay in multiple read domains
@@ -3007,13 +3157,8 @@
 	 * stale data. That is, any new read domains.
 	 */
 	invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
-	if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
-#if WATCH_BUF
-		DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
-			 __func__, flush_domains, invalidate_domains);
-#endif
+	if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU)
 		i915_gem_clflush_object(obj);
-	}
 
 	old_read_domains = obj->read_domains;
 
@@ -3027,21 +3172,10 @@
 		obj->pending_write_domain = obj->write_domain;
 	obj->read_domains = obj->pending_read_domains;
 
-	if (flush_domains & I915_GEM_GPU_DOMAINS) {
-		if (obj_priv->ring == &dev_priv->render_ring)
-			dev_priv->flush_rings |= FLUSH_RENDER_RING;
-		else if (obj_priv->ring == &dev_priv->bsd_ring)
-			dev_priv->flush_rings |= FLUSH_BSD_RING;
-	}
-
 	dev->invalidate_domains |= invalidate_domains;
 	dev->flush_domains |= flush_domains;
-#if WATCH_BUF
-	DRM_INFO("%s: read %08x write %08x invalidate %08x flush %08x\n",
-		 __func__,
-		 obj->read_domains, obj->write_domain,
-		 dev->invalidate_domains, dev->flush_domains);
-#endif
+	if (obj_priv->ring)
+		dev_priv->mm.flush_rings |= obj_priv->ring->id;
 
 	trace_i915_gem_object_change_domain(obj,
 					    old_read_domains,
@@ -3104,12 +3238,7 @@
 	if (offset == 0 && size == obj->size)
 		return i915_gem_object_set_to_cpu_domain(obj, 0);
 
-	ret = i915_gem_object_flush_gpu_write_domain(obj);
-	if (ret)
-		return ret;
-
-	/* Wait on any GPU rendering and flushing to occur. */
-	ret = i915_gem_object_wait_rendering(obj);
+	ret = i915_gem_object_flush_gpu_write_domain(obj, false);
 	if (ret != 0)
 		return ret;
 	i915_gem_object_flush_gtt_write_domain(obj);
@@ -3196,11 +3325,13 @@
 	 * properly handle blits to/from tiled surfaces.
 	 */
 	if (need_fence) {
-		ret = i915_gem_object_get_fence_reg(obj);
+		ret = i915_gem_object_get_fence_reg(obj, true);
 		if (ret != 0) {
 			i915_gem_object_unpin(obj);
 			return ret;
 		}
+
+		dev_priv->fence_regs[obj_priv->fence_reg].gpu = true;
 	}
 
 	entry->offset = obj_priv->gtt_offset;
@@ -3258,6 +3389,8 @@
 				  (int) reloc->offset,
 				  reloc->read_domains,
 				  reloc->write_domain);
+			drm_gem_object_unreference(target_obj);
+			i915_gem_object_unpin(obj);
 			return -EINVAL;
 		}
 		if (reloc->write_domain & I915_GEM_DOMAIN_CPU ||
@@ -3333,7 +3466,7 @@
 		if (ret != 0) {
 			drm_gem_object_unreference(target_obj);
 			i915_gem_object_unpin(obj);
-			return -EINVAL;
+			return ret;
 		}
 
 		/* Map the page containing the relocation we're going to
@@ -3348,11 +3481,6 @@
 						   (reloc_offset & (PAGE_SIZE - 1)));
 		reloc_val = target_obj_priv->gtt_offset + reloc->delta;
 
-#if WATCH_BUF
-		DRM_INFO("Applied relocation: %p@0x%08x %08x -> %08x\n",
-			  obj, (unsigned int) reloc->offset,
-			  readl(reloc_entry), reloc_val);
-#endif
 		writel(reloc_val, reloc_entry);
 		io_mapping_unmap_atomic(reloc_page, KM_USER0);
 
@@ -3364,10 +3492,6 @@
 		drm_gem_object_unreference(target_obj);
 	}
 
-#if WATCH_BUF
-	if (0)
-		i915_gem_dump_object(obj, 128, __func__, ~0);
-#endif
 	return 0;
 }
 
@@ -3382,28 +3506,48 @@
  * relatively low latency when blocking on a particular request to finish.
  */
 static int
-i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
+i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
 {
-	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
-	int ret = 0;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
 	unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
+	struct drm_i915_gem_request *request;
+	struct intel_ring_buffer *ring = NULL;
+	u32 seqno = 0;
+	int ret;
 
-	mutex_lock(&dev->struct_mutex);
-	while (!list_empty(&i915_file_priv->mm.request_list)) {
-		struct drm_i915_gem_request *request;
-
-		request = list_first_entry(&i915_file_priv->mm.request_list,
-					   struct drm_i915_gem_request,
-					   client_list);
-
+	spin_lock(&file_priv->mm.lock);
+	list_for_each_entry(request, &file_priv->mm.request_list, client_list) {
 		if (time_after_eq(request->emitted_jiffies, recent_enough))
 			break;
 
-		ret = i915_wait_request(dev, request->seqno, request->ring);
-		if (ret != 0)
-			break;
+		ring = request->ring;
+		seqno = request->seqno;
 	}
-	mutex_unlock(&dev->struct_mutex);
+	spin_unlock(&file_priv->mm.lock);
+
+	if (seqno == 0)
+		return 0;
+
+	ret = 0;
+	if (!i915_seqno_passed(ring->get_seqno(dev, ring), seqno)) {
+		/* And wait for the seqno passing without holding any locks and
+		 * causing extra latency for others. This is safe as the irq
+		 * generation is designed to be run atomically and so is
+		 * lockless.
+		 */
+		ring->user_irq_get(dev, ring);
+		ret = wait_event_interruptible(ring->irq_queue,
+					       i915_seqno_passed(ring->get_seqno(dev, ring), seqno)
+					       || atomic_read(&dev_priv->mm.wedged));
+		ring->user_irq_put(dev, ring);
+
+		if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
+			ret = -EIO;
+	}
+
+	if (ret == 0)
+		queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
 
 	return ret;
 }
@@ -3539,8 +3683,7 @@
 	return ret;
 }
 
-
-int
+static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 		       struct drm_file *file_priv,
 		       struct drm_i915_gem_execbuffer2 *args,
@@ -3552,13 +3695,18 @@
 	struct drm_i915_gem_object *obj_priv;
 	struct drm_clip_rect *cliprects = NULL;
 	struct drm_i915_gem_relocation_entry *relocs = NULL;
-	int ret = 0, ret2, i, pinned = 0;
+	struct drm_i915_gem_request *request = NULL;
+	int ret, ret2, i, pinned = 0;
 	uint64_t exec_offset;
-	uint32_t seqno, flush_domains, reloc_index;
+	uint32_t reloc_index;
 	int pin_tries, flips;
 
 	struct intel_ring_buffer *ring = NULL;
 
+	ret = i915_gem_check_is_wedged(dev);
+	if (ret)
+		return ret;
+
 #if WATCH_EXEC
 	DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
 		  (int) args->buffers_ptr, args->buffer_count, args->batch_len);
@@ -3605,20 +3753,20 @@
 		}
 	}
 
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL) {
+		ret = -ENOMEM;
+		goto pre_mutex_err;
+	}
+
 	ret = i915_gem_get_relocs_from_user(exec_list, args->buffer_count,
 					    &relocs);
 	if (ret != 0)
 		goto pre_mutex_err;
 
-	mutex_lock(&dev->struct_mutex);
-
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
-	if (atomic_read(&dev_priv->mm.wedged)) {
-		mutex_unlock(&dev->struct_mutex);
-		ret = -EIO;
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret)
 		goto pre_mutex_err;
-	}
 
 	if (dev_priv->mm.suspended) {
 		mutex_unlock(&dev->struct_mutex);
@@ -3698,15 +3846,16 @@
 					  pinned+1, args->buffer_count,
 					  total_size, num_fences,
 					  ret);
-				DRM_ERROR("%d objects [%d pinned], "
-					  "%d object bytes [%d pinned], "
-					  "%d/%d gtt bytes\n",
-					  atomic_read(&dev->object_count),
-					  atomic_read(&dev->pin_count),
-					  atomic_read(&dev->object_memory),
-					  atomic_read(&dev->pin_memory),
-					  atomic_read(&dev->gtt_memory),
-					  dev->gtt_total);
+				DRM_ERROR("%u objects [%u pinned, %u GTT], "
+					  "%zu object bytes [%zu pinned], "
+					  "%zu /%zu gtt bytes\n",
+					  dev_priv->mm.object_count,
+					  dev_priv->mm.pin_count,
+					  dev_priv->mm.gtt_count,
+					  dev_priv->mm.object_memory,
+					  dev_priv->mm.pin_memory,
+					  dev_priv->mm.gtt_memory,
+					  dev_priv->mm.gtt_total);
 			}
 			goto err;
 		}
@@ -3739,15 +3888,13 @@
 		goto err;
 	}
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
 	/* Zero the global flush/invalidate flags. These
 	 * will be modified as new domains are computed
 	 * for each object
 	 */
 	dev->invalidate_domains = 0;
 	dev->flush_domains = 0;
-	dev_priv->flush_rings = 0;
+	dev_priv->mm.flush_rings = 0;
 
 	for (i = 0; i < args->buffer_count; i++) {
 		struct drm_gem_object *obj = object_list[i];
@@ -3756,8 +3903,6 @@
 		i915_gem_object_set_to_gpu_domain(obj);
 	}
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
 	if (dev->invalidate_domains | dev->flush_domains) {
 #if WATCH_EXEC
 		DRM_INFO("%s: invalidate_domains %08x flush_domains %08x\n",
@@ -3765,17 +3910,10 @@
 			 dev->invalidate_domains,
 			 dev->flush_domains);
 #endif
-		i915_gem_flush(dev,
+		i915_gem_flush(dev, file_priv,
 			       dev->invalidate_domains,
-			       dev->flush_domains);
-		if (dev_priv->flush_rings & FLUSH_RENDER_RING)
-			(void)i915_add_request(dev, file_priv,
-					       dev->flush_domains,
-					       &dev_priv->render_ring);
-		if (dev_priv->flush_rings & FLUSH_BSD_RING)
-			(void)i915_add_request(dev, file_priv,
-					       dev->flush_domains,
-					       &dev_priv->bsd_ring);
+			       dev->flush_domains,
+			       dev_priv->mm.flush_rings);
 	}
 
 	for (i = 0; i < args->buffer_count; i++) {
@@ -3787,16 +3925,12 @@
 		if (obj->write_domain)
 			list_move_tail(&obj_priv->gpu_write_list,
 				       &dev_priv->mm.gpu_write_list);
-		else
-			list_del_init(&obj_priv->gpu_write_list);
 
 		trace_i915_gem_object_change_domain(obj,
 						    obj->read_domains,
 						    old_write_domain);
 	}
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
 #if WATCH_COHERENCY
 	for (i = 0; i < args->buffer_count; i++) {
 		i915_gem_object_check_coherency(object_list[i],
@@ -3823,33 +3957,17 @@
 	 * Ensure that the commands in the batch buffer are
 	 * finished before the interrupt fires
 	 */
-	flush_domains = i915_retire_commands(dev, ring);
+	i915_retire_commands(dev, ring);
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
-
-	/*
-	 * Get a seqno representing the execution of the current buffer,
-	 * which we can wait on.  We would like to mitigate these interrupts,
-	 * likely by only creating seqnos occasionally (so that we have
-	 * *some* interrupts representing completion of buffers that we can
-	 * wait on when trying to clear up gtt space).
-	 */
-	seqno = i915_add_request(dev, file_priv, flush_domains, ring);
-	BUG_ON(seqno == 0);
 	for (i = 0; i < args->buffer_count; i++) {
 		struct drm_gem_object *obj = object_list[i];
 		obj_priv = to_intel_bo(obj);
 
-		i915_gem_object_move_to_active(obj, seqno, ring);
-#if WATCH_LRU
-		DRM_INFO("%s: move to exec list %p\n", __func__, obj);
-#endif
+		i915_gem_object_move_to_active(obj, ring);
 	}
-#if WATCH_LRU
-	i915_dump_lru(dev, __func__);
-#endif
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	i915_add_request(dev, file_priv, request, ring);
+	request = NULL;
 
 err:
 	for (i = 0; i < pinned; i++)
@@ -3882,6 +4000,7 @@
 
 	drm_free_large(object_list);
 	kfree(cliprects);
+	kfree(request);
 
 	return ret;
 }
@@ -3938,7 +4057,7 @@
 		exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr;
 		exec2_list[i].alignment = exec_list[i].alignment;
 		exec2_list[i].offset = exec_list[i].offset;
-		if (!IS_I965G(dev))
+		if (INTEL_INFO(dev)->gen < 4)
 			exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE;
 		else
 			exec2_list[i].flags = 0;
@@ -4035,12 +4154,12 @@
 i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
 {
 	struct drm_device *dev = obj->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 	int ret;
 
 	BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
-
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	WARN_ON(i915_verify_lists(dev));
 
 	if (obj_priv->gtt_space != NULL) {
 		if (alignment == 0)
@@ -4068,14 +4187,13 @@
 	 * remove it from the inactive list
 	 */
 	if (obj_priv->pin_count == 1) {
-		atomic_inc(&dev->pin_count);
-		atomic_add(obj->size, &dev->pin_memory);
-		if (!obj_priv->active &&
-		    (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
-			list_del_init(&obj_priv->list);
+		i915_gem_info_add_pin(dev_priv, obj->size);
+		if (!obj_priv->active)
+			list_move_tail(&obj_priv->list,
+				       &dev_priv->mm.pinned_list);
 	}
-	i915_verify_inactive(dev, __FILE__, __LINE__);
 
+	WARN_ON(i915_verify_lists(dev));
 	return 0;
 }
 
@@ -4086,7 +4204,7 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	WARN_ON(i915_verify_lists(dev));
 	obj_priv->pin_count--;
 	BUG_ON(obj_priv->pin_count < 0);
 	BUG_ON(obj_priv->gtt_space == NULL);
@@ -4096,14 +4214,12 @@
 	 * the inactive list
 	 */
 	if (obj_priv->pin_count == 0) {
-		if (!obj_priv->active &&
-		    (obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
+		if (!obj_priv->active)
 			list_move_tail(&obj_priv->list,
 				       &dev_priv->mm.inactive_list);
-		atomic_dec(&dev->pin_count);
-		atomic_sub(obj->size, &dev->pin_memory);
+		i915_gem_info_remove_pin(dev_priv, obj->size);
 	}
-	i915_verify_inactive(dev, __FILE__, __LINE__);
+	WARN_ON(i915_verify_lists(dev));
 }
 
 int
@@ -4115,17 +4231,20 @@
 	struct drm_i915_gem_object *obj_priv;
 	int ret;
 
-	mutex_lock(&dev->struct_mutex);
-
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
 		DRM_ERROR("Bad handle in i915_gem_pin_ioctl(): %d\n",
 			  args->handle);
-		mutex_unlock(&dev->struct_mutex);
 		return -ENOENT;
 	}
 	obj_priv = to_intel_bo(obj);
 
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
+	}
+
 	if (obj_priv->madv != I915_MADV_WILLNEED) {
 		DRM_ERROR("Attempting to pin a purgeable buffer\n");
 		drm_gem_object_unreference(obj);
@@ -4170,18 +4289,23 @@
 	struct drm_i915_gem_pin *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
-
-	mutex_lock(&dev->struct_mutex);
+	int ret;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
 		DRM_ERROR("Bad handle in i915_gem_unpin_ioctl(): %d\n",
 			  args->handle);
-		mutex_unlock(&dev->struct_mutex);
 		return -ENOENT;
 	}
 
 	obj_priv = to_intel_bo(obj);
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
+	}
+
 	if (obj_priv->pin_filp != file_priv) {
 		DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
 			  args->handle);
@@ -4207,6 +4331,7 @@
 	struct drm_i915_gem_busy *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
+	int ret;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL) {
@@ -4215,7 +4340,11 @@
 		return -ENOENT;
 	}
 
-	mutex_lock(&dev->struct_mutex);
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
+	}
 
 	/* Count all active objects as busy, even if they are currently not used
 	 * by the gpu. Users of this interface expect objects to eventually
@@ -4230,10 +4359,10 @@
 		 * use this buffer rather sooner than later, so issuing the required
 		 * flush earlier is beneficial.
 		 */
-		if (obj->write_domain) {
-			i915_gem_flush(dev, 0, obj->write_domain);
-			(void)i915_add_request(dev, file_priv, obj->write_domain, obj_priv->ring);
-		}
+		if (obj->write_domain & I915_GEM_GPU_DOMAINS)
+			i915_gem_flush_ring(dev, file_priv,
+					    obj_priv->ring,
+					    0, obj->write_domain);
 
 		/* Update the active list for the hardware's current position.
 		 * Otherwise this only updates on a delayed timer or when irqs
@@ -4264,6 +4393,7 @@
 	struct drm_i915_gem_madvise *args = data;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
+	int ret;
 
 	switch (args->madv) {
 	case I915_MADV_DONTNEED:
@@ -4279,10 +4409,14 @@
 			  args->handle);
 		return -ENOENT;
 	}
-
-	mutex_lock(&dev->struct_mutex);
 	obj_priv = to_intel_bo(obj);
 
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ret;
+	}
+
 	if (obj_priv->pin_count) {
 		drm_gem_object_unreference(obj);
 		mutex_unlock(&dev->struct_mutex);
@@ -4310,6 +4444,7 @@
 struct drm_gem_object * i915_gem_alloc_object(struct drm_device *dev,
 					      size_t size)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj;
 
 	obj = kzalloc(sizeof(*obj), GFP_KERNEL);
@@ -4321,6 +4456,8 @@
 		return NULL;
 	}
 
+	i915_gem_info_add_obj(dev_priv, size);
+
 	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
 	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
 
@@ -4361,6 +4498,7 @@
 		i915_gem_free_mmap_offset(obj);
 
 	drm_gem_object_release(obj);
+	i915_gem_info_remove_obj(dev_priv, obj->size);
 
 	kfree(obj_priv->page_cpu_valid);
 	kfree(obj_priv->bit_17);
@@ -4419,7 +4557,7 @@
 	 * And not confound mm.suspended!
 	 */
 	dev_priv->mm.suspended = 1;
-	del_timer(&dev_priv->hangcheck_timer);
+	del_timer_sync(&dev_priv->hangcheck_timer);
 
 	i915_kernel_lost_context(dev);
 	i915_gem_cleanup_ringbuffer(dev);
@@ -4499,28 +4637,18 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret;
 
-	dev_priv->render_ring = render_ring;
-
-	if (!I915_NEED_GFX_HWS(dev)) {
-		dev_priv->render_ring.status_page.page_addr
-			= dev_priv->status_page_dmah->vaddr;
-		memset(dev_priv->render_ring.status_page.page_addr,
-				0, PAGE_SIZE);
-	}
-
 	if (HAS_PIPE_CONTROL(dev)) {
 		ret = i915_gem_init_pipe_control(dev);
 		if (ret)
 			return ret;
 	}
 
-	ret = intel_init_ring_buffer(dev, &dev_priv->render_ring);
+	ret = intel_init_render_ring_buffer(dev);
 	if (ret)
 		goto cleanup_pipe_control;
 
 	if (HAS_BSD(dev)) {
-		dev_priv->bsd_ring = bsd_ring;
-		ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+		ret = intel_init_bsd_ring_buffer(dev);
 		if (ret)
 			goto cleanup_render_ring;
 	}
@@ -4573,11 +4701,8 @@
 		return ret;
 	}
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	BUG_ON(!list_empty(&dev_priv->render_ring.active_list));
 	BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list));
-	spin_unlock(&dev_priv->mm.active_list_lock);
-
 	BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
 	BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
 	BUG_ON(!list_empty(&dev_priv->render_ring.request_list));
@@ -4629,10 +4754,10 @@
 	int i;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 
-	spin_lock_init(&dev_priv->mm.active_list_lock);
 	INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
 	INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
 	INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+	INIT_LIST_HEAD(&dev_priv->mm.pinned_list);
 	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
 	INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
 	INIT_LIST_HEAD(&dev_priv->render_ring.active_list);
@@ -4645,6 +4770,7 @@
 		INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
 	INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
 			  i915_gem_retire_work_handler);
+	init_completion(&dev_priv->error_completion);
 	spin_lock(&shrink_list_lock);
 	list_add(&dev_priv->mm.shrink_list, &shrink_list);
 	spin_unlock(&shrink_list_lock);
@@ -4663,21 +4789,30 @@
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		dev_priv->fence_reg_start = 3;
 
-	if (IS_I965G(dev) || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+	if (INTEL_INFO(dev)->gen >= 4 || IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
 		dev_priv->num_fence_regs = 16;
 	else
 		dev_priv->num_fence_regs = 8;
 
 	/* Initialize fence registers to zero */
-	if (IS_I965G(dev)) {
+	switch (INTEL_INFO(dev)->gen) {
+	case 6:
+		for (i = 0; i < 16; i++)
+			I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
+		break;
+	case 5:
+	case 4:
 		for (i = 0; i < 16; i++)
 			I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
-	} else {
-		for (i = 0; i < 8; i++)
-			I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+		break;
+	case 3:
 		if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
 			for (i = 0; i < 8; i++)
 				I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
+	case 2:
+		for (i = 0; i < 8; i++)
+			I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
+		break;
 	}
 	i915_gem_detect_bit_6_swizzle(dev);
 	init_waitqueue_head(&dev_priv->pending_flip_queue);
@@ -4687,8 +4822,8 @@
  * Create a physically contiguous memory object for this object
  * e.g. for cursor + overlay regs
  */
-int i915_gem_init_phys_object(struct drm_device *dev,
-			      int id, int size, int align)
+static int i915_gem_init_phys_object(struct drm_device *dev,
+				     int id, int size, int align)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_phys_object *phys_obj;
@@ -4720,7 +4855,7 @@
 	return ret;
 }
 
-void i915_gem_free_phys_object(struct drm_device *dev, int id)
+static void i915_gem_free_phys_object(struct drm_device *dev, int id)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_gem_phys_object *phys_obj;
@@ -4865,18 +5000,25 @@
 	return 0;
 }
 
-void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
+void i915_gem_release(struct drm_device *dev, struct drm_file *file)
 {
-	struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
 
 	/* Clean up our request list when the client is going away, so that
 	 * later retire_requests won't dereference our soon-to-be-gone
 	 * file_priv.
 	 */
-	mutex_lock(&dev->struct_mutex);
-	while (!list_empty(&i915_file_priv->mm.request_list))
-		list_del_init(i915_file_priv->mm.request_list.next);
-	mutex_unlock(&dev->struct_mutex);
+	spin_lock(&file_priv->mm.lock);
+	while (!list_empty(&file_priv->mm.request_list)) {
+		struct drm_i915_gem_request *request;
+
+		request = list_first_entry(&file_priv->mm.request_list,
+					   struct drm_i915_gem_request,
+					   client_list);
+		list_del(&request->client_list);
+		request->file_priv = NULL;
+	}
+	spin_unlock(&file_priv->mm.lock);
 }
 
 static int
@@ -4885,12 +5027,10 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int lists_empty;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
 		      list_empty(&dev_priv->render_ring.active_list);
 	if (HAS_BSD(dev))
 		lists_empty &= list_empty(&dev_priv->bsd_ring.active_list);
-	spin_unlock(&dev_priv->mm.active_list_lock);
 
 	return !lists_empty;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
index 80f380b..48644b8 100644
--- a/drivers/gpu/drm/i915/i915_gem_debug.c
+++ b/drivers/gpu/drm/i915/i915_gem_debug.c
@@ -30,29 +30,112 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-#if WATCH_INACTIVE
-void
-i915_verify_inactive(struct drm_device *dev, char *file, int line)
+#if WATCH_LISTS
+int
+i915_verify_lists(struct drm_device *dev)
 {
+	static int warned;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	struct drm_gem_object *obj;
-	struct drm_i915_gem_object *obj_priv;
+	struct drm_i915_gem_object *obj;
+	int err = 0;
 
-	list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-		obj = &obj_priv->base;
-		if (obj_priv->pin_count || obj_priv->active ||
-		    (obj->write_domain & ~(I915_GEM_DOMAIN_CPU |
-					   I915_GEM_DOMAIN_GTT)))
-			DRM_ERROR("inactive %p (p %d a %d w %x)  %s:%d\n",
+	if (warned)
+		return 0;
+
+	list_for_each_entry(obj, &dev_priv->render_ring.active_list, list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed render active %p\n", obj);
+			err++;
+			break;
+		} else if (!obj->active ||
+			   (obj->base.read_domains & I915_GEM_GPU_DOMAINS) == 0) {
+			DRM_ERROR("invalid render active %p (a %d r %x)\n",
 				  obj,
-				  obj_priv->pin_count, obj_priv->active,
-				  obj->write_domain, file, line);
+				  obj->active,
+				  obj->base.read_domains);
+			err++;
+		} else if (obj->base.write_domain && list_empty(&obj->gpu_write_list)) {
+			DRM_ERROR("invalid render active %p (w %x, gwl %d)\n",
+				  obj,
+				  obj->base.write_domain,
+				  !list_empty(&obj->gpu_write_list));
+			err++;
+		}
 	}
+
+	list_for_each_entry(obj, &dev_priv->mm.flushing_list, list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed flushing %p\n", obj);
+			err++;
+			break;
+		} else if (!obj->active ||
+			   (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0 ||
+			   list_empty(&obj->gpu_write_list)){
+			DRM_ERROR("invalid flushing %p (a %d w %x gwl %d)\n",
+				  obj,
+				  obj->active,
+				  obj->base.write_domain,
+				  !list_empty(&obj->gpu_write_list));
+			err++;
+		}
+	}
+
+	list_for_each_entry(obj, &dev_priv->mm.gpu_write_list, gpu_write_list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed gpu write %p\n", obj);
+			err++;
+			break;
+		} else if (!obj->active ||
+			   (obj->base.write_domain & I915_GEM_GPU_DOMAINS) == 0) {
+			DRM_ERROR("invalid gpu write %p (a %d w %x)\n",
+				  obj,
+				  obj->active,
+				  obj->base.write_domain);
+			err++;
+		}
+	}
+
+	list_for_each_entry(obj, &dev_priv->mm.inactive_list, list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed inactive %p\n", obj);
+			err++;
+			break;
+		} else if (obj->pin_count || obj->active ||
+			   (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+			DRM_ERROR("invalid inactive %p (p %d a %d w %x)\n",
+				  obj,
+				  obj->pin_count, obj->active,
+				  obj->base.write_domain);
+			err++;
+		}
+	}
+
+	list_for_each_entry(obj, &dev_priv->mm.pinned_list, list) {
+		if (obj->base.dev != dev ||
+		    !atomic_read(&obj->base.refcount.refcount)) {
+			DRM_ERROR("freed pinned %p\n", obj);
+			err++;
+			break;
+		} else if (!obj->pin_count || obj->active ||
+			   (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
+			DRM_ERROR("invalid pinned %p (p %d a %d w %x)\n",
+				  obj,
+				  obj->pin_count, obj->active,
+				  obj->base.write_domain);
+			err++;
+		}
+	}
+
+	return warned = err;
 }
 #endif /* WATCH_INACTIVE */
 
 
-#if WATCH_BUF | WATCH_EXEC | WATCH_PWRITE
+#if WATCH_EXEC | WATCH_PWRITE
 static void
 i915_gem_dump_page(struct page *page, uint32_t start, uint32_t end,
 		   uint32_t bias, uint32_t mark)
@@ -97,41 +180,6 @@
 }
 #endif
 
-#if WATCH_LRU
-void
-i915_dump_lru(struct drm_device *dev, const char *where)
-{
-	drm_i915_private_t		*dev_priv = dev->dev_private;
-	struct drm_i915_gem_object	*obj_priv;
-
-	DRM_INFO("active list %s {\n", where);
-	spin_lock(&dev_priv->mm.active_list_lock);
-	list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
-			    list)
-	{
-		DRM_INFO("    %p: %08x\n", obj_priv,
-			 obj_priv->last_rendering_seqno);
-	}
-	spin_unlock(&dev_priv->mm.active_list_lock);
-	DRM_INFO("}\n");
-	DRM_INFO("flushing list %s {\n", where);
-	list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
-			    list)
-	{
-		DRM_INFO("    %p: %08x\n", obj_priv,
-			 obj_priv->last_rendering_seqno);
-	}
-	DRM_INFO("}\n");
-	DRM_INFO("inactive %s {\n", where);
-	list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-		DRM_INFO("    %p: %08x\n", obj_priv,
-			 obj_priv->last_rendering_seqno);
-	}
-	DRM_INFO("}\n");
-}
-#endif
-
-
 #if WATCH_COHERENCY
 void
 i915_gem_object_check_coherency(struct drm_gem_object *obj, int handle)
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index e85246e..3d7fbf3 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -93,7 +93,7 @@
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct list_head eviction_list, unwind_list;
-	struct drm_i915_gem_object *obj_priv, *tmp_obj_priv;
+	struct drm_i915_gem_object *obj_priv;
 	struct list_head *render_iter, *bsd_iter;
 	int ret = 0;
 
@@ -175,39 +175,34 @@
 	return -ENOSPC;
 
 found:
+	/* drm_mm doesn't allow any other other operations while
+	 * scanning, therefore store to be evicted objects on a
+	 * temporary list. */
 	INIT_LIST_HEAD(&eviction_list);
-	list_for_each_entry_safe(obj_priv, tmp_obj_priv,
-				 &unwind_list, evict_list) {
+	while (!list_empty(&unwind_list)) {
+		obj_priv = list_first_entry(&unwind_list,
+					    struct drm_i915_gem_object,
+					    evict_list);
 		if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
-			/* drm_mm doesn't allow any other other operations while
-			 * scanning, therefore store to be evicted objects on a
-			 * temporary list. */
 			list_move(&obj_priv->evict_list, &eviction_list);
-		} else
-			drm_gem_object_unreference(&obj_priv->base);
-	}
-
-	/* Unbinding will emit any required flushes */
-	list_for_each_entry_safe(obj_priv, tmp_obj_priv,
-				 &eviction_list, evict_list) {
-#if WATCH_LRU
-		DRM_INFO("%s: evicting %p\n", __func__, &obj_priv->base);
-#endif
-		ret = i915_gem_object_unbind(&obj_priv->base);
-		if (ret)
-			return ret;
-
+			continue;
+		}
+		list_del(&obj_priv->evict_list);
 		drm_gem_object_unreference(&obj_priv->base);
 	}
 
-	/* The just created free hole should be on the top of the free stack
-	 * maintained by drm_mm, so this BUG_ON actually executes in O(1).
-	 * Furthermore all accessed data has just recently been used, so it
-	 * should be really fast, too. */
-	BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size,
-				   alignment, 0));
+	/* Unbinding will emit any required flushes */
+	while (!list_empty(&eviction_list)) {
+		obj_priv = list_first_entry(&eviction_list,
+					    struct drm_i915_gem_object,
+					    evict_list);
+		if (ret == 0)
+			ret = i915_gem_object_unbind(&obj_priv->base);
+		list_del(&obj_priv->evict_list);
+		drm_gem_object_unreference(&obj_priv->base);
+	}
 
-	return 0;
+	return ret;
 }
 
 int
@@ -217,14 +212,11 @@
 	int ret;
 	bool lists_empty;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
 		       list_empty(&dev_priv->mm.flushing_list) &&
 		       list_empty(&dev_priv->render_ring.active_list) &&
 		       (!HAS_BSD(dev)
 			|| list_empty(&dev_priv->bsd_ring.active_list)));
-	spin_unlock(&dev_priv->mm.active_list_lock);
-
 	if (lists_empty)
 		return -ENOSPC;
 
@@ -239,13 +231,11 @@
 	if (ret)
 		return ret;
 
-	spin_lock(&dev_priv->mm.active_list_lock);
 	lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
 		       list_empty(&dev_priv->mm.flushing_list) &&
 		       list_empty(&dev_priv->render_ring.active_list) &&
 		       (!HAS_BSD(dev)
 			|| list_empty(&dev_priv->bsd_ring.active_list)));
-	spin_unlock(&dev_priv->mm.active_list_lock);
 	BUG_ON(!lists_empty);
 
 	return 0;
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 710eca7..8c9ffc4 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -98,7 +98,7 @@
 		 */
 		swizzle_x = I915_BIT_6_SWIZZLE_9_10;
 		swizzle_y = I915_BIT_6_SWIZZLE_9;
-	} else if (!IS_I9XX(dev)) {
+	} else if (IS_GEN2(dev)) {
 		/* As far as we know, the 865 doesn't have these bit 6
 		 * swizzling issues.
 		 */
@@ -190,19 +190,19 @@
 	if (tiling_mode == I915_TILING_NONE)
 		return true;
 
-	if (!IS_I9XX(dev) ||
+	if (IS_GEN2(dev) ||
 	    (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
 		tile_width = 128;
 	else
 		tile_width = 512;
 
 	/* check maximum stride & object size */
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		/* i965 stores the end address of the gtt mapping in the fence
 		 * reg, so dont bother to check the size */
 		if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
 			return false;
-	} else if (IS_GEN3(dev) || IS_GEN2(dev)) {
+	} else {
 		if (stride > 8192)
 			return false;
 
@@ -216,7 +216,7 @@
 	}
 
 	/* 965+ just needs multiples of tile width */
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		if (stride & (tile_width - 1))
 			return false;
 		return true;
@@ -244,16 +244,18 @@
 	if (tiling_mode == I915_TILING_NONE)
 		return true;
 
-	if (!IS_I965G(dev)) {
-		if (obj_priv->gtt_offset & (obj->size - 1))
+	if (INTEL_INFO(dev)->gen >= 4)
+		return true;
+
+	if (obj_priv->gtt_offset & (obj->size - 1))
+		return false;
+
+	if (IS_GEN3(dev)) {
+		if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
 			return false;
-		if (IS_I9XX(dev)) {
-			if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK)
-				return false;
-		} else {
-			if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
-				return false;
-		}
+	} else {
+		if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK)
+			return false;
 	}
 
 	return true;
@@ -271,7 +273,11 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_gem_object *obj;
 	struct drm_i915_gem_object *obj_priv;
-	int ret = 0;
+	int ret;
+
+	ret = i915_gem_check_is_wedged(dev);
+	if (ret)
+		return ret;
 
 	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
 	if (obj == NULL)
@@ -328,7 +334,7 @@
 		if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode))
 			ret = i915_gem_object_unbind(obj);
 		else if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
-			ret = i915_gem_object_put_fence_reg(obj);
+			ret = i915_gem_object_put_fence_reg(obj, true);
 		else
 			i915_gem_release_mmap(obj);
 
@@ -399,16 +405,14 @@
  * bit 17 of its physical address and therefore being interpreted differently
  * by the GPU.
  */
-static int
+static void
 i915_gem_swizzle_page(struct page *page)
 {
+	char temp[64];
 	char *vaddr;
 	int i;
-	char temp[64];
 
 	vaddr = kmap(page);
-	if (vaddr == NULL)
-		return -ENOMEM;
 
 	for (i = 0; i < PAGE_SIZE; i += 128) {
 		memcpy(temp, &vaddr[i], 64);
@@ -417,8 +421,6 @@
 	}
 
 	kunmap(page);
-
-	return 0;
 }
 
 void
@@ -440,11 +442,7 @@
 		char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17;
 		if ((new_bit_17 & 0x1) !=
 		    (test_bit(i, obj_priv->bit_17) != 0)) {
-			int ret = i915_gem_swizzle_page(obj_priv->pages[i]);
-			if (ret != 0) {
-				DRM_ERROR("Failed to swizzle page\n");
-				return;
-			}
+			i915_gem_swizzle_page(obj_priv->pages[i]);
 			set_page_dirty(obj_priv->pages[i]);
 		}
 	}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 744225e..64c07c2 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -85,7 +85,7 @@
 }
 
 /* For display hotplug interrupt */
-void
+static void
 ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 {
 	if ((dev_priv->irq_mask_reg & mask) != 0) {
@@ -172,7 +172,7 @@
 	else {
 		i915_enable_pipestat(dev_priv, 1,
 				     PIPE_LEGACY_BLC_EVENT_ENABLE);
-		if (IS_I965G(dev))
+		if (INTEL_INFO(dev)->gen >= 4)
 			i915_enable_pipestat(dev_priv, 0,
 					     PIPE_LEGACY_BLC_EVENT_ENABLE);
 	}
@@ -191,12 +191,7 @@
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-	unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
-
-	if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
-		return 1;
-
-	return 0;
+	return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
 }
 
 /* Called from drm generic code, passed a 'crtc', which
@@ -207,10 +202,7 @@
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long high_frame;
 	unsigned long low_frame;
-	u32 high1, high2, low, count;
-
-	high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
-	low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+	u32 high1, high2, low;
 
 	if (!i915_pipe_enabled(dev, pipe)) {
 		DRM_DEBUG_DRIVER("trying to get vblank count for disabled "
@@ -218,23 +210,23 @@
 		return 0;
 	}
 
+	high_frame = pipe ? PIPEBFRAMEHIGH : PIPEAFRAMEHIGH;
+	low_frame = pipe ? PIPEBFRAMEPIXEL : PIPEAFRAMEPIXEL;
+
 	/*
 	 * High & low register fields aren't synchronized, so make sure
 	 * we get a low value that's stable across two reads of the high
 	 * register.
 	 */
 	do {
-		high1 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-			 PIPE_FRAME_HIGH_SHIFT);
-		low =  ((I915_READ(low_frame) & PIPE_FRAME_LOW_MASK) >>
-			PIPE_FRAME_LOW_SHIFT);
-		high2 = ((I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK) >>
-			 PIPE_FRAME_HIGH_SHIFT);
+		high1 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
+		low   = I915_READ(low_frame)  & PIPE_FRAME_LOW_MASK;
+		high2 = I915_READ(high_frame) & PIPE_FRAME_HIGH_MASK;
 	} while (high1 != high2);
 
-	count = (high1 << 8) | low;
-
-	return count;
+	high1 >>= PIPE_FRAME_HIGH_SHIFT;
+	low >>= PIPE_FRAME_LOW_SHIFT;
+	return (high1 << 8) | low;
 }
 
 u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
@@ -260,16 +252,12 @@
 						    hotplug_work);
 	struct drm_device *dev = dev_priv->dev;
 	struct drm_mode_config *mode_config = &dev->mode_config;
-	struct drm_encoder *encoder;
+	struct intel_encoder *encoder;
 
-	if (mode_config->num_encoder) {
-		list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-			struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-	
-			if (intel_encoder->hot_plug)
-				(*intel_encoder->hot_plug) (intel_encoder);
-		}
-	}
+	list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+		if (encoder->hot_plug)
+			encoder->hot_plug(encoder);
+
 	/* Just fire off a uevent and let userspace tell us what to do */
 	drm_helper_hpd_irq_event(dev);
 }
@@ -305,13 +293,17 @@
 	return;
 }
 
-irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	int ret = IRQ_NONE;
 	u32 de_iir, gt_iir, de_ier, pch_iir;
 	struct drm_i915_master_private *master_priv;
 	struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
+	u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
+
+	if (IS_GEN6(dev))
+		bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
 
 	/* disable master interrupt before clearing iir  */
 	de_ier = I915_READ(DEIER);
@@ -335,28 +327,28 @@
 	}
 
 	if (gt_iir & GT_PIPE_NOTIFY) {
-		u32 seqno = render_ring->get_gem_seqno(dev, render_ring);
+		u32 seqno = render_ring->get_seqno(dev, render_ring);
 		render_ring->irq_gem_seqno = seqno;
 		trace_i915_gem_request_complete(dev, seqno);
-		DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+		wake_up_all(&dev_priv->render_ring.irq_queue);
 		dev_priv->hangcheck_count = 0;
-		mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+		mod_timer(&dev_priv->hangcheck_timer,
+			  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 	}
-	if (gt_iir & GT_BSD_USER_INTERRUPT)
-		DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
-
+	if (gt_iir & bsd_usr_interrupt)
+		wake_up_all(&dev_priv->bsd_ring.irq_queue);
 
 	if (de_iir & DE_GSE)
-		ironlake_opregion_gse_intr(dev);
+		intel_opregion_gse_intr(dev);
 
 	if (de_iir & DE_PLANEA_FLIP_DONE) {
 		intel_prepare_page_flip(dev, 0);
-		intel_finish_page_flip(dev, 0);
+		intel_finish_page_flip_plane(dev, 0);
 	}
 
 	if (de_iir & DE_PLANEB_FLIP_DONE) {
 		intel_prepare_page_flip(dev, 1);
-		intel_finish_page_flip(dev, 1);
+		intel_finish_page_flip_plane(dev, 1);
 	}
 
 	if (de_iir & DE_PIPEA_VBLANK)
@@ -404,23 +396,20 @@
 	char *reset_event[] = { "RESET=1", NULL };
 	char *reset_done_event[] = { "ERROR=0", NULL };
 
-	DRM_DEBUG_DRIVER("generating error event\n");
 	kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, error_event);
 
 	if (atomic_read(&dev_priv->mm.wedged)) {
-		if (IS_I965G(dev)) {
-			DRM_DEBUG_DRIVER("resetting chip\n");
-			kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
-			if (!i965_reset(dev, GDRST_RENDER)) {
-				atomic_set(&dev_priv->mm.wedged, 0);
-				kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
-			}
-		} else {
-			DRM_DEBUG_DRIVER("reboot required\n");
+		DRM_DEBUG_DRIVER("resetting chip\n");
+		kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
+		if (!i915_reset(dev, GRDOM_RENDER)) {
+			atomic_set(&dev_priv->mm.wedged, 0);
+			kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
 		}
+		complete_all(&dev_priv->error_completion);
 	}
 }
 
+#ifdef CONFIG_DEBUG_FS
 static struct drm_i915_error_object *
 i915_error_object_create(struct drm_device *dev,
 			 struct drm_gem_object *src)
@@ -511,7 +500,7 @@
 
 	if (IS_I830(dev) || IS_845G(dev))
 		cmd = MI_BATCH_BUFFER;
-	else if (IS_I965G(dev))
+	else if (INTEL_INFO(dev)->gen >= 4)
 		cmd = (MI_BATCH_BUFFER_START | (2 << 6) |
 		       MI_BATCH_NON_SECURE_I965);
 	else
@@ -584,13 +573,16 @@
 		return;
 	}
 
-	error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring);
+	DRM_DEBUG_DRIVER("generating error event\n");
+
+	error->seqno =
+		dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring);
 	error->eir = I915_READ(EIR);
 	error->pgtbl_er = I915_READ(PGTBL_ER);
 	error->pipeastat = I915_READ(PIPEASTAT);
 	error->pipebstat = I915_READ(PIPEBSTAT);
 	error->instpm = I915_READ(INSTPM);
-	if (!IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen < 4) {
 		error->ipeir = I915_READ(IPEIR);
 		error->ipehr = I915_READ(IPEHR);
 		error->instdone = I915_READ(INSTDONE);
@@ -744,6 +736,9 @@
 	if (error)
 		i915_error_state_free(dev, error);
 }
+#else
+#define i915_capture_error_state(x)
+#endif
 
 static void i915_report_and_clear_eir(struct drm_device *dev)
 {
@@ -785,7 +780,7 @@
 		}
 	}
 
-	if (IS_I9XX(dev)) {
+	if (!IS_GEN2(dev)) {
 		if (eir & I915_ERROR_PAGE_TABLE) {
 			u32 pgtbl_err = I915_READ(PGTBL_ER);
 			printk(KERN_ERR "page table error\n");
@@ -811,7 +806,7 @@
 		printk(KERN_ERR "instruction error\n");
 		printk(KERN_ERR "  INSTPM: 0x%08x\n",
 		       I915_READ(INSTPM));
-		if (!IS_I965G(dev)) {
+		if (INTEL_INFO(dev)->gen < 4) {
 			u32 ipeir = I915_READ(IPEIR);
 
 			printk(KERN_ERR "  IPEIR: 0x%08x\n",
@@ -876,12 +871,15 @@
 	i915_report_and_clear_eir(dev);
 
 	if (wedged) {
+		INIT_COMPLETION(dev_priv->error_completion);
 		atomic_set(&dev_priv->mm.wedged, 1);
 
 		/*
 		 * Wakeup waiting processes so they don't hang
 		 */
-		DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+		wake_up_all(&dev_priv->render_ring.irq_queue);
+		if (HAS_BSD(dev))
+			wake_up_all(&dev_priv->bsd_ring.irq_queue);
 	}
 
 	queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -912,7 +910,7 @@
 
 	/* Potential stall - if we see that the flip has happened, assume a missed interrupt */
 	obj_priv = to_intel_bo(work->pending_flip_obj);
-	if(IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		int dspsurf = intel_crtc->plane == 0 ? DSPASURF : DSPBSURF;
 		stall_detected = I915_READ(dspsurf) == obj_priv->gtt_offset;
 	} else {
@@ -951,7 +949,7 @@
 
 	iir = I915_READ(IIR);
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS;
 	else
 		vblank_status = PIPE_VBLANK_INTERRUPT_STATUS;
@@ -1020,17 +1018,17 @@
 		}
 
 		if (iir & I915_USER_INTERRUPT) {
-			u32 seqno =
-				render_ring->get_gem_seqno(dev, render_ring);
+			u32 seqno = render_ring->get_seqno(dev, render_ring);
 			render_ring->irq_gem_seqno = seqno;
 			trace_i915_gem_request_complete(dev, seqno);
-			DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+			wake_up_all(&dev_priv->render_ring.irq_queue);
 			dev_priv->hangcheck_count = 0;
-			mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+			mod_timer(&dev_priv->hangcheck_timer,
+				  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 		}
 
 		if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
-			DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+			wake_up_all(&dev_priv->bsd_ring.irq_queue);
 
 		if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
 			intel_prepare_page_flip(dev, 0);
@@ -1065,7 +1063,7 @@
 		if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
 		    (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) ||
 		    (iir & I915_ASLE_INTERRUPT))
-			opregion_asle_intr(dev);
+			intel_opregion_asle_intr(dev);
 
 		/* With MSI, interrupts are only generated when iir
 		 * transitions from zero to nonzero.  If another bit got
@@ -1207,18 +1205,15 @@
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long irqflags;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	u32 pipeconf;
 
-	pipeconf = I915_READ(pipeconf_reg);
-	if (!(pipeconf & PIPEACONF_ENABLE))
+	if (!i915_pipe_enabled(dev, pipe))
 		return -EINVAL;
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	if (HAS_PCH_SPLIT(dev))
 		ironlake_enable_display_irq(dev_priv, (pipe == 0) ? 
 					    DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
-	else if (IS_I965G(dev))
+	else if (INTEL_INFO(dev)->gen >= 4)
 		i915_enable_pipestat(dev_priv, pipe,
 				     PIPE_START_VBLANK_INTERRUPT_ENABLE);
 	else
@@ -1252,7 +1247,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (!HAS_PCH_SPLIT(dev))
-		opregion_enable_asle(dev);
+		intel_opregion_enable_asle(dev);
 	dev_priv->irq_enabled = 1;
 }
 
@@ -1311,7 +1306,7 @@
 	return -EINVAL;
 }
 
-struct drm_i915_gem_request *
+static struct drm_i915_gem_request *
 i915_get_tail_request(struct drm_device *dev)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -1331,11 +1326,7 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	uint32_t acthd, instdone, instdone1;
 
-	/* No reset support on this chip yet. */
-	if (IS_GEN6(dev))
-		return;
-
-	if (!IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen < 4) {
 		acthd = I915_READ(ACTHD);
 		instdone = I915_READ(INSTDONE);
 		instdone1 = 0;
@@ -1347,9 +1338,8 @@
 
 	/* If all work is done then ACTHD clearly hasn't advanced. */
 	if (list_empty(&dev_priv->render_ring.request_list) ||
-		i915_seqno_passed(i915_get_gem_seqno(dev,
-				&dev_priv->render_ring),
-			i915_get_tail_request(dev)->seqno)) {
+		i915_seqno_passed(dev_priv->render_ring.get_seqno(dev, &dev_priv->render_ring),
+				  i915_get_tail_request(dev)->seqno)) {
 		bool missed_wakeup = false;
 
 		dev_priv->hangcheck_count = 0;
@@ -1357,13 +1347,13 @@
 		/* Issue a wake-up to catch stuck h/w. */
 		if (dev_priv->render_ring.waiting_gem_seqno &&
 		    waitqueue_active(&dev_priv->render_ring.irq_queue)) {
-			DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
+			wake_up_all(&dev_priv->render_ring.irq_queue);
 			missed_wakeup = true;
 		}
 
 		if (dev_priv->bsd_ring.waiting_gem_seqno &&
 		    waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
-			DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+			wake_up_all(&dev_priv->bsd_ring.irq_queue);
 			missed_wakeup = true;
 		}
 
@@ -1377,6 +1367,21 @@
 	    dev_priv->last_instdone1 == instdone1) {
 		if (dev_priv->hangcheck_count++ > 1) {
 			DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+
+			if (!IS_GEN2(dev)) {
+				/* Is the chip hanging on a WAIT_FOR_EVENT?
+				 * If so we can simply poke the RB_WAIT bit
+				 * and break the hang. This should work on
+				 * all but the second generation chipsets.
+				 */
+				u32 tmp = I915_READ(PRB0_CTL);
+				if (tmp & RING_WAIT) {
+					I915_WRITE(PRB0_CTL, tmp);
+					POSTING_READ(PRB0_CTL);
+					goto out;
+				}
+			}
+
 			i915_handle_error(dev, true);
 			return;
 		}
@@ -1388,8 +1393,10 @@
 		dev_priv->last_instdone1 = instdone1;
 	}
 
+out:
 	/* Reset timer case chip hangs without another request being added */
-	mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
+	mod_timer(&dev_priv->hangcheck_timer,
+		  jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
 }
 
 /* drm_dma.h hooks
@@ -1436,17 +1443,19 @@
 	I915_WRITE(DEIER, dev_priv->de_irq_enable_reg);
 	(void) I915_READ(DEIER);
 
-	/* Gen6 only needs render pipe_control now */
 	if (IS_GEN6(dev))
-		render_mask = GT_PIPE_NOTIFY;
+		render_mask = GT_PIPE_NOTIFY | GT_GEN6_BSD_USER_INTERRUPT;
 
 	dev_priv->gt_irq_mask_reg = ~render_mask;
 	dev_priv->gt_irq_enable_reg = render_mask;
 
 	I915_WRITE(GTIIR, I915_READ(GTIIR));
 	I915_WRITE(GTIMR, dev_priv->gt_irq_mask_reg);
-	if (IS_GEN6(dev))
+	if (IS_GEN6(dev)) {
 		I915_WRITE(GEN6_RENDER_IMR, ~GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT);
+		I915_WRITE(GEN6_BSD_IMR, ~GEN6_BSD_IMR_USER_INTERRUPT);
+	}
+
 	I915_WRITE(GTIER, dev_priv->gt_irq_enable_reg);
 	(void) I915_READ(GTIER);
 
@@ -1578,7 +1587,7 @@
 		I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
 	}
 
-	opregion_enable_asle(dev);
+	intel_opregion_enable_asle(dev);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 4f5e155..d02de21 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -25,52 +25,16 @@
 #ifndef _I915_REG_H_
 #define _I915_REG_H_
 
+#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
+
 /*
  * The Bridge device's PCI config space has information about the
  * fb aperture size and the amount of pre-reserved memory.
+ * This is all handled in the intel-gtt.ko module. i915.ko only
+ * cares about the vga bit for the vga rbiter.
  */
 #define INTEL_GMCH_CTRL		0x52
 #define INTEL_GMCH_VGA_DISABLE  (1 << 1)
-#define INTEL_GMCH_ENABLED	0x4
-#define INTEL_GMCH_MEM_MASK	0x1
-#define INTEL_GMCH_MEM_64M	0x1
-#define INTEL_GMCH_MEM_128M	0
-
-#define INTEL_GMCH_GMS_MASK		(0xf << 4)
-#define INTEL_855_GMCH_GMS_DISABLED	(0x0 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_1M	(0x1 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_4M	(0x2 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_8M	(0x3 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_16M	(0x4 << 4)
-#define INTEL_855_GMCH_GMS_STOLEN_32M	(0x5 << 4)
-
-#define INTEL_915G_GMCH_GMS_STOLEN_48M	(0x6 << 4)
-#define INTEL_915G_GMCH_GMS_STOLEN_64M	(0x7 << 4)
-#define INTEL_GMCH_GMS_STOLEN_128M	(0x8 << 4)
-#define INTEL_GMCH_GMS_STOLEN_256M	(0x9 << 4)
-#define INTEL_GMCH_GMS_STOLEN_96M	(0xa << 4)
-#define INTEL_GMCH_GMS_STOLEN_160M	(0xb << 4)
-#define INTEL_GMCH_GMS_STOLEN_224M	(0xc << 4)
-#define INTEL_GMCH_GMS_STOLEN_352M	(0xd << 4)
-
-#define SNB_GMCH_CTRL	0x50
-#define SNB_GMCH_GMS_STOLEN_MASK	0xF8
-#define SNB_GMCH_GMS_STOLEN_32M		(1 << 3)
-#define SNB_GMCH_GMS_STOLEN_64M		(2 << 3)
-#define SNB_GMCH_GMS_STOLEN_96M		(3 << 3)
-#define SNB_GMCH_GMS_STOLEN_128M	(4 << 3)
-#define SNB_GMCH_GMS_STOLEN_160M	(5 << 3)
-#define SNB_GMCH_GMS_STOLEN_192M	(6 << 3)
-#define SNB_GMCH_GMS_STOLEN_224M	(7 << 3)
-#define SNB_GMCH_GMS_STOLEN_256M	(8 << 3)
-#define SNB_GMCH_GMS_STOLEN_288M	(9 << 3)
-#define SNB_GMCH_GMS_STOLEN_320M	(0xa << 3)
-#define SNB_GMCH_GMS_STOLEN_352M	(0xb << 3)
-#define SNB_GMCH_GMS_STOLEN_384M	(0xc << 3)
-#define SNB_GMCH_GMS_STOLEN_416M	(0xd << 3)
-#define SNB_GMCH_GMS_STOLEN_448M	(0xe << 3)
-#define SNB_GMCH_GMS_STOLEN_480M	(0xf << 3)
-#define SNB_GMCH_GMS_STOLEN_512M	(0x10 << 3)
 
 /* PCI config space */
 
@@ -106,10 +70,13 @@
 #define   I915_GC_RENDER_CLOCK_200_MHZ	(1 << 0)
 #define   I915_GC_RENDER_CLOCK_333_MHZ	(4 << 0)
 #define LBB	0xf4
-#define GDRST 0xc0
-#define  GDRST_FULL	(0<<2)
-#define  GDRST_RENDER	(1<<2)
-#define  GDRST_MEDIA	(3<<2)
+
+/* Graphics reset regs */
+#define I965_GDRST 0xc0 /* PCI config register */
+#define ILK_GDSR 0x2ca4 /* MCHBAR offset */
+#define  GRDOM_FULL	(0<<2)
+#define  GRDOM_RENDER	(1<<2)
+#define  GRDOM_MEDIA	(3<<2)
 
 /* VGA stuff */
 
@@ -192,11 +159,11 @@
 #define MI_STORE_DWORD_INDEX	MI_INSTR(0x21, 1)
 #define   MI_STORE_DWORD_INDEX_SHIFT 2
 #define MI_LOAD_REGISTER_IMM	MI_INSTR(0x22, 1)
+#define MI_FLUSH_DW		MI_INSTR(0x26, 2) /* for GEN6 */
 #define MI_BATCH_BUFFER		MI_INSTR(0x30, 1)
 #define   MI_BATCH_NON_SECURE	(1)
 #define   MI_BATCH_NON_SECURE_I965 (1<<8)
 #define MI_BATCH_BUFFER_START	MI_INSTR(0x31, 0)
-
 /*
  * 3D instructions used by the kernel
  */
@@ -249,6 +216,16 @@
 #define   PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
 #define   PIPE_CONTROL_STALL_EN	(1<<1) /* in addr word, Ironlake+ only */
 
+
+/*
+ * Reset registers
+ */
+#define DEBUG_RESET_I830		0x6070
+#define  DEBUG_RESET_FULL		(1<<7)
+#define  DEBUG_RESET_RENDER		(1<<8)
+#define  DEBUG_RESET_DISPLAY		(1<<9)
+
+
 /*
  * Fence registers
  */
@@ -283,6 +260,16 @@
 #define PRB0_HEAD	0x02034
 #define PRB0_START	0x02038
 #define PRB0_CTL	0x0203c
+#define RENDER_RING_BASE	0x02000
+#define BSD_RING_BASE		0x04000
+#define GEN6_BSD_RING_BASE	0x12000
+#define RING_TAIL(base)		((base)+0x30)
+#define RING_HEAD(base)		((base)+0x34)
+#define RING_START(base)	((base)+0x38)
+#define RING_CTL(base)		((base)+0x3c)
+#define RING_HWS_PGA(base)	((base)+0x80)
+#define RING_HWS_PGA_GEN6(base)	((base)+0x2080)
+#define RING_ACTHD(base)	((base)+0x74)
 #define   TAIL_ADDR		0x001FFFF8
 #define   HEAD_WRAP_COUNT	0xFFE00000
 #define   HEAD_WRAP_ONE		0x00200000
@@ -295,6 +282,8 @@
 #define   RING_VALID_MASK	0x00000001
 #define   RING_VALID		0x00000001
 #define   RING_INVALID		0x00000000
+#define   RING_WAIT_I8XX	(1<<0) /* gen2, PRBx_HEAD */
+#define   RING_WAIT		(1<<11) /* gen3+, PRBx_CTL */
 #define PRB1_TAIL	0x02040 /* 915+ only */
 #define PRB1_HEAD	0x02044 /* 915+ only */
 #define PRB1_START	0x02048 /* 915+ only */
@@ -306,7 +295,6 @@
 #define INSTDONE1	0x0207c /* 965+ only */
 #define ACTHD_I965	0x02074
 #define HWS_PGA		0x02080
-#define HWS_PGA_GEN6	0x04080
 #define HWS_ADDRESS_MASK	0xfffff000
 #define HWS_START_ADDRESS_SHIFT	4
 #define PWRCTXA		0x2088 /* 965GM+ only */
@@ -464,17 +452,17 @@
 #define   GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR	(1 << 25)
 #define   GEN6_BLITTER_SYNC_STATUS			(1 << 24)
 #define   GEN6_BLITTER_USER_INTERRUPT			(1 << 22)
-/*
- * BSD (bit stream decoder instruction and interrupt control register defines
- * (G4X and Ironlake only)
- */
 
-#define BSD_RING_TAIL          0x04030
-#define BSD_RING_HEAD          0x04034
-#define BSD_RING_START         0x04038
-#define BSD_RING_CTL           0x0403c
-#define BSD_RING_ACTHD         0x04074
-#define BSD_HWS_PGA            0x04080
+#define GEN6_BSD_SLEEP_PSMI_CONTROL	0x12050
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK	(1 << 16)
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE		(1 << 0)
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE		0
+#define   GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR			(1 << 3)
+
+#define GEN6_BSD_IMR			0x120a8
+#define   GEN6_BSD_IMR_USER_INTERRUPT	(1 << 12)
+
+#define GEN6_BSD_RNCID			0x12198
 
 /*
  * Framebuffer compression (915+ only)
@@ -579,12 +567,51 @@
 # define GPIO_DATA_VAL_IN		(1 << 12)
 # define GPIO_DATA_PULLUP_DISABLE	(1 << 13)
 
-#define GMBUS0			0x5100
-#define GMBUS1			0x5104
-#define GMBUS2			0x5108
-#define GMBUS3			0x510c
-#define GMBUS4			0x5110
-#define GMBUS5			0x5120
+#define GMBUS0			0x5100 /* clock/port select */
+#define   GMBUS_RATE_100KHZ	(0<<8)
+#define   GMBUS_RATE_50KHZ	(1<<8)
+#define   GMBUS_RATE_400KHZ	(2<<8) /* reserved on Pineview */
+#define   GMBUS_RATE_1MHZ	(3<<8) /* reserved on Pineview */
+#define   GMBUS_HOLD_EXT	(1<<7) /* 300ns hold time, rsvd on Pineview */
+#define   GMBUS_PORT_DISABLED	0
+#define   GMBUS_PORT_SSC	1
+#define   GMBUS_PORT_VGADDC	2
+#define   GMBUS_PORT_PANEL	3
+#define   GMBUS_PORT_DPC	4 /* HDMIC */
+#define   GMBUS_PORT_DPB	5 /* SDVO, HDMIB */
+				  /* 6 reserved */
+#define   GMBUS_PORT_DPD	7 /* HDMID */
+#define   GMBUS_NUM_PORTS       8
+#define GMBUS1			0x5104 /* command/status */
+#define   GMBUS_SW_CLR_INT	(1<<31)
+#define   GMBUS_SW_RDY		(1<<30)
+#define   GMBUS_ENT		(1<<29) /* enable timeout */
+#define   GMBUS_CYCLE_NONE	(0<<25)
+#define   GMBUS_CYCLE_WAIT	(1<<25)
+#define   GMBUS_CYCLE_INDEX	(2<<25)
+#define   GMBUS_CYCLE_STOP	(4<<25)
+#define   GMBUS_BYTE_COUNT_SHIFT 16
+#define   GMBUS_SLAVE_INDEX_SHIFT 8
+#define   GMBUS_SLAVE_ADDR_SHIFT 1
+#define   GMBUS_SLAVE_READ	(1<<0)
+#define   GMBUS_SLAVE_WRITE	(0<<0)
+#define GMBUS2			0x5108 /* status */
+#define   GMBUS_INUSE		(1<<15)
+#define   GMBUS_HW_WAIT_PHASE	(1<<14)
+#define   GMBUS_STALL_TIMEOUT	(1<<13)
+#define   GMBUS_INT		(1<<12)
+#define   GMBUS_HW_RDY		(1<<11)
+#define   GMBUS_SATOER		(1<<10)
+#define   GMBUS_ACTIVE		(1<<9)
+#define GMBUS3			0x510c /* data buffer bytes 3-0 */
+#define GMBUS4			0x5110 /* interrupt mask (Pineview+) */
+#define   GMBUS_SLAVE_TIMEOUT_EN (1<<4)
+#define   GMBUS_NAK_EN		(1<<3)
+#define   GMBUS_IDLE_EN		(1<<2)
+#define   GMBUS_HW_WAIT_EN	(1<<1)
+#define   GMBUS_HW_RDY_EN	(1<<0)
+#define GMBUS5			0x5120 /* byte index */
+#define   GMBUS_2BYTE_INDEX_EN	(1<<31)
 
 /*
  * Clock control & power management
@@ -603,6 +630,7 @@
 #define   VGA1_PD_P1_MASK	(0x1f << 8)
 #define DPLL_A	0x06014
 #define DPLL_B	0x06018
+#define DPLL(pipe) _PIPE(pipe, DPLL_A, DPLL_B)
 #define   DPLL_VCO_ENABLE		(1 << 31)
 #define   DPLL_DVO_HIGH_SPEED		(1 << 30)
 #define   DPLL_SYNCLOCK_ENABLE		(1 << 29)
@@ -640,24 +668,6 @@
 #define ADPA_DPMS_STANDBY	(2<<10)
 #define ADPA_DPMS_OFF		(3<<10)
 
-#define RING_TAIL		0x00
-#define TAIL_ADDR		0x001FFFF8
-#define RING_HEAD		0x04
-#define HEAD_WRAP_COUNT		0xFFE00000
-#define HEAD_WRAP_ONE		0x00200000
-#define HEAD_ADDR		0x001FFFFC
-#define RING_START		0x08
-#define START_ADDR		0xFFFFF000
-#define RING_LEN		0x0C
-#define RING_NR_PAGES		0x001FF000
-#define RING_REPORT_MASK	0x00000006
-#define RING_REPORT_64K		0x00000002
-#define RING_REPORT_128K	0x00000004
-#define RING_NO_REPORT		0x00000000
-#define RING_VALID_MASK		0x00000001
-#define RING_VALID		0x00000001
-#define RING_INVALID		0x00000000
-
 /* Scratch pad debug 0 reg:
  */
 #define   DPLL_FPA01_P1_POST_DIV_MASK_I830	0x001f0000
@@ -736,10 +746,13 @@
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK	0x0000003f
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT	0
 #define DPLL_B_MD 0x06020 /* 965+ only */
+#define DPLL_MD(pipe) _PIPE(pipe, DPLL_A_MD, DPLL_B_MD)
 #define FPA0	0x06040
 #define FPA1	0x06044
 #define FPB0	0x06048
 #define FPB1	0x0604c
+#define FP0(pipe) _PIPE(pipe, FPA0, FPB0)
+#define FP1(pipe) _PIPE(pipe, FPA1, FPB1)
 #define   FP_N_DIV_MASK		0x003f0000
 #define   FP_N_PINEVIEW_DIV_MASK	0x00ff0000
 #define   FP_N_DIV_SHIFT		16
@@ -760,6 +773,7 @@
 #define   DPLLA_TEST_M_BYPASS		(1 << 2)
 #define   DPLLA_INPUT_BUFFER_ENABLE	(1 << 0)
 #define D_STATE		0x6104
+#define  DSTATE_GFX_RESET_I830			(1<<6)
 #define  DSTATE_PLL_D3_OFF			(1<<3)
 #define  DSTATE_GFX_CLOCK_GATING		(1<<1)
 #define  DSTATE_DOT_CLOCK_GATING		(1<<0)
@@ -926,6 +940,8 @@
 #define CLKCFG_MEM_800					(3 << 4)
 #define CLKCFG_MEM_MASK					(7 << 4)
 
+#define TSC1			0x11001
+#define   TSE			(1<<0)
 #define TR1			0x11006
 #define TSFS			0x11020
 #define   TSFS_SLOPE_MASK	0x0000ff00
@@ -1070,6 +1086,8 @@
 #define   MEMSTAT_SRC_CTL_STDBY 3
 #define RCPREVBSYTUPAVG		0x113b8
 #define RCPREVBSYTDNAVG		0x113bc
+#define PMMISC			0x11214
+#define   MCPPCE_EN		(1<<0) /* enable PM_MSG from PCH->MPC */
 #define SDEW			0x1124c
 #define CSIEW0			0x11250
 #define CSIEW1			0x11254
@@ -1150,6 +1168,15 @@
 #define PIPEBSRC	0x6101c
 #define BCLRPAT_B	0x61020
 
+#define HTOTAL(pipe) _PIPE(pipe, HTOTAL_A, HTOTAL_B)
+#define HBLANK(pipe) _PIPE(pipe, HBLANK_A, HBLANK_B)
+#define HSYNC(pipe) _PIPE(pipe, HSYNC_A, HSYNC_B)
+#define VTOTAL(pipe) _PIPE(pipe, VTOTAL_A, VTOTAL_B)
+#define VBLANK(pipe) _PIPE(pipe, VBLANK_A, VBLANK_B)
+#define VSYNC(pipe) _PIPE(pipe, VSYNC_A, VSYNC_B)
+#define PIPESRC(pipe) _PIPE(pipe, PIPEASRC, PIPEBSRC)
+#define BCLRPAT(pipe) _PIPE(pipe, BCLRPAT_A, BCLRPAT_B)
+
 /* VGA port control */
 #define ADPA			0x61100
 #define   ADPA_DAC_ENABLE	(1<<31)
@@ -1481,6 +1508,7 @@
 # define TV_TEST_MODE_MASK		(7 << 0)
 
 #define TV_DAC			0x68004
+# define TV_DAC_SAVE		0x00ffff00
 /**
  * Reports that DAC state change logic has reported change (RO).
  *
@@ -2075,29 +2103,35 @@
 
 /* Display & cursor control */
 
-/* dithering flag on Ironlake */
-#define PIPE_ENABLE_DITHER		(1 << 4)
-#define PIPE_DITHER_TYPE_MASK		(3 << 2)
-#define PIPE_DITHER_TYPE_SPATIAL	(0 << 2)
-#define PIPE_DITHER_TYPE_ST01		(1 << 2)
 /* Pipe A */
 #define PIPEADSL		0x70000
-#define   DSL_LINEMASK	       	0x00000fff
+#define   DSL_LINEMASK		0x00000fff
 #define PIPEACONF		0x70008
-#define   PIPEACONF_ENABLE	(1<<31)
-#define   PIPEACONF_DISABLE	0
-#define   PIPEACONF_DOUBLE_WIDE	(1<<30)
+#define   PIPECONF_ENABLE	(1<<31)
+#define   PIPECONF_DISABLE	0
+#define   PIPECONF_DOUBLE_WIDE	(1<<30)
 #define   I965_PIPECONF_ACTIVE	(1<<30)
-#define   PIPEACONF_SINGLE_WIDE	0
-#define   PIPEACONF_PIPE_UNLOCKED 0
-#define   PIPEACONF_PIPE_LOCKED	(1<<25)
-#define   PIPEACONF_PALETTE	0
-#define   PIPEACONF_GAMMA		(1<<24)
+#define   PIPECONF_SINGLE_WIDE	0
+#define   PIPECONF_PIPE_UNLOCKED 0
+#define   PIPECONF_PIPE_LOCKED	(1<<25)
+#define   PIPECONF_PALETTE	0
+#define   PIPECONF_GAMMA		(1<<24)
 #define   PIPECONF_FORCE_BORDER	(1<<25)
 #define   PIPECONF_PROGRESSIVE	(0 << 21)
 #define   PIPECONF_INTERLACE_W_FIELD_INDICATION	(6 << 21)
 #define   PIPECONF_INTERLACE_FIELD_0_ONLY		(7 << 21)
 #define   PIPECONF_CXSR_DOWNCLOCK	(1<<16)
+#define   PIPECONF_BPP_MASK	(0x000000e0)
+#define   PIPECONF_BPP_8	(0<<5)
+#define   PIPECONF_BPP_10	(1<<5)
+#define   PIPECONF_BPP_6	(2<<5)
+#define   PIPECONF_BPP_12	(3<<5)
+#define   PIPECONF_DITHER_EN	(1<<4)
+#define   PIPECONF_DITHER_TYPE_MASK (0x0000000c)
+#define   PIPECONF_DITHER_TYPE_SP (0<<2)
+#define   PIPECONF_DITHER_TYPE_ST1 (1<<2)
+#define   PIPECONF_DITHER_TYPE_ST2 (2<<2)
+#define   PIPECONF_DITHER_TYPE_TEMP (3<<2)
 #define PIPEASTAT		0x70024
 #define   PIPE_FIFO_UNDERRUN_STATUS		(1UL<<31)
 #define   PIPE_CRC_ERROR_ENABLE			(1UL<<29)
@@ -2128,12 +2162,15 @@
 #define   PIPE_START_VBLANK_INTERRUPT_STATUS	(1UL<<2) /* 965 or later */
 #define   PIPE_VBLANK_INTERRUPT_STATUS		(1UL<<1)
 #define   PIPE_OVERLAY_UPDATED_STATUS		(1UL<<0)
-#define   PIPE_BPC_MASK 			(7 << 5) /* Ironlake */
+#define   PIPE_BPC_MASK				(7 << 5) /* Ironlake */
 #define   PIPE_8BPC				(0 << 5)
 #define   PIPE_10BPC				(1 << 5)
 #define   PIPE_6BPC				(2 << 5)
 #define   PIPE_12BPC				(3 << 5)
 
+#define PIPECONF(pipe) _PIPE(pipe, PIPEACONF, PIPEBCONF)
+#define PIPEDSL(pipe)  _PIPE(pipe, PIPEADSL, PIPEBDSL)
+
 #define DSPARB			0x70030
 #define   DSPARB_CSTART_MASK	(0x7f << 7)
 #define   DSPARB_CSTART_SHIFT	7
@@ -2206,8 +2243,8 @@
 #define  WM1_LP_SR_EN		(1<<31)
 #define  WM1_LP_LATENCY_SHIFT	24
 #define  WM1_LP_LATENCY_MASK	(0x7f<<24)
-#define  WM1_LP_FBC_LP1_MASK	(0xf<<20)
-#define  WM1_LP_FBC_LP1_SHIFT	20
+#define  WM1_LP_FBC_MASK	(0xf<<20)
+#define  WM1_LP_FBC_SHIFT	20
 #define  WM1_LP_SR_MASK		(0x1ff<<8)
 #define  WM1_LP_SR_SHIFT	8
 #define  WM1_LP_CURSOR_MASK	(0x3f)
@@ -2333,6 +2370,14 @@
 #define DSPASURF		0x7019C /* 965+ only */
 #define DSPATILEOFF		0x701A4 /* 965+ only */
 
+#define DSPCNTR(plane) _PIPE(plane, DSPACNTR, DSPBCNTR)
+#define DSPADDR(plane) _PIPE(plane, DSPAADDR, DSPBADDR)
+#define DSPSTRIDE(plane) _PIPE(plane, DSPASTRIDE, DSPBSTRIDE)
+#define DSPPOS(plane) _PIPE(plane, DSPAPOS, DSPBPOS)
+#define DSPSIZE(plane) _PIPE(plane, DSPASIZE, DSPBSIZE)
+#define DSPSURF(plane) _PIPE(plane, DSPASURF, DSPBSURF)
+#define DSPTILEOFF(plane) _PIPE(plane, DSPATILEOFF, DSPBTILEOFF)
+
 /* VBIOS flags */
 #define SWF00			0x71410
 #define SWF01			0x71414
@@ -2397,6 +2442,7 @@
 #define  RR_HW_HIGH_POWER_FRAMES_MASK   0xff00
 
 #define FDI_PLL_BIOS_0  0x46000
+#define  FDI_PLL_FB_CLOCK_MASK  0xff
 #define FDI_PLL_BIOS_1  0x46004
 #define FDI_PLL_BIOS_2  0x46008
 #define DISPLAY_PORT_PLL_BIOS_0         0x4600c
@@ -2420,46 +2466,47 @@
 #define PIPEA_DATA_M1           0x60030
 #define  TU_SIZE(x)             (((x)-1) << 25) /* default size 64 */
 #define  TU_SIZE_MASK           0x7e000000
-#define  PIPEA_DATA_M1_OFFSET   0
+#define  PIPE_DATA_M1_OFFSET    0
 #define PIPEA_DATA_N1           0x60034
-#define  PIPEA_DATA_N1_OFFSET   0
+#define  PIPE_DATA_N1_OFFSET    0
 
 #define PIPEA_DATA_M2           0x60038
-#define  PIPEA_DATA_M2_OFFSET   0
+#define  PIPE_DATA_M2_OFFSET    0
 #define PIPEA_DATA_N2           0x6003c
-#define  PIPEA_DATA_N2_OFFSET   0
+#define  PIPE_DATA_N2_OFFSET    0
 
 #define PIPEA_LINK_M1           0x60040
-#define  PIPEA_LINK_M1_OFFSET   0
+#define  PIPE_LINK_M1_OFFSET    0
 #define PIPEA_LINK_N1           0x60044
-#define  PIPEA_LINK_N1_OFFSET   0
+#define  PIPE_LINK_N1_OFFSET    0
 
 #define PIPEA_LINK_M2           0x60048
-#define  PIPEA_LINK_M2_OFFSET   0
+#define  PIPE_LINK_M2_OFFSET    0
 #define PIPEA_LINK_N2           0x6004c
-#define  PIPEA_LINK_N2_OFFSET   0
+#define  PIPE_LINK_N2_OFFSET    0
 
 /* PIPEB timing regs are same start from 0x61000 */
 
 #define PIPEB_DATA_M1           0x61030
-#define  PIPEB_DATA_M1_OFFSET   0
 #define PIPEB_DATA_N1           0x61034
-#define  PIPEB_DATA_N1_OFFSET   0
 
 #define PIPEB_DATA_M2           0x61038
-#define  PIPEB_DATA_M2_OFFSET   0
 #define PIPEB_DATA_N2           0x6103c
-#define  PIPEB_DATA_N2_OFFSET   0
 
 #define PIPEB_LINK_M1           0x61040
-#define  PIPEB_LINK_M1_OFFSET   0
 #define PIPEB_LINK_N1           0x61044
-#define  PIPEB_LINK_N1_OFFSET   0
 
 #define PIPEB_LINK_M2           0x61048
-#define  PIPEB_LINK_M2_OFFSET   0
 #define PIPEB_LINK_N2           0x6104c
-#define  PIPEB_LINK_N2_OFFSET   0
+
+#define PIPE_DATA_M1(pipe) _PIPE(pipe, PIPEA_DATA_M1, PIPEB_DATA_M1)
+#define PIPE_DATA_N1(pipe) _PIPE(pipe, PIPEA_DATA_N1, PIPEB_DATA_N1)
+#define PIPE_DATA_M2(pipe) _PIPE(pipe, PIPEA_DATA_M2, PIPEB_DATA_M2)
+#define PIPE_DATA_N2(pipe) _PIPE(pipe, PIPEA_DATA_N2, PIPEB_DATA_N2)
+#define PIPE_LINK_M1(pipe) _PIPE(pipe, PIPEA_LINK_M1, PIPEB_LINK_M1)
+#define PIPE_LINK_N1(pipe) _PIPE(pipe, PIPEA_LINK_N1, PIPEB_LINK_N1)
+#define PIPE_LINK_M2(pipe) _PIPE(pipe, PIPEA_LINK_M2, PIPEB_LINK_M2)
+#define PIPE_LINK_N2(pipe) _PIPE(pipe, PIPEA_LINK_N2, PIPEB_LINK_N2)
 
 /* CPU panel fitter */
 #define PFA_CTL_1               0x68080
@@ -2516,7 +2563,7 @@
 #define GT_SYNC_STATUS          (1 << 2)
 #define GT_USER_INTERRUPT       (1 << 0)
 #define GT_BSD_USER_INTERRUPT   (1 << 5)
-
+#define GT_GEN6_BSD_USER_INTERRUPT	(1 << 12)
 
 #define GTISR   0x44010
 #define GTIMR   0x44014
@@ -2600,11 +2647,14 @@
 
 #define PCH_DPLL_A              0xc6014
 #define PCH_DPLL_B              0xc6018
+#define PCH_DPLL(pipe) _PIPE(pipe, PCH_DPLL_A, PCH_DPLL_B)
 
 #define PCH_FPA0                0xc6040
 #define PCH_FPA1                0xc6044
 #define PCH_FPB0                0xc6048
 #define PCH_FPB1                0xc604c
+#define PCH_FP0(pipe) _PIPE(pipe, PCH_FPA0, PCH_FPB0)
+#define PCH_FP1(pipe) _PIPE(pipe, PCH_FPA1, PCH_FPB1)
 
 #define PCH_DPLL_TEST           0xc606c
 
@@ -2690,6 +2740,13 @@
 #define TRANS_VBLANK_B          0xe1010
 #define TRANS_VSYNC_B           0xe1014
 
+#define TRANS_HTOTAL(pipe) _PIPE(pipe, TRANS_HTOTAL_A, TRANS_HTOTAL_B)
+#define TRANS_HBLANK(pipe) _PIPE(pipe, TRANS_HBLANK_A, TRANS_HBLANK_B)
+#define TRANS_HSYNC(pipe) _PIPE(pipe, TRANS_HSYNC_A, TRANS_HSYNC_B)
+#define TRANS_VTOTAL(pipe) _PIPE(pipe, TRANS_VTOTAL_A, TRANS_VTOTAL_B)
+#define TRANS_VBLANK(pipe) _PIPE(pipe, TRANS_VBLANK_A, TRANS_VBLANK_B)
+#define TRANS_VSYNC(pipe) _PIPE(pipe, TRANS_VSYNC_A, TRANS_VSYNC_B)
+
 #define TRANSB_DATA_M1          0xe1030
 #define TRANSB_DATA_N1          0xe1034
 #define TRANSB_DATA_M2          0xe1038
@@ -2701,6 +2758,7 @@
 
 #define TRANSACONF              0xf0008
 #define TRANSBCONF              0xf1008
+#define TRANSCONF(plane) _PIPE(plane, TRANSACONF, TRANSBCONF)
 #define  TRANS_DISABLE          (0<<31)
 #define  TRANS_ENABLE           (1<<31)
 #define  TRANS_STATE_MASK       (1<<30)
@@ -2725,6 +2783,7 @@
 /* CPU: FDI_TX */
 #define FDI_TXA_CTL             0x60100
 #define FDI_TXB_CTL             0x61100
+#define FDI_TX_CTL(pipe) _PIPE(pipe, FDI_TXA_CTL, FDI_TXB_CTL)
 #define  FDI_TX_DISABLE         (0<<31)
 #define  FDI_TX_ENABLE          (1<<31)
 #define  FDI_LINK_TRAIN_PATTERN_1       (0<<28)
@@ -2766,8 +2825,8 @@
 /* FDI_RX, FDI_X is hard-wired to Transcoder_X */
 #define FDI_RXA_CTL             0xf000c
 #define FDI_RXB_CTL             0xf100c
+#define FDI_RX_CTL(pipe) _PIPE(pipe, FDI_RXA_CTL, FDI_RXB_CTL)
 #define  FDI_RX_ENABLE          (1<<31)
-#define  FDI_RX_DISABLE         (0<<31)
 /* train, dp width same as FDI_TX */
 #define  FDI_DP_PORT_WIDTH_X8           (7<<19)
 #define  FDI_8BPC                       (0<<16)
@@ -2782,8 +2841,7 @@
 #define  FDI_FS_ERR_REPORT_ENABLE       (1<<9)
 #define  FDI_FE_ERR_REPORT_ENABLE       (1<<8)
 #define  FDI_RX_ENHANCE_FRAME_ENABLE    (1<<6)
-#define  FDI_SEL_RAWCLK                 (0<<4)
-#define  FDI_SEL_PCDCLK                 (1<<4)
+#define  FDI_PCDCLK	                (1<<4)
 /* CPT */
 #define  FDI_AUTO_TRAINING			(1<<10)
 #define  FDI_LINK_TRAIN_PATTERN_1_CPT		(0<<8)
@@ -2798,6 +2856,9 @@
 #define FDI_RXA_TUSIZE2         0xf0038
 #define FDI_RXB_TUSIZE1         0xf1030
 #define FDI_RXB_TUSIZE2         0xf1038
+#define FDI_RX_MISC(pipe) _PIPE(pipe, FDI_RXA_MISC, FDI_RXB_MISC)
+#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, FDI_RXA_TUSIZE1, FDI_RXB_TUSIZE1)
+#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, FDI_RXA_TUSIZE2, FDI_RXB_TUSIZE2)
 
 /* FDI_RX interrupt register format */
 #define FDI_RX_INTER_LANE_ALIGN         (1<<10)
@@ -2816,6 +2877,8 @@
 #define FDI_RXA_IMR             0xf0018
 #define FDI_RXB_IIR             0xf1014
 #define FDI_RXB_IMR             0xf1018
+#define FDI_RX_IIR(pipe) _PIPE(pipe, FDI_RXA_IIR, FDI_RXB_IIR)
+#define FDI_RX_IMR(pipe) _PIPE(pipe, FDI_RXA_IMR, FDI_RXB_IMR)
 
 #define FDI_PLL_CTL_1           0xfe000
 #define FDI_PLL_CTL_2           0xfe004
@@ -2935,6 +2998,7 @@
 #define TRANS_DP_CTL_A		0xe0300
 #define TRANS_DP_CTL_B		0xe1300
 #define TRANS_DP_CTL_C		0xe2300
+#define TRANS_DP_CTL(pipe)	(TRANS_DP_CTL_A + (pipe) * 0x01000)
 #define  TRANS_DP_OUTPUT_ENABLE	(1<<31)
 #define  TRANS_DP_PORT_SEL_B	(0<<29)
 #define  TRANS_DP_PORT_SEL_C	(1<<29)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 31f0858..989c19d 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -256,7 +256,7 @@
 		dev_priv->saveFPA1 = I915_READ(FPA1);
 		dev_priv->saveDPLL_A = I915_READ(DPLL_A);
 	}
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
 		dev_priv->saveDPLL_A_MD = I915_READ(DPLL_A_MD);
 	dev_priv->saveHTOTAL_A = I915_READ(HTOTAL_A);
 	dev_priv->saveHBLANK_A = I915_READ(HBLANK_A);
@@ -294,7 +294,7 @@
 	dev_priv->saveDSPASIZE = I915_READ(DSPASIZE);
 	dev_priv->saveDSPAPOS = I915_READ(DSPAPOS);
 	dev_priv->saveDSPAADDR = I915_READ(DSPAADDR);
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		dev_priv->saveDSPASURF = I915_READ(DSPASURF);
 		dev_priv->saveDSPATILEOFF = I915_READ(DSPATILEOFF);
 	}
@@ -313,7 +313,7 @@
 		dev_priv->saveFPB1 = I915_READ(FPB1);
 		dev_priv->saveDPLL_B = I915_READ(DPLL_B);
 	}
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
 		dev_priv->saveDPLL_B_MD = I915_READ(DPLL_B_MD);
 	dev_priv->saveHTOTAL_B = I915_READ(HTOTAL_B);
 	dev_priv->saveHBLANK_B = I915_READ(HBLANK_B);
@@ -351,7 +351,7 @@
 	dev_priv->saveDSPBSIZE = I915_READ(DSPBSIZE);
 	dev_priv->saveDSPBPOS = I915_READ(DSPBPOS);
 	dev_priv->saveDSPBADDR = I915_READ(DSPBADDR);
-	if (IS_I965GM(dev) || IS_GM45(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		dev_priv->saveDSPBSURF = I915_READ(DSPBSURF);
 		dev_priv->saveDSPBTILEOFF = I915_READ(DSPBTILEOFF);
 	}
@@ -404,7 +404,7 @@
 	I915_WRITE(dpll_a_reg, dev_priv->saveDPLL_A);
 	POSTING_READ(dpll_a_reg);
 	udelay(150);
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
 		I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
 		POSTING_READ(DPLL_A_MD);
 	}
@@ -448,7 +448,7 @@
 	I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
 	I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
 	I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
 		I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
 	}
@@ -473,7 +473,7 @@
 	I915_WRITE(dpll_b_reg, dev_priv->saveDPLL_B);
 	POSTING_READ(dpll_b_reg);
 	udelay(150);
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
 		I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
 		POSTING_READ(DPLL_B_MD);
 	}
@@ -517,7 +517,7 @@
 	I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
 	I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
 	I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
 		I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
 	}
@@ -550,7 +550,7 @@
 	dev_priv->saveCURBCNTR = I915_READ(CURBCNTR);
 	dev_priv->saveCURBPOS = I915_READ(CURBPOS);
 	dev_priv->saveCURBBASE = I915_READ(CURBBASE);
-	if (!IS_I9XX(dev))
+	if (IS_GEN2(dev))
 		dev_priv->saveCURSIZE = I915_READ(CURSIZE);
 
 	/* CRT state */
@@ -573,7 +573,7 @@
 		dev_priv->savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
 		dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
 		dev_priv->saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
-		if (IS_I965G(dev))
+		if (INTEL_INFO(dev)->gen >= 4)
 			dev_priv->saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
 		if (IS_MOBILE(dev) && !IS_I830(dev))
 			dev_priv->saveLVDS = I915_READ(LVDS);
@@ -664,7 +664,7 @@
 	I915_WRITE(CURBPOS, dev_priv->saveCURBPOS);
 	I915_WRITE(CURBCNTR, dev_priv->saveCURBCNTR);
 	I915_WRITE(CURBBASE, dev_priv->saveCURBBASE);
-	if (!IS_I9XX(dev))
+	if (IS_GEN2(dev))
 		I915_WRITE(CURSIZE, dev_priv->saveCURSIZE);
 
 	/* CRT state */
@@ -674,7 +674,7 @@
 		I915_WRITE(ADPA, dev_priv->saveADPA);
 
 	/* LVDS state */
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
 		I915_WRITE(BLC_PWM_CTL2, dev_priv->saveBLC_PWM_CTL2);
 
 	if (HAS_PCH_SPLIT(dev)) {
@@ -878,9 +878,7 @@
 	for (i = 0; i < 3; i++)
 		I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
 
-	/* I2C state */
-	intel_i2c_reset_gmbus(dev);
+	intel_i2c_reset(dev);
 
 	return 0;
 }
-
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 96f75d7..b1f73ac 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -129,10 +129,6 @@
 	int i, temp_downclock;
 	struct drm_display_mode *temp_mode;
 
-	/* Defaults if we can't find VBT info */
-	dev_priv->lvds_dither = 0;
-	dev_priv->lvds_vbt = 0;
-
 	lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
 	if (!lvds_options)
 		return;
@@ -140,6 +136,7 @@
 	dev_priv->lvds_dither = lvds_options->pixel_dither;
 	if (lvds_options->panel_type == 0xff)
 		return;
+
 	panel_type = lvds_options->panel_type;
 
 	lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
@@ -169,6 +166,8 @@
 			((unsigned char *)entry + dvo_timing_offset);
 
 	panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
+	if (!panel_fixed_mode)
+		return;
 
 	fill_detail_timing_data(panel_fixed_mode, dvo_timing);
 
@@ -230,8 +229,6 @@
 	struct lvds_dvo_timing *dvo_timing;
 	struct drm_display_mode *panel_fixed_mode;
 
-	dev_priv->sdvo_lvds_vbt_mode = NULL;
-
 	sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
 	if (!sdvo_lvds_options)
 		return;
@@ -260,10 +257,6 @@
 	struct drm_device *dev = dev_priv->dev;
 	struct bdb_general_features *general;
 
-	/* Set sensible defaults in case we can't find the general block */
-	dev_priv->int_tv_support = 1;
-	dev_priv->int_crt_support = 1;
-
 	general = find_section(bdb, BDB_GENERAL_FEATURES);
 	if (general) {
 		dev_priv->int_tv_support = general->int_tv_support;
@@ -289,14 +282,6 @@
 			  struct bdb_header *bdb)
 {
 	struct bdb_general_definitions *general;
-	const int crt_bus_map_table[] = {
-		GPIOB,
-		GPIOA,
-		GPIOC,
-		GPIOD,
-		GPIOE,
-		GPIOF,
-	};
 
 	general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 	if (general) {
@@ -304,10 +289,8 @@
 		if (block_size >= sizeof(*general)) {
 			int bus_pin = general->crt_ddc_gmbus_pin;
 			DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
-			if ((bus_pin >= 1) && (bus_pin <= 6)) {
-				dev_priv->crt_ddc_bus =
-					crt_bus_map_table[bus_pin-1];
-			}
+			if (bus_pin >= 1 && bus_pin <= 6)
+				dev_priv->crt_ddc_pin = bus_pin;
 		} else {
 			DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
 				  block_size);
@@ -317,7 +300,7 @@
 
 static void
 parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
-		       struct bdb_header *bdb)
+			  struct bdb_header *bdb)
 {
 	struct sdvo_device_mapping *p_mapping;
 	struct bdb_general_definitions *p_defs;
@@ -327,7 +310,7 @@
 
 	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 	if (!p_defs) {
-		DRM_DEBUG_KMS("No general definition block is found\n");
+		DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
 		return;
 	}
 	/* judge whether the size of child device meets the requirements.
@@ -377,7 +360,16 @@
 			p_mapping->slave_addr = p_child->slave_addr;
 			p_mapping->dvo_wiring = p_child->dvo_wiring;
 			p_mapping->ddc_pin = p_child->ddc_pin;
+			p_mapping->i2c_pin = p_child->i2c_pin;
+			p_mapping->i2c_speed = p_child->i2c_speed;
 			p_mapping->initialized = 1;
+			DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d, i2c_speed=%d\n",
+				      p_mapping->dvo_port,
+				      p_mapping->slave_addr,
+				      p_mapping->dvo_wiring,
+				      p_mapping->ddc_pin,
+				      p_mapping->i2c_pin,
+				      p_mapping->i2c_speed);
 		} else {
 			DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
 					 "two SDVO device.\n");
@@ -409,14 +401,11 @@
 	if (!driver)
 		return;
 
-	if (driver && SUPPORTS_EDP(dev) &&
-	    driver->lvds_config == BDB_DRIVER_FEATURE_EDP) {
-		dev_priv->edp_support = 1;
-	} else {
-		dev_priv->edp_support = 0;
-	}
+	if (SUPPORTS_EDP(dev) &&
+	    driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+		dev_priv->edp.support = 1;
 
-	if (driver && driver->dual_frequency)
+	if (driver->dual_frequency)
 		dev_priv->render_reclock_avail = true;
 }
 
@@ -427,26 +416,40 @@
 
 	edp = find_section(bdb, BDB_EDP);
 	if (!edp) {
-		if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
+		if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
 			DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
-				      "supported, assume 18bpp panel color "
-				      "depth.\n");
-			dev_priv->edp_bpp = 18;
+				      "supported, assume %dbpp panel color "
+				      "depth.\n",
+				      dev_priv->edp.bpp);
 		}
 		return;
 	}
 
 	switch ((edp->color_depth >> (panel_type * 2)) & 3) {
 	case EDP_18BPP:
-		dev_priv->edp_bpp = 18;
+		dev_priv->edp.bpp = 18;
 		break;
 	case EDP_24BPP:
-		dev_priv->edp_bpp = 24;
+		dev_priv->edp.bpp = 24;
 		break;
 	case EDP_30BPP:
-		dev_priv->edp_bpp = 30;
+		dev_priv->edp.bpp = 30;
 		break;
 	}
+
+	dev_priv->edp.rate = edp->link_params[panel_type].rate;
+	dev_priv->edp.lanes = edp->link_params[panel_type].lanes;
+	dev_priv->edp.preemphasis = edp->link_params[panel_type].preemphasis;
+	dev_priv->edp.vswing = edp->link_params[panel_type].vswing;
+
+	DRM_DEBUG_KMS("eDP vBIOS settings: bpp=%d, rate=%d, lanes=%d, preemphasis=%d, vswing=%d\n",
+		      dev_priv->edp.bpp,
+		      dev_priv->edp.rate,
+		      dev_priv->edp.lanes,
+		      dev_priv->edp.preemphasis,
+		      dev_priv->edp.vswing);
+
+	dev_priv->edp.initialized = true;
 }
 
 static void
@@ -460,7 +463,7 @@
 
 	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
 	if (!p_defs) {
-		DRM_DEBUG_KMS("No general definition block is found\n");
+		DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
 		return;
 	}
 	/* judge whether the size of child device meets the requirements.
@@ -513,6 +516,28 @@
 	}
 	return;
 }
+
+static void
+init_vbt_defaults(struct drm_i915_private *dev_priv)
+{
+	dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
+
+	/* LFP panel data */
+	dev_priv->lvds_dither = 1;
+	dev_priv->lvds_vbt = 0;
+
+	/* SDVO panel data */
+	dev_priv->sdvo_lvds_vbt_mode = NULL;
+
+	/* general features */
+	dev_priv->int_tv_support = 1;
+	dev_priv->int_crt_support = 1;
+	dev_priv->lvds_use_ssc = 0;
+
+	/* eDP data */
+	dev_priv->edp.bpp = 18;
+}
+
 /**
  * intel_init_bios - initialize VBIOS settings & find VBT
  * @dev: DRM device
@@ -520,11 +545,6 @@
  * Loads the Video BIOS and checks that the VBT exists.  Sets scratch registers
  * to appropriate values.
  *
- * VBT existence is a sanity check that is relied on by other i830_bios.c code.
- * Note that it would be better to use a BIOS call to get the VBT, as BIOSes may
- * feed an updated VBT back through that, compared to what we'll fetch using
- * this method of groping around in the BIOS data.
- *
  * Returns 0 on success, nonzero on failure.
  */
 bool
@@ -532,31 +552,47 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct pci_dev *pdev = dev->pdev;
-	struct vbt_header *vbt = NULL;
-	struct bdb_header *bdb;
-	u8 __iomem *bios;
-	size_t size;
-	int i;
+	struct bdb_header *bdb = NULL;
+	u8 __iomem *bios = NULL;
 
-	bios = pci_map_rom(pdev, &size);
-	if (!bios)
-		return -1;
+	init_vbt_defaults(dev_priv);
 
-	/* Scour memory looking for the VBT signature */
-	for (i = 0; i + 4 < size; i++) {
-		if (!memcmp(bios + i, "$VBT", 4)) {
-			vbt = (struct vbt_header *)(bios + i);
-			break;
+	/* XXX Should this validation be moved to intel_opregion.c? */
+	if (dev_priv->opregion.vbt) {
+		struct vbt_header *vbt = dev_priv->opregion.vbt;
+		if (memcmp(vbt->signature, "$VBT", 4) == 0) {
+			DRM_DEBUG_DRIVER("Using VBT from OpRegion: %20s\n",
+					 vbt->signature);
+			bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
+		} else
+			dev_priv->opregion.vbt = NULL;
+	}
+
+	if (bdb == NULL) {
+		struct vbt_header *vbt = NULL;
+		size_t size;
+		int i;
+
+		bios = pci_map_rom(pdev, &size);
+		if (!bios)
+			return -1;
+
+		/* Scour memory looking for the VBT signature */
+		for (i = 0; i + 4 < size; i++) {
+			if (!memcmp(bios + i, "$VBT", 4)) {
+				vbt = (struct vbt_header *)(bios + i);
+				break;
+			}
 		}
-	}
 
-	if (!vbt) {
-		DRM_ERROR("VBT signature missing\n");
-		pci_unmap_rom(pdev, bios);
-		return -1;
-	}
+		if (!vbt) {
+			DRM_ERROR("VBT signature missing\n");
+			pci_unmap_rom(pdev, bios);
+			return -1;
+		}
 
-	bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+		bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
+	}
 
 	/* Grab useful general definitions */
 	parse_general_features(dev_priv, bdb);
@@ -568,7 +604,8 @@
 	parse_driver_features(dev_priv, bdb);
 	parse_edp(dev_priv, bdb);
 
-	pci_unmap_rom(pdev, bios);
+	if (bios)
+		pci_unmap_rom(pdev, bios);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 4c18514..e1a598f 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -197,7 +197,8 @@
 struct child_device_config {
 	u16 handle;
 	u16 device_type;
-	u8  device_id[10]; /* See DEVICE_TYPE_* above */
+	u8  i2c_speed;
+	u8  rsvd[9];
 	u16 addin_offset;
 	u8  dvo_port; /* See Device_PORT_* above */
 	u8  i2c_pin;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 197d4f3..389fcd2 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -79,7 +79,7 @@
 	if (mode->clock < 25000)
 		return MODE_CLOCK_LOW;
 
-	if (!IS_I9XX(dev))
+	if (IS_GEN2(dev))
 		max_clock = 350000;
 	else
 		max_clock = 400000;
@@ -123,7 +123,7 @@
 	 * Disable separate mode multiplier used when cloning SDVO to CRT
 	 * XXX this needs to be adjusted when we really are cloning
 	 */
-	if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
 		dpll_md = I915_READ(dpll_md_reg);
 		I915_WRITE(dpll_md_reg,
 			   dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
@@ -187,7 +187,7 @@
 	I915_WRITE(PCH_ADPA, adpa);
 
 	if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
-		     1000, 1))
+		     1000))
 		DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
 
 	if (turn_off_dac) {
@@ -244,7 +244,7 @@
 		/* wait for FORCE_DETECT to go off */
 		if (wait_for((I915_READ(PORT_HOTPLUG_EN) &
 			      CRT_HOTPLUG_FORCE_DETECT) == 0,
-			     1000, 1))
+			     1000))
 			DRM_DEBUG_KMS("timed out waiting for FORCE_DETECT to go off");
 	}
 
@@ -261,21 +261,47 @@
 	return ret;
 }
 
+static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
+{
+	u8 buf;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = 0xA0,
+			.flags = 0,
+			.len = 1,
+			.buf = &buf,
+		},
+	};
+	/* DDC monitor detect: Does it ACK a write to 0xA0? */
+	return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
+}
+
 static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
 {
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 
 	/* CRT should always be at 0, but check anyway */
 	if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
 		return false;
 
-	return intel_ddc_probe(intel_encoder);
+	if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
+		DRM_DEBUG_KMS("CRT detected via DDC:0xa0\n");
+		return true;
+	}
+
+	if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
+		DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
+		return true;
+	}
+
+	return false;
 }
 
 static enum drm_connector_status
 intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
 {
-	struct drm_encoder *encoder = &intel_encoder->enc;
+	struct drm_encoder *encoder = &intel_encoder->base;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -295,6 +321,8 @@
 	uint8_t	st00;
 	enum drm_connector_status status;
 
+	DRM_DEBUG_KMS("starting load-detect on CRT\n");
+
 	if (pipe == 0) {
 		bclrpat_reg = BCLRPAT_A;
 		vtotal_reg = VTOTAL_A;
@@ -324,9 +352,10 @@
 	/* Set the border color to purple. */
 	I915_WRITE(bclrpat_reg, 0x500050);
 
-	if (IS_I9XX(dev)) {
+	if (!IS_GEN2(dev)) {
 		uint32_t pipeconf = I915_READ(pipeconf_reg);
 		I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
+		POSTING_READ(pipeconf_reg);
 		/* Wait for next Vblank to substitue
 		 * border color for Color info */
 		intel_wait_for_vblank(dev, pipe);
@@ -404,34 +433,37 @@
 intel_crt_detect(struct drm_connector *connector, bool force)
 {
 	struct drm_device *dev = connector->dev;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
+	struct intel_encoder *encoder = intel_attached_encoder(connector);
 	struct drm_crtc *crtc;
 	int dpms_mode;
 	enum drm_connector_status status;
 
-	if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
-		if (intel_crt_detect_hotplug(connector))
+	if (I915_HAS_HOTPLUG(dev)) {
+		if (intel_crt_detect_hotplug(connector)) {
+			DRM_DEBUG_KMS("CRT detected via hotplug\n");
 			return connector_status_connected;
-		else
+		} else
 			return connector_status_disconnected;
 	}
 
-	if (intel_crt_detect_ddc(encoder))
+	if (intel_crt_detect_ddc(&encoder->base))
 		return connector_status_connected;
 
 	if (!force)
 		return connector->status;
 
 	/* for pre-945g platforms use load detect */
-	if (encoder->crtc && encoder->crtc->enabled) {
-		status = intel_crt_load_detect(encoder->crtc, intel_encoder);
+	if (encoder->base.crtc && encoder->base.crtc->enabled) {
+		status = intel_crt_load_detect(encoder->base.crtc, encoder);
 	} else {
-		crtc = intel_get_load_detect_pipe(intel_encoder, connector,
+		crtc = intel_get_load_detect_pipe(encoder, connector,
 						  NULL, &dpms_mode);
 		if (crtc) {
-			status = intel_crt_load_detect(crtc, intel_encoder);
-			intel_release_load_detect_pipe(intel_encoder,
+			if (intel_crt_detect_ddc(&encoder->base))
+				status = connector_status_connected;
+			else
+				status = intel_crt_load_detect(crtc, encoder);
+			intel_release_load_detect_pipe(encoder,
 						       connector, dpms_mode);
 		} else
 			status = connector_status_unknown;
@@ -449,32 +481,18 @@
 
 static int intel_crt_get_modes(struct drm_connector *connector)
 {
-	int ret;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-	struct i2c_adapter *ddc_bus;
 	struct drm_device *dev = connector->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
 
-
-	ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
+	ret = intel_ddc_get_modes(connector,
+				 &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
 	if (ret || !IS_G4X(dev))
-		goto end;
+		return ret;
 
 	/* Try to probe digital port for output in DVI-I -> VGA mode. */
-	ddc_bus = intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
-
-	if (!ddc_bus) {
-		dev_printk(KERN_ERR, &connector->dev->pdev->dev,
-			   "DDC bus registration failed for CRTDDC_D.\n");
-		goto end;
-	}
-	/* Try to get modes by GPIOD port */
-	ret = intel_ddc_get_modes(connector, ddc_bus);
-	intel_i2c_destroy(ddc_bus);
-
-end:
-	return ret;
-
+	return intel_ddc_get_modes(connector,
+				   &dev_priv->gmbus[GMBUS_PORT_DPB].adapter);
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
@@ -507,7 +525,7 @@
 static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
 	.mode_valid = intel_crt_mode_valid,
 	.get_modes = intel_crt_get_modes,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_crt_enc_funcs = {
@@ -520,7 +538,6 @@
 	struct intel_encoder *intel_encoder;
 	struct intel_connector *intel_connector;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 i2c_reg;
 
 	intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
 	if (!intel_encoder)
@@ -536,27 +553,10 @@
 	drm_connector_init(dev, &intel_connector->base,
 			   &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_crt_enc_funcs,
+	drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
 			 DRM_MODE_ENCODER_DAC);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base,
-					  &intel_encoder->enc);
-
-	/* Set up the DDC bus. */
-	if (HAS_PCH_SPLIT(dev))
-		i2c_reg = PCH_GPIOA;
-	else {
-		i2c_reg = GPIOA;
-		/* Use VBT information for CRT DDC if available */
-		if (dev_priv->crt_ddc_bus != 0)
-			i2c_reg = dev_priv->crt_ddc_bus;
-	}
-	intel_encoder->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
-	if (!intel_encoder->ddc_bus) {
-		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
-			   "failed.\n");
-		return;
-	}
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 
 	intel_encoder->type = INTEL_OUTPUT_ANALOG;
 	intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
@@ -566,7 +566,7 @@
 	connector->interlace_allowed = 1;
 	connector->doublescan_allowed = 0;
 
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
 	drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
 	drm_sysfs_connector_add(connector);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b5bf51a..69c54c5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -43,8 +43,8 @@
 
 bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
 static void intel_update_watermarks(struct drm_device *dev);
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
-static void intel_crtc_update_cursor(struct drm_crtc *crtc);
+static void intel_increase_pllclock(struct drm_crtc *crtc);
+static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
 typedef struct {
     /* given values */
@@ -342,6 +342,13 @@
 intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
 			   int target, int refclk, intel_clock_t *best_clock);
 
+static inline u32 /* units of 100MHz */
+intel_fdi_link_freq(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	return (I915_READ(FDI_PLL_BIOS_0) & FDI_PLL_FB_CLOCK_MASK) + 2;
+}
+
 static const intel_limit_t intel_limits_i8xx_dvo = {
         .dot = { .min = I8XX_DOT_MIN,		.max = I8XX_DOT_MAX },
         .vco = { .min = I8XX_VCO_MIN,		.max = I8XX_VCO_MAX },
@@ -701,16 +708,16 @@
 		limit = intel_ironlake_limit(crtc);
 	else if (IS_G4X(dev)) {
 		limit = intel_g4x_limit(crtc);
-	} else if (IS_I9XX(dev) && !IS_PINEVIEW(dev)) {
-		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
-			limit = &intel_limits_i9xx_lvds;
-		else
-			limit = &intel_limits_i9xx_sdvo;
 	} else if (IS_PINEVIEW(dev)) {
 		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
 			limit = &intel_limits_pineview_lvds;
 		else
 			limit = &intel_limits_pineview_sdvo;
+	} else if (!IS_GEN2(dev)) {
+		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+			limit = &intel_limits_i9xx_lvds;
+		else
+			limit = &intel_limits_i9xx_sdvo;
 	} else {
 		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
 			limit = &intel_limits_i8xx_lvds;
@@ -744,20 +751,17 @@
 /**
  * Returns whether any output on the specified pipe is of the specified type
  */
-bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
+bool intel_pipe_has_type(struct drm_crtc *crtc, int type)
 {
-    struct drm_device *dev = crtc->dev;
-    struct drm_mode_config *mode_config = &dev->mode_config;
-    struct drm_encoder *l_entry;
+	struct drm_device *dev = crtc->dev;
+	struct drm_mode_config *mode_config = &dev->mode_config;
+	struct intel_encoder *encoder;
 
-    list_for_each_entry(l_entry, &mode_config->encoder_list, head) {
-	    if (l_entry && l_entry->crtc == crtc) {
-		    struct intel_encoder *intel_encoder = enc_to_intel_encoder(l_entry);
-		    if (intel_encoder->type == type)
-			    return true;
-	    }
-    }
-    return false;
+	list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
+		if (encoder->base.crtc == crtc && encoder->type == type)
+			return true;
+
+	return false;
 }
 
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
@@ -955,26 +959,26 @@
 intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
 		      int target, int refclk, intel_clock_t *best_clock)
 {
-    intel_clock_t clock;
-    if (target < 200000) {
-	clock.p1 = 2;
-	clock.p2 = 10;
-	clock.n = 2;
-	clock.m1 = 23;
-	clock.m2 = 8;
-    } else {
-	clock.p1 = 1;
-	clock.p2 = 10;
-	clock.n = 1;
-	clock.m1 = 14;
-	clock.m2 = 2;
-    }
-    clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
-    clock.p = (clock.p1 * clock.p2);
-    clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
-    clock.vco = 0;
-    memcpy(best_clock, &clock, sizeof(intel_clock_t));
-    return true;
+	intel_clock_t clock;
+	if (target < 200000) {
+		clock.p1 = 2;
+		clock.p2 = 10;
+		clock.n = 2;
+		clock.m1 = 23;
+		clock.m2 = 8;
+	} else {
+		clock.p1 = 1;
+		clock.p2 = 10;
+		clock.n = 1;
+		clock.m1 = 14;
+		clock.m2 = 2;
+	}
+	clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
+	clock.p = (clock.p1 * clock.p2);
+	clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
+	clock.vco = 0;
+	memcpy(best_clock, &clock, sizeof(intel_clock_t));
+	return true;
 }
 
 /**
@@ -1007,14 +1011,14 @@
 		   I915_READ(pipestat_reg) | PIPE_VBLANK_INTERRUPT_STATUS);
 
 	/* Wait for vblank interrupt bit to set */
-	if (wait_for((I915_READ(pipestat_reg) &
-		      PIPE_VBLANK_INTERRUPT_STATUS),
-		     50, 0))
+	if (wait_for(I915_READ(pipestat_reg) &
+		     PIPE_VBLANK_INTERRUPT_STATUS,
+		     50))
 		DRM_DEBUG_KMS("vblank wait timed out\n");
 }
 
-/**
- * intel_wait_for_vblank_off - wait for vblank after disabling a pipe
+/*
+ * intel_wait_for_pipe_off - wait for pipe to turn off
  * @dev: drm device
  * @pipe: pipe to wait for
  *
@@ -1022,28 +1026,41 @@
  * spinning on the vblank interrupt status bit, since we won't actually
  * see an interrupt when the pipe is disabled.
  *
- * So this function waits for the display line value to settle (it
- * usually ends up stopping at the start of the next frame).
+ * On Gen4 and above:
+ *   wait for the pipe register state bit to turn off
+ *
+ * Otherwise:
+ *   wait for the display line value to settle (it usually
+ *   ends up stopping at the start of the next frame).
+ *
  */
-void intel_wait_for_vblank_off(struct drm_device *dev, int pipe)
+void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int pipedsl_reg = (pipe == 0 ? PIPEADSL : PIPEBDSL);
-	unsigned long timeout = jiffies + msecs_to_jiffies(100);
-	u32 last_line;
 
-	/* Wait for the display line to settle */
-	do {
-		last_line = I915_READ(pipedsl_reg) & DSL_LINEMASK;
-		mdelay(5);
-	} while (((I915_READ(pipedsl_reg) & DSL_LINEMASK) != last_line) &&
-		 time_after(timeout, jiffies));
+	if (INTEL_INFO(dev)->gen >= 4) {
+		int reg = PIPECONF(pipe);
 
-	if (time_after(jiffies, timeout))
-		DRM_DEBUG_KMS("vblank wait timed out\n");
+		/* Wait for the Pipe State to go off */
+		if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0,
+			     100))
+			DRM_DEBUG_KMS("pipe_off wait timed out\n");
+	} else {
+		u32 last_line;
+		int reg = PIPEDSL(pipe);
+		unsigned long timeout = jiffies + msecs_to_jiffies(100);
+
+		/* Wait for the display line to settle */
+		do {
+			last_line = I915_READ(reg) & DSL_LINEMASK;
+			mdelay(5);
+		} while (((I915_READ(reg) & DSL_LINEMASK) != last_line) &&
+			 time_after(timeout, jiffies));
+		if (time_after(jiffies, timeout))
+			DRM_DEBUG_KMS("pipe_off wait timed out\n");
+	}
 }
 
-/* Parameters have changed, update FBC info */
 static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 {
 	struct drm_device *dev = crtc->dev;
@@ -1055,6 +1072,14 @@
 	int plane, i;
 	u32 fbc_ctl, fbc_ctl2;
 
+	if (fb->pitch == dev_priv->cfb_pitch &&
+	    obj_priv->fence_reg == dev_priv->cfb_fence &&
+	    intel_crtc->plane == dev_priv->cfb_plane &&
+	    I915_READ(FBC_CONTROL) & FBC_CTL_EN)
+		return;
+
+	i8xx_disable_fbc(dev);
+
 	dev_priv->cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
 
 	if (fb->pitch < dev_priv->cfb_pitch)
@@ -1088,7 +1113,7 @@
 	I915_WRITE(FBC_CONTROL, fbc_ctl);
 
 	DRM_DEBUG_KMS("enabled FBC, pitch %ld, yoff %d, plane %d, ",
-		  dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
+		      dev_priv->cfb_pitch, crtc->y, dev_priv->cfb_plane);
 }
 
 void i8xx_disable_fbc(struct drm_device *dev)
@@ -1096,19 +1121,16 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 fbc_ctl;
 
-	if (!I915_HAS_FBC(dev))
-		return;
-
-	if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN))
-		return;	/* Already off, just return */
-
 	/* Disable compression */
 	fbc_ctl = I915_READ(FBC_CONTROL);
+	if ((fbc_ctl & FBC_CTL_EN) == 0)
+		return;
+
 	fbc_ctl &= ~FBC_CTL_EN;
 	I915_WRITE(FBC_CONTROL, fbc_ctl);
 
 	/* Wait for compressing bit to clear */
-	if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10, 0)) {
+	if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
 		DRM_DEBUG_KMS("FBC idle timed out\n");
 		return;
 	}
@@ -1131,14 +1153,27 @@
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int plane = (intel_crtc->plane == 0 ? DPFC_CTL_PLANEA :
-		     DPFC_CTL_PLANEB);
+	int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
 	unsigned long stall_watermark = 200;
 	u32 dpfc_ctl;
 
+	dpfc_ctl = I915_READ(DPFC_CONTROL);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+		    dev_priv->cfb_fence == obj_priv->fence_reg &&
+		    dev_priv->cfb_plane == intel_crtc->plane &&
+		    dev_priv->cfb_y == crtc->y)
+			return;
+
+		I915_WRITE(DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+		POSTING_READ(DPFC_CONTROL);
+		intel_wait_for_vblank(dev, intel_crtc->pipe);
+	}
+
 	dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
 	dev_priv->cfb_fence = obj_priv->fence_reg;
 	dev_priv->cfb_plane = intel_crtc->plane;
+	dev_priv->cfb_y = crtc->y;
 
 	dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
 	if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1148,7 +1183,6 @@
 		I915_WRITE(DPFC_CHICKEN, ~DPFC_HT_MODIFY);
 	}
 
-	I915_WRITE(DPFC_CONTROL, dpfc_ctl);
 	I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
 		   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
 		   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
@@ -1167,10 +1201,12 @@
 
 	/* Disable compression */
 	dpfc_ctl = I915_READ(DPFC_CONTROL);
-	dpfc_ctl &= ~DPFC_CTL_EN;
-	I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		dpfc_ctl &= ~DPFC_CTL_EN;
+		I915_WRITE(DPFC_CONTROL, dpfc_ctl);
 
-	DRM_DEBUG_KMS("disabled FBC\n");
+		DRM_DEBUG_KMS("disabled FBC\n");
+	}
 }
 
 static bool g4x_fbc_enabled(struct drm_device *dev)
@@ -1188,16 +1224,30 @@
 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int plane = (intel_crtc->plane == 0) ? DPFC_CTL_PLANEA :
-					       DPFC_CTL_PLANEB;
+	int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
 	unsigned long stall_watermark = 200;
 	u32 dpfc_ctl;
 
+	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		if (dev_priv->cfb_pitch == dev_priv->cfb_pitch / 64 - 1 &&
+		    dev_priv->cfb_fence == obj_priv->fence_reg &&
+		    dev_priv->cfb_plane == intel_crtc->plane &&
+		    dev_priv->cfb_offset == obj_priv->gtt_offset &&
+		    dev_priv->cfb_y == crtc->y)
+			return;
+
+		I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl & ~DPFC_CTL_EN);
+		POSTING_READ(ILK_DPFC_CONTROL);
+		intel_wait_for_vblank(dev, intel_crtc->pipe);
+	}
+
 	dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1;
 	dev_priv->cfb_fence = obj_priv->fence_reg;
 	dev_priv->cfb_plane = intel_crtc->plane;
+	dev_priv->cfb_offset = obj_priv->gtt_offset;
+	dev_priv->cfb_y = crtc->y;
 
-	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
 	dpfc_ctl &= DPFC_RESERVED;
 	dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
 	if (obj_priv->tiling_mode != I915_TILING_NONE) {
@@ -1207,15 +1257,13 @@
 		I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY);
 	}
 
-	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 	I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
 		   (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
 		   (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
 	I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
 	I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID);
 	/* enable it... */
-	I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) |
-		   DPFC_CTL_EN);
+	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
 	DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
 }
@@ -1227,10 +1275,12 @@
 
 	/* Disable compression */
 	dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-	dpfc_ctl &= ~DPFC_CTL_EN;
-	I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+	if (dpfc_ctl & DPFC_CTL_EN) {
+		dpfc_ctl &= ~DPFC_CTL_EN;
+		I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
 
-	DRM_DEBUG_KMS("disabled FBC\n");
+		DRM_DEBUG_KMS("disabled FBC\n");
+	}
 }
 
 static bool ironlake_fbc_enabled(struct drm_device *dev)
@@ -1272,8 +1322,7 @@
 
 /**
  * intel_update_fbc - enable/disable FBC as needed
- * @crtc: CRTC to point the compressor at
- * @mode: mode in use
+ * @dev: the drm_device
  *
  * Set up the framebuffer compression hardware at mode set time.  We
  * enable it if possible:
@@ -1290,18 +1339,14 @@
  *
  * We need to enable/disable FBC on a global basis.
  */
-static void intel_update_fbc(struct drm_crtc *crtc,
-			     struct drm_display_mode *mode)
+static void intel_update_fbc(struct drm_device *dev)
 {
-	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_framebuffer *fb = crtc->fb;
+	struct drm_crtc *crtc = NULL, *tmp_crtc;
+	struct intel_crtc *intel_crtc;
+	struct drm_framebuffer *fb;
 	struct intel_framebuffer *intel_fb;
 	struct drm_i915_gem_object *obj_priv;
-	struct drm_crtc *tmp_crtc;
-	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	int plane = intel_crtc->plane;
-	int crtcs_enabled = 0;
 
 	DRM_DEBUG_KMS("\n");
 
@@ -1311,12 +1356,6 @@
 	if (!I915_HAS_FBC(dev))
 		return;
 
-	if (!crtc->fb)
-		return;
-
-	intel_fb = to_intel_framebuffer(fb);
-	obj_priv = to_intel_bo(intel_fb->obj);
-
 	/*
 	 * If FBC is already on, we just have to verify that we can
 	 * keep it that way...
@@ -1327,35 +1366,47 @@
 	 *   - going to an unsupported config (interlace, pixel multiply, etc.)
 	 */
 	list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
-		if (tmp_crtc->enabled)
-			crtcs_enabled++;
+		if (tmp_crtc->enabled) {
+			if (crtc) {
+				DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+				dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+				goto out_disable;
+			}
+			crtc = tmp_crtc;
+		}
 	}
-	DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled);
-	if (crtcs_enabled > 1) {
-		DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
-		dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+
+	if (!crtc || crtc->fb == NULL) {
+		DRM_DEBUG_KMS("no output, disabling\n");
+		dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
 		goto out_disable;
 	}
+
+	intel_crtc = to_intel_crtc(crtc);
+	fb = crtc->fb;
+	intel_fb = to_intel_framebuffer(fb);
+	obj_priv = to_intel_bo(intel_fb->obj);
+
 	if (intel_fb->obj->size > dev_priv->cfb_size) {
 		DRM_DEBUG_KMS("framebuffer too large, disabling "
-				"compression\n");
+			      "compression\n");
 		dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
 		goto out_disable;
 	}
-	if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
-	    (mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
+	if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
+	    (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
 		DRM_DEBUG_KMS("mode incompatible with compression, "
-				"disabling\n");
+			      "disabling\n");
 		dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
 		goto out_disable;
 	}
-	if ((mode->hdisplay > 2048) ||
-	    (mode->vdisplay > 1536)) {
+	if ((crtc->mode.hdisplay > 2048) ||
+	    (crtc->mode.vdisplay > 1536)) {
 		DRM_DEBUG_KMS("mode too large for compression, disabling\n");
 		dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
 		goto out_disable;
 	}
-	if ((IS_I915GM(dev) || IS_I945GM(dev)) && plane != 0) {
+	if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
 		DRM_DEBUG_KMS("plane not 0, disabling compression\n");
 		dev_priv->no_fbc_reason = FBC_BAD_PLANE;
 		goto out_disable;
@@ -1370,18 +1421,7 @@
 	if (in_dbg_master())
 		goto out_disable;
 
-	if (intel_fbc_enabled(dev)) {
-		/* We can re-enable it in this case, but need to update pitch */
-		if ((fb->pitch > dev_priv->cfb_pitch) ||
-		    (obj_priv->fence_reg != dev_priv->cfb_fence) ||
-		    (plane != dev_priv->cfb_plane))
-			intel_disable_fbc(dev);
-	}
-
-	/* Now try to turn it back on if possible */
-	if (!intel_fbc_enabled(dev))
-		intel_enable_fbc(crtc, 500);
-
+	intel_enable_fbc(crtc, 500);
 	return;
 
 out_disable:
@@ -1393,7 +1433,9 @@
 }
 
 int
-intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
+intel_pin_and_fence_fb_obj(struct drm_device *dev,
+			   struct drm_gem_object *obj,
+			   bool pipelined)
 {
 	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 	u32 alignment;
@@ -1403,7 +1445,7 @@
 	case I915_TILING_NONE:
 		if (IS_BROADWATER(dev) || IS_CRESTLINE(dev))
 			alignment = 128 * 1024;
-		else if (IS_I965G(dev))
+		else if (INTEL_INFO(dev)->gen >= 4)
 			alignment = 4 * 1024;
 		else
 			alignment = 64 * 1024;
@@ -1421,9 +1463,13 @@
 	}
 
 	ret = i915_gem_object_pin(obj, alignment);
-	if (ret != 0)
+	if (ret)
 		return ret;
 
+	ret = i915_gem_object_set_to_display_plane(obj, pipelined);
+	if (ret)
+		goto err_unpin;
+
 	/* Install a fence for tiled scan-out. Pre-i965 always needs a
 	 * fence, whereas 965+ only requires a fence if using
 	 * framebuffer compression.  For simplicity, we always install
@@ -1431,14 +1477,16 @@
 	 */
 	if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
 	    obj_priv->tiling_mode != I915_TILING_NONE) {
-		ret = i915_gem_object_get_fence_reg(obj);
-		if (ret != 0) {
-			i915_gem_object_unpin(obj);
-			return ret;
-		}
+		ret = i915_gem_object_get_fence_reg(obj, false);
+		if (ret)
+			goto err_unpin;
 	}
 
 	return 0;
+
+err_unpin:
+	i915_gem_object_unpin(obj);
+	return ret;
 }
 
 /* Assume fb object is pinned & idle & fenced and just update base pointers */
@@ -1454,12 +1502,8 @@
 	struct drm_gem_object *obj;
 	int plane = intel_crtc->plane;
 	unsigned long Start, Offset;
-	int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR);
-	int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF);
-	int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE;
-	int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF);
-	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
 	u32 dspcntr;
+	u32 reg;
 
 	switch (plane) {
 	case 0:
@@ -1474,7 +1518,8 @@
 	obj = intel_fb->obj;
 	obj_priv = to_intel_bo(obj);
 
-	dspcntr = I915_READ(dspcntr_reg);
+	reg = DSPCNTR(plane);
+	dspcntr = I915_READ(reg);
 	/* Mask out pixel format bits in case we change it */
 	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 	switch (fb->bits_per_pixel) {
@@ -1495,7 +1540,7 @@
 		DRM_ERROR("Unknown color depth\n");
 		return -EINVAL;
 	}
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		if (obj_priv->tiling_mode != I915_TILING_NONE)
 			dspcntr |= DISPPLANE_TILED;
 		else
@@ -1506,28 +1551,24 @@
 		/* must disable */
 		dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
-	I915_WRITE(dspcntr_reg, dspcntr);
+	I915_WRITE(reg, dspcntr);
 
 	Start = obj_priv->gtt_offset;
 	Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8);
 
 	DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
 		      Start, Offset, x, y, fb->pitch);
-	I915_WRITE(dspstride, fb->pitch);
-	if (IS_I965G(dev)) {
-		I915_WRITE(dspsurf, Start);
-		I915_WRITE(dsptileoff, (y << 16) | x);
-		I915_WRITE(dspbase, Offset);
-	} else {
-		I915_WRITE(dspbase, Start + Offset);
-	}
-	POSTING_READ(dspbase);
+	I915_WRITE(DSPSTRIDE(plane), fb->pitch);
+	if (INTEL_INFO(dev)->gen >= 4) {
+		I915_WRITE(DSPSURF(plane), Start);
+		I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
+		I915_WRITE(DSPADDR(plane), Offset);
+	} else
+		I915_WRITE(DSPADDR(plane), Start + Offset);
+	POSTING_READ(reg);
 
-	if (IS_I965G(dev) || plane == 0)
-		intel_update_fbc(crtc, &crtc->mode);
-
-	intel_wait_for_vblank(dev, intel_crtc->pipe);
-	intel_increase_pllclock(crtc, true);
+	intel_update_fbc(dev);
+	intel_increase_pllclock(crtc);
 
 	return 0;
 }
@@ -1539,11 +1580,6 @@
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_master_private *master_priv;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_framebuffer *intel_fb;
-	struct drm_i915_gem_object *obj_priv;
-	struct drm_gem_object *obj;
-	int pipe = intel_crtc->pipe;
-	int plane = intel_crtc->plane;
 	int ret;
 
 	/* no fb bound */
@@ -1552,46 +1588,42 @@
 		return 0;
 	}
 
-	switch (plane) {
+	switch (intel_crtc->plane) {
 	case 0:
 	case 1:
 		break;
 	default:
-		DRM_ERROR("Can't update plane %d in SAREA\n", plane);
 		return -EINVAL;
 	}
 
-	intel_fb = to_intel_framebuffer(crtc->fb);
-	obj = intel_fb->obj;
-	obj_priv = to_intel_bo(obj);
-
 	mutex_lock(&dev->struct_mutex);
-	ret = intel_pin_and_fence_fb_obj(dev, obj);
+	ret = intel_pin_and_fence_fb_obj(dev,
+					 to_intel_framebuffer(crtc->fb)->obj,
+					 false);
 	if (ret != 0) {
 		mutex_unlock(&dev->struct_mutex);
 		return ret;
 	}
 
-	ret = i915_gem_object_set_to_display_plane(obj);
-	if (ret != 0) {
-		i915_gem_object_unpin(obj);
-		mutex_unlock(&dev->struct_mutex);
-		return ret;
-	}
-
-	ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y);
-	if (ret) {
-		i915_gem_object_unpin(obj);
-		mutex_unlock(&dev->struct_mutex);
-		return ret;
-	}
-
 	if (old_fb) {
-		intel_fb = to_intel_framebuffer(old_fb);
-		obj_priv = to_intel_bo(intel_fb->obj);
-		i915_gem_object_unpin(intel_fb->obj);
+		struct drm_i915_private *dev_priv = dev->dev_private;
+		struct drm_gem_object *obj = to_intel_framebuffer(old_fb)->obj;
+		struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+
+		wait_event(dev_priv->pending_flip_queue,
+			   atomic_read(&obj_priv->pending_flip) == 0);
 	}
 
+	ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y);
+	if (ret) {
+		i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+		mutex_unlock(&dev->struct_mutex);
+		return ret;
+	}
+
+	if (old_fb)
+		i915_gem_object_unpin(to_intel_framebuffer(old_fb)->obj);
+
 	mutex_unlock(&dev->struct_mutex);
 
 	if (!dev->primary->master)
@@ -1601,7 +1633,7 @@
 	if (!master_priv->sarea_priv)
 		return 0;
 
-	if (pipe) {
+	if (intel_crtc->pipe) {
 		master_priv->sarea_priv->pipeB_x = x;
 		master_priv->sarea_priv->pipeB_y = y;
 	} else {
@@ -1612,7 +1644,7 @@
 	return 0;
 }
 
-static void ironlake_set_pll_edp (struct drm_crtc *crtc, int clock)
+static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1645,6 +1677,7 @@
 	}
 	I915_WRITE(DP_A, dpa_ctl);
 
+	POSTING_READ(DP_A);
 	udelay(500);
 }
 
@@ -1655,84 +1688,84 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-	int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-	int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
-	u32 temp, tries = 0;
+	u32 reg, temp, tries;
 
 	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
 	   for train result */
-	temp = I915_READ(fdi_rx_imr_reg);
+	reg = FDI_RX_IMR(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_RX_SYMBOL_LOCK;
 	temp &= ~FDI_RX_BIT_LOCK;
-	I915_WRITE(fdi_rx_imr_reg, temp);
-	I915_READ(fdi_rx_imr_reg);
+	I915_WRITE(reg, temp);
+	I915_READ(reg);
 	udelay(150);
 
 	/* enable CPU FDI TX and PCH FDI RX */
-	temp = I915_READ(fdi_tx_reg);
-	temp |= FDI_TX_ENABLE;
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~(7 << 19);
 	temp |= (intel_crtc->fdi_lanes - 1) << 19;
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_1;
-	I915_WRITE(fdi_tx_reg, temp);
-	I915_READ(fdi_tx_reg);
+	I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-	temp = I915_READ(fdi_rx_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_1;
-	I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-	I915_READ(fdi_rx_reg);
+	I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+	POSTING_READ(reg);
 	udelay(150);
 
+	reg = FDI_RX_IIR(pipe);
 	for (tries = 0; tries < 5; tries++) {
-		temp = I915_READ(fdi_rx_iir_reg);
+		temp = I915_READ(reg);
 		DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
 		if ((temp & FDI_RX_BIT_LOCK)) {
 			DRM_DEBUG_KMS("FDI train 1 done.\n");
-			I915_WRITE(fdi_rx_iir_reg,
-				   temp | FDI_RX_BIT_LOCK);
+			I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
 			break;
 		}
 	}
 	if (tries == 5)
-		DRM_DEBUG_KMS("FDI train 1 fail!\n");
+		DRM_ERROR("FDI train 1 fail!\n");
 
 	/* Train 2 */
-	temp = I915_READ(fdi_tx_reg);
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_2;
-	I915_WRITE(fdi_tx_reg, temp);
+	I915_WRITE(reg, temp);
 
-	temp = I915_READ(fdi_rx_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_2;
-	I915_WRITE(fdi_rx_reg, temp);
+	I915_WRITE(reg, temp);
+
+	POSTING_READ(reg);
 	udelay(150);
 
-	tries = 0;
-
+	reg = FDI_RX_IIR(pipe);
 	for (tries = 0; tries < 5; tries++) {
-		temp = I915_READ(fdi_rx_iir_reg);
+		temp = I915_READ(reg);
 		DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
 		if (temp & FDI_RX_SYMBOL_LOCK) {
-			I915_WRITE(fdi_rx_iir_reg,
-				   temp | FDI_RX_SYMBOL_LOCK);
+			I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
 			DRM_DEBUG_KMS("FDI train 2 done.\n");
 			break;
 		}
 	}
 	if (tries == 5)
-		DRM_DEBUG_KMS("FDI train 2 fail!\n");
+		DRM_ERROR("FDI train 2 fail!\n");
 
 	DRM_DEBUG_KMS("FDI train done\n");
 }
 
-static int snb_b_fdi_train_param [] = {
+static const int const snb_b_fdi_train_param [] = {
 	FDI_LINK_TRAIN_400MV_0DB_SNB_B,
 	FDI_LINK_TRAIN_400MV_6DB_SNB_B,
 	FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
@@ -1746,24 +1779,22 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
-	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-	int fdi_rx_iir_reg = (pipe == 0) ? FDI_RXA_IIR : FDI_RXB_IIR;
-	int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
-	u32 temp, i;
+	u32 reg, temp, i;
 
 	/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
 	   for train result */
-	temp = I915_READ(fdi_rx_imr_reg);
+	reg = FDI_RX_IMR(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_RX_SYMBOL_LOCK;
 	temp &= ~FDI_RX_BIT_LOCK;
-	I915_WRITE(fdi_rx_imr_reg, temp);
-	I915_READ(fdi_rx_imr_reg);
+	I915_WRITE(reg, temp);
+
+	POSTING_READ(reg);
 	udelay(150);
 
 	/* enable CPU FDI TX and PCH FDI RX */
-	temp = I915_READ(fdi_tx_reg);
-	temp |= FDI_TX_ENABLE;
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~(7 << 19);
 	temp |= (intel_crtc->fdi_lanes - 1) << 19;
 	temp &= ~FDI_LINK_TRAIN_NONE;
@@ -1771,10 +1802,10 @@
 	temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
 	/* SNB-B */
 	temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
-	I915_WRITE(fdi_tx_reg, temp);
-	I915_READ(fdi_tx_reg);
+	I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
-	temp = I915_READ(fdi_rx_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
 	if (HAS_PCH_CPT(dev)) {
 		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
 		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
@@ -1782,32 +1813,37 @@
 		temp &= ~FDI_LINK_TRAIN_NONE;
 		temp |= FDI_LINK_TRAIN_PATTERN_1;
 	}
-	I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-	I915_READ(fdi_rx_reg);
+	I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+	POSTING_READ(reg);
 	udelay(150);
 
 	for (i = 0; i < 4; i++ ) {
-		temp = I915_READ(fdi_tx_reg);
+		reg = FDI_TX_CTL(pipe);
+		temp = I915_READ(reg);
 		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
 		temp |= snb_b_fdi_train_param[i];
-		I915_WRITE(fdi_tx_reg, temp);
+		I915_WRITE(reg, temp);
+
+		POSTING_READ(reg);
 		udelay(500);
 
-		temp = I915_READ(fdi_rx_iir_reg);
+		reg = FDI_RX_IIR(pipe);
+		temp = I915_READ(reg);
 		DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
 		if (temp & FDI_RX_BIT_LOCK) {
-			I915_WRITE(fdi_rx_iir_reg,
-				   temp | FDI_RX_BIT_LOCK);
+			I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
 			DRM_DEBUG_KMS("FDI train 1 done.\n");
 			break;
 		}
 	}
 	if (i == 4)
-		DRM_DEBUG_KMS("FDI train 1 fail!\n");
+		DRM_ERROR("FDI train 1 fail!\n");
 
 	/* Train 2 */
-	temp = I915_READ(fdi_tx_reg);
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
 	temp &= ~FDI_LINK_TRAIN_NONE;
 	temp |= FDI_LINK_TRAIN_PATTERN_2;
 	if (IS_GEN6(dev)) {
@@ -1815,9 +1851,10 @@
 		/* SNB-B */
 		temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
 	}
-	I915_WRITE(fdi_tx_reg, temp);
+	I915_WRITE(reg, temp);
 
-	temp = I915_READ(fdi_rx_reg);
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
 	if (HAS_PCH_CPT(dev)) {
 		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
 		temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
@@ -1825,64 +1862,437 @@
 		temp &= ~FDI_LINK_TRAIN_NONE;
 		temp |= FDI_LINK_TRAIN_PATTERN_2;
 	}
-	I915_WRITE(fdi_rx_reg, temp);
+	I915_WRITE(reg, temp);
+
+	POSTING_READ(reg);
 	udelay(150);
 
 	for (i = 0; i < 4; i++ ) {
-		temp = I915_READ(fdi_tx_reg);
+		reg = FDI_TX_CTL(pipe);
+		temp = I915_READ(reg);
 		temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
 		temp |= snb_b_fdi_train_param[i];
-		I915_WRITE(fdi_tx_reg, temp);
+		I915_WRITE(reg, temp);
+
+		POSTING_READ(reg);
 		udelay(500);
 
-		temp = I915_READ(fdi_rx_iir_reg);
+		reg = FDI_RX_IIR(pipe);
+		temp = I915_READ(reg);
 		DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
 
 		if (temp & FDI_RX_SYMBOL_LOCK) {
-			I915_WRITE(fdi_rx_iir_reg,
-				   temp | FDI_RX_SYMBOL_LOCK);
+			I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
 			DRM_DEBUG_KMS("FDI train 2 done.\n");
 			break;
 		}
 	}
 	if (i == 4)
-		DRM_DEBUG_KMS("FDI train 2 fail!\n");
+		DRM_ERROR("FDI train 2 fail!\n");
 
 	DRM_DEBUG_KMS("FDI train done.\n");
 }
 
-static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void ironlake_fdi_enable(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;
+	u32 reg, temp;
+
+	/* Write the TU size bits so error detection works */
+	I915_WRITE(FDI_RX_TUSIZE1(pipe),
+		   I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
+
+	/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	temp &= ~((0x7 << 19) | (0x7 << 16));
+	temp |= (intel_crtc->fdi_lanes - 1) << 19;
+	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
+
+	POSTING_READ(reg);
+	udelay(200);
+
+	/* Switch from Rawclk to PCDclk */
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp | FDI_PCDCLK);
+
+	POSTING_READ(reg);
+	udelay(200);
+
+	/* Enable CPU FDI TX PLL, always on for Ironlake */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+		I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
+
+		POSTING_READ(reg);
+		udelay(100);
+	}
+}
+
+static void intel_flush_display_plane(struct drm_device *dev,
+				      int plane)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 reg = DSPADDR(plane);
+	I915_WRITE(reg, I915_READ(reg));
+}
+
+/*
+ * When we disable a pipe, we need to clear any pending scanline wait events
+ * to avoid hanging the ring, which we assume we are waiting on.
+ */
+static void intel_clear_scanline_wait(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 tmp;
+
+	if (IS_GEN2(dev))
+		/* Can't break the hang on i8xx */
+		return;
+
+	tmp = I915_READ(PRB0_CTL);
+	if (tmp & RING_WAIT) {
+		I915_WRITE(PRB0_CTL, tmp);
+		POSTING_READ(PRB0_CTL);
+	}
+}
+
+static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
+{
+	struct drm_i915_gem_object *obj_priv;
+	struct drm_i915_private *dev_priv;
+
+	if (crtc->fb == NULL)
+		return;
+
+	obj_priv = to_intel_bo(to_intel_framebuffer(crtc->fb)->obj);
+	dev_priv = crtc->dev->dev_private;
+	wait_event(dev_priv->pending_flip_queue,
+		   atomic_read(&obj_priv->pending_flip) == 0);
+}
+
+static void ironlake_crtc_enable(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;
 	int plane = intel_crtc->plane;
-	int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-	int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-	int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
-	int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-	int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-	int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-	int cpu_vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-	int cpu_vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-	int cpu_vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-	int trans_htot_reg = (pipe == 0) ? TRANS_HTOTAL_A : TRANS_HTOTAL_B;
-	int trans_hblank_reg = (pipe == 0) ? TRANS_HBLANK_A : TRANS_HBLANK_B;
-	int trans_hsync_reg = (pipe == 0) ? TRANS_HSYNC_A : TRANS_HSYNC_B;
-	int trans_vtot_reg = (pipe == 0) ? TRANS_VTOTAL_A : TRANS_VTOTAL_B;
-	int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
-	int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
-	int trans_dpll_sel = (pipe == 0) ? 0 : 1;
-	u32 temp;
-	u32 pipe_bpc;
+	u32 reg, temp;
 
-	temp = I915_READ(pipeconf_reg);
-	pipe_bpc = temp & PIPE_BPC_MASK;
+	if (intel_crtc->active)
+		return;
+
+	intel_crtc->active = true;
+	intel_update_watermarks(dev);
+
+	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+		temp = I915_READ(PCH_LVDS);
+		if ((temp & LVDS_PORT_EN) == 0)
+			I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
+	}
+
+	ironlake_fdi_enable(crtc);
+
+	/* Enable panel fitting for LVDS */
+	if (dev_priv->pch_pf_size &&
+	    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
+	     || HAS_eDP || intel_pch_has_edp(crtc))) {
+		/* Force use of hard-coded filter coefficients
+		 * as some pre-programmed values are broken,
+		 * e.g. x201.
+		 */
+		I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
+			   PF_ENABLE | PF_FILTER_MED_3x3);
+		I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
+			   dev_priv->pch_pf_pos);
+		I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
+			   dev_priv->pch_pf_size);
+	}
+
+	/* Enable CPU pipe */
+	reg = PIPECONF(pipe);
+	temp = I915_READ(reg);
+	if ((temp & PIPECONF_ENABLE) == 0) {
+		I915_WRITE(reg, temp | PIPECONF_ENABLE);
+		POSTING_READ(reg);
+		udelay(100);
+	}
+
+	/* configure and enable CPU plane */
+	reg = DSPCNTR(plane);
+	temp = I915_READ(reg);
+	if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+		I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+		intel_flush_display_plane(dev, plane);
+	}
+
+	/* For PCH output, training FDI link */
+	if (IS_GEN6(dev))
+		gen6_fdi_link_train(crtc);
+	else
+		ironlake_fdi_link_train(crtc);
+
+	/* enable PCH DPLL */
+	reg = PCH_DPLL(pipe);
+	temp = I915_READ(reg);
+	if ((temp & DPLL_VCO_ENABLE) == 0) {
+		I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+		POSTING_READ(reg);
+		udelay(200);
+	}
+
+	if (HAS_PCH_CPT(dev)) {
+		/* Be sure PCH DPLL SEL is set */
+		temp = I915_READ(PCH_DPLL_SEL);
+		if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
+			temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+		else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
+			temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+		I915_WRITE(PCH_DPLL_SEL, temp);
+	}
+
+	/* set transcoder timing */
+	I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
+	I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
+	I915_WRITE(TRANS_HSYNC(pipe),  I915_READ(HSYNC(pipe)));
+
+	I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
+	I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
+	I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
+
+	/* enable normal train */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+	I915_WRITE(reg, temp);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	if (HAS_PCH_CPT(dev)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_NORMAL_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_NONE;
+	}
+	I915_WRITE(reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
+
+	/* wait one idle pattern time */
+	POSTING_READ(reg);
+	udelay(100);
+
+	/* For PCH DP, enable TRANS_DP_CTL */
+	if (HAS_PCH_CPT(dev) &&
+	    intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+		reg = TRANS_DP_CTL(pipe);
+		temp = I915_READ(reg);
+		temp &= ~(TRANS_DP_PORT_SEL_MASK |
+			  TRANS_DP_SYNC_MASK);
+		temp |= (TRANS_DP_OUTPUT_ENABLE |
+			 TRANS_DP_ENH_FRAMING);
+
+		if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
+			temp |= TRANS_DP_HSYNC_ACTIVE_HIGH;
+		if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
+			temp |= TRANS_DP_VSYNC_ACTIVE_HIGH;
+
+		switch (intel_trans_dp_port_sel(crtc)) {
+		case PCH_DP_B:
+			temp |= TRANS_DP_PORT_SEL_B;
+			break;
+		case PCH_DP_C:
+			temp |= TRANS_DP_PORT_SEL_C;
+			break;
+		case PCH_DP_D:
+			temp |= TRANS_DP_PORT_SEL_D;
+			break;
+		default:
+			DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
+			temp |= TRANS_DP_PORT_SEL_B;
+			break;
+		}
+
+		I915_WRITE(reg, temp);
+	}
+
+	/* enable PCH transcoder */
+	reg = TRANSCONF(pipe);
+	temp = I915_READ(reg);
+	/*
+	 * make the BPC in transcoder be consistent with
+	 * that in pipeconf reg.
+	 */
+	temp &= ~PIPE_BPC_MASK;
+	temp |= I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK;
+	I915_WRITE(reg, temp | TRANS_ENABLE);
+	if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
+		DRM_ERROR("failed to enable transcoder\n");
+
+	intel_crtc_load_lut(crtc);
+	intel_update_fbc(dev);
+	intel_crtc_update_cursor(crtc, true);
+}
+
+static void ironlake_crtc_disable(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;
+	int plane = intel_crtc->plane;
+	u32 reg, temp;
+
+	if (!intel_crtc->active)
+		return;
+
+	intel_crtc_wait_for_pending_flips(crtc);
+	drm_vblank_off(dev, pipe);
+	intel_crtc_update_cursor(crtc, false);
+
+	/* Disable display plane */
+	reg = DSPCNTR(plane);
+	temp = I915_READ(reg);
+	if (temp & DISPLAY_PLANE_ENABLE) {
+		I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+		intel_flush_display_plane(dev, plane);
+	}
+
+	if (dev_priv->cfb_plane == plane &&
+	    dev_priv->display.disable_fbc)
+		dev_priv->display.disable_fbc(dev);
+
+	/* disable cpu pipe, disable after all planes disabled */
+	reg = PIPECONF(pipe);
+	temp = I915_READ(reg);
+	if (temp & PIPECONF_ENABLE) {
+		I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
+		/* wait for cpu pipe off, pipe state */
+		if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, 50))
+			DRM_ERROR("failed to turn off cpu pipe\n");
+	}
+
+	/* Disable PF */
+	I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
+	I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
+
+	/* disable CPU FDI tx and PCH FDI rx */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~FDI_TX_ENABLE);
+	POSTING_READ(reg);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	temp &= ~(0x7 << 16);
+	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	I915_WRITE(reg, temp & ~FDI_RX_ENABLE);
+
+	POSTING_READ(reg);
+	udelay(100);
+
+	/* still set train pattern 1 */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	temp &= ~FDI_LINK_TRAIN_NONE;
+	temp |= FDI_LINK_TRAIN_PATTERN_1;
+	I915_WRITE(reg, temp);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	if (HAS_PCH_CPT(dev)) {
+		temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+		temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+	} else {
+		temp &= ~FDI_LINK_TRAIN_NONE;
+		temp |= FDI_LINK_TRAIN_PATTERN_1;
+	}
+	/* BPC in FDI rx is consistent with that in PIPECONF */
+	temp &= ~(0x07 << 16);
+	temp |= (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) << 11;
+	I915_WRITE(reg, temp);
+
+	POSTING_READ(reg);
+	udelay(100);
+
+	if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+		temp = I915_READ(PCH_LVDS);
+		if (temp & LVDS_PORT_EN) {
+			I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
+			POSTING_READ(PCH_LVDS);
+			udelay(100);
+		}
+	}
+
+	/* disable PCH transcoder */
+	reg = TRANSCONF(plane);
+	temp = I915_READ(reg);
+	if (temp & TRANS_ENABLE) {
+		I915_WRITE(reg, temp & ~TRANS_ENABLE);
+		/* wait for PCH transcoder off, transcoder state */
+		if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
+			DRM_ERROR("failed to disable transcoder\n");
+	}
+
+	if (HAS_PCH_CPT(dev)) {
+		/* disable TRANS_DP_CTL */
+		reg = TRANS_DP_CTL(pipe);
+		temp = I915_READ(reg);
+		temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
+		I915_WRITE(reg, temp);
+
+		/* disable DPLL_SEL */
+		temp = I915_READ(PCH_DPLL_SEL);
+		if (pipe == 0)
+			temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
+		else
+			temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+		I915_WRITE(PCH_DPLL_SEL, temp);
+	}
+
+	/* disable PCH DPLL */
+	reg = PCH_DPLL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
+
+	/* Switch from PCDclk to Rawclk */
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~FDI_PCDCLK);
+
+	/* Disable CPU FDI TX PLL */
+	reg = FDI_TX_CTL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~FDI_TX_PLL_ENABLE);
+
+	POSTING_READ(reg);
+	udelay(100);
+
+	reg = FDI_RX_CTL(pipe);
+	temp = I915_READ(reg);
+	I915_WRITE(reg, temp & ~FDI_RX_PLL_ENABLE);
+
+	/* Wait for the clocks to turn off. */
+	POSTING_READ(reg);
+	udelay(100);
+
+	intel_crtc->active = false;
+	intel_update_watermarks(dev);
+	intel_update_fbc(dev);
+	intel_clear_scanline_wait(dev);
+}
+
+static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	int plane = intel_crtc->plane;
 
 	/* XXX: When our outputs are all unaware of DPMS modes other than off
 	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
@@ -1892,379 +2302,160 @@
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 		DRM_DEBUG_KMS("crtc %d/%d dpms on\n", pipe, plane);
-
-		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-			temp = I915_READ(PCH_LVDS);
-			if ((temp & LVDS_PORT_EN) == 0) {
-				I915_WRITE(PCH_LVDS, temp | LVDS_PORT_EN);
-				POSTING_READ(PCH_LVDS);
-			}
-		}
-
-		if (!HAS_eDP) {
-
-			/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
-			temp = I915_READ(fdi_rx_reg);
-			/*
-			 * make the BPC in FDI Rx be consistent with that in
-			 * pipeconf reg.
-			 */
-			temp &= ~(0x7 << 16);
-			temp |= (pipe_bpc << 11);
-			temp &= ~(7 << 19);
-			temp |= (intel_crtc->fdi_lanes - 1) << 19;
-			I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-			I915_READ(fdi_rx_reg);
-			udelay(200);
-
-			/* Switch from Rawclk to PCDclk */
-			temp = I915_READ(fdi_rx_reg);
-			I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-			I915_READ(fdi_rx_reg);
-			udelay(200);
-
-			/* Enable CPU FDI TX PLL, always on for Ironlake */
-			temp = I915_READ(fdi_tx_reg);
-			if ((temp & FDI_TX_PLL_ENABLE) == 0) {
-				I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-				I915_READ(fdi_tx_reg);
-				udelay(100);
-			}
-		}
-
-		/* Enable panel fitting for LVDS */
-		if (dev_priv->pch_pf_size &&
-		    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
-		    || HAS_eDP || intel_pch_has_edp(crtc))) {
-			/* Force use of hard-coded filter coefficients
-			 * as some pre-programmed values are broken,
-			 * e.g. x201.
-			 */
-			I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
-				   PF_ENABLE | PF_FILTER_MED_3x3);
-			I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
-				   dev_priv->pch_pf_pos);
-			I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
-				   dev_priv->pch_pf_size);
-		}
-
-		/* Enable CPU pipe */
-		temp = I915_READ(pipeconf_reg);
-		if ((temp & PIPEACONF_ENABLE) == 0) {
-			I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-			I915_READ(pipeconf_reg);
-			udelay(100);
-		}
-
-		/* configure and enable CPU plane */
-		temp = I915_READ(dspcntr_reg);
-		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-			I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-		}
-
-		if (!HAS_eDP) {
-			/* For PCH output, training FDI link */
-			if (IS_GEN6(dev))
-				gen6_fdi_link_train(crtc);
-			else
-				ironlake_fdi_link_train(crtc);
-
-			/* enable PCH DPLL */
-			temp = I915_READ(pch_dpll_reg);
-			if ((temp & DPLL_VCO_ENABLE) == 0) {
-				I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
-				I915_READ(pch_dpll_reg);
-			}
-			udelay(200);
-
-			if (HAS_PCH_CPT(dev)) {
-				/* Be sure PCH DPLL SEL is set */
-				temp = I915_READ(PCH_DPLL_SEL);
-				if (trans_dpll_sel == 0 &&
-						(temp & TRANSA_DPLL_ENABLE) == 0)
-					temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
-				else if (trans_dpll_sel == 1 &&
-						(temp & TRANSB_DPLL_ENABLE) == 0)
-					temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-				I915_WRITE(PCH_DPLL_SEL, temp);
-				I915_READ(PCH_DPLL_SEL);
-			}
-
-			/* set transcoder timing */
-			I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
-			I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
-			I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
-
-			I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
-			I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
-			I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
-
-			/* enable normal train */
-			temp = I915_READ(fdi_tx_reg);
-			temp &= ~FDI_LINK_TRAIN_NONE;
-			I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
-					FDI_TX_ENHANCE_FRAME_ENABLE);
-			I915_READ(fdi_tx_reg);
-
-			temp = I915_READ(fdi_rx_reg);
-			if (HAS_PCH_CPT(dev)) {
-				temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-				temp |= FDI_LINK_TRAIN_NORMAL_CPT;
-			} else {
-				temp &= ~FDI_LINK_TRAIN_NONE;
-				temp |= FDI_LINK_TRAIN_NONE;
-			}
-			I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENHANCE_FRAME_ENABLE);
-			I915_READ(fdi_rx_reg);
-
-			/* wait one idle pattern time */
-			udelay(100);
-
-			/* For PCH DP, enable TRANS_DP_CTL */
-			if (HAS_PCH_CPT(dev) &&
-			    intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
-				int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
-				int reg;
-
-				reg = I915_READ(trans_dp_ctl);
-				reg &= ~(TRANS_DP_PORT_SEL_MASK |
-					 TRANS_DP_SYNC_MASK);
-				reg |= (TRANS_DP_OUTPUT_ENABLE |
-					TRANS_DP_ENH_FRAMING);
-
-				if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC)
-				      reg |= TRANS_DP_HSYNC_ACTIVE_HIGH;
-				if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC)
-				      reg |= TRANS_DP_VSYNC_ACTIVE_HIGH;
-
-				switch (intel_trans_dp_port_sel(crtc)) {
-				case PCH_DP_B:
-					reg |= TRANS_DP_PORT_SEL_B;
-					break;
-				case PCH_DP_C:
-					reg |= TRANS_DP_PORT_SEL_C;
-					break;
-				case PCH_DP_D:
-					reg |= TRANS_DP_PORT_SEL_D;
-					break;
-				default:
-					DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
-					reg |= TRANS_DP_PORT_SEL_B;
-					break;
-				}
-
-				I915_WRITE(trans_dp_ctl, reg);
-				POSTING_READ(trans_dp_ctl);
-			}
-
-			/* enable PCH transcoder */
-			temp = I915_READ(transconf_reg);
-			/*
-			 * make the BPC in transcoder be consistent with
-			 * that in pipeconf reg.
-			 */
-			temp &= ~PIPE_BPC_MASK;
-			temp |= pipe_bpc;
-			I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
-			I915_READ(transconf_reg);
-
-			if (wait_for(I915_READ(transconf_reg) & TRANS_STATE_ENABLE, 100, 1))
-				DRM_ERROR("failed to enable transcoder\n");
-		}
-
-		intel_crtc_load_lut(crtc);
-
-		intel_update_fbc(crtc, &crtc->mode);
+		ironlake_crtc_enable(crtc);
 		break;
 
 	case DRM_MODE_DPMS_OFF:
 		DRM_DEBUG_KMS("crtc %d/%d dpms off\n", pipe, plane);
-
-		drm_vblank_off(dev, pipe);
-		/* Disable display plane */
-		temp = I915_READ(dspcntr_reg);
-		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-			I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-			I915_READ(dspbase_reg);
-		}
-
-		if (dev_priv->cfb_plane == plane &&
-		    dev_priv->display.disable_fbc)
-			dev_priv->display.disable_fbc(dev);
-
-		/* disable cpu pipe, disable after all planes disabled */
-		temp = I915_READ(pipeconf_reg);
-		if ((temp & PIPEACONF_ENABLE) != 0) {
-			I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
-
-			/* wait for cpu pipe off, pipe state */
-			if (wait_for((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) == 0, 50, 1))
-				DRM_ERROR("failed to turn off cpu pipe\n");
-		} else
-			DRM_DEBUG_KMS("crtc %d is disabled\n", pipe);
-
-		udelay(100);
-
-		/* Disable PF */
-		I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1, 0);
-		I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ, 0);
-
-		/* disable CPU FDI tx and PCH FDI rx */
-		temp = I915_READ(fdi_tx_reg);
-		I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
-		I915_READ(fdi_tx_reg);
-
-		temp = I915_READ(fdi_rx_reg);
-		/* BPC in FDI rx is consistent with that in pipeconf */
-		temp &= ~(0x07 << 16);
-		temp |= (pipe_bpc << 11);
-		I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
-		I915_READ(fdi_rx_reg);
-
-		udelay(100);
-
-		/* still set train pattern 1 */
-		temp = I915_READ(fdi_tx_reg);
-		temp &= ~FDI_LINK_TRAIN_NONE;
-		temp |= FDI_LINK_TRAIN_PATTERN_1;
-		I915_WRITE(fdi_tx_reg, temp);
-		POSTING_READ(fdi_tx_reg);
-
-		temp = I915_READ(fdi_rx_reg);
-		if (HAS_PCH_CPT(dev)) {
-			temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
-			temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
-		} else {
-			temp &= ~FDI_LINK_TRAIN_NONE;
-			temp |= FDI_LINK_TRAIN_PATTERN_1;
-		}
-		I915_WRITE(fdi_rx_reg, temp);
-		POSTING_READ(fdi_rx_reg);
-
-		udelay(100);
-
-		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
-			temp = I915_READ(PCH_LVDS);
-			I915_WRITE(PCH_LVDS, temp & ~LVDS_PORT_EN);
-			I915_READ(PCH_LVDS);
-			udelay(100);
-		}
-
-		/* disable PCH transcoder */
-		temp = I915_READ(transconf_reg);
-		if ((temp & TRANS_ENABLE) != 0) {
-			I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
-
-			/* wait for PCH transcoder off, transcoder state */
-			if (wait_for((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0, 50, 1))
-				DRM_ERROR("failed to disable transcoder\n");
-		}
-
-		temp = I915_READ(transconf_reg);
-		/* BPC in transcoder is consistent with that in pipeconf */
-		temp &= ~PIPE_BPC_MASK;
-		temp |= pipe_bpc;
-		I915_WRITE(transconf_reg, temp);
-		I915_READ(transconf_reg);
-		udelay(100);
-
-		if (HAS_PCH_CPT(dev)) {
-			/* disable TRANS_DP_CTL */
-			int trans_dp_ctl = (pipe == 0) ? TRANS_DP_CTL_A : TRANS_DP_CTL_B;
-			int reg;
-
-			reg = I915_READ(trans_dp_ctl);
-			reg &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
-			I915_WRITE(trans_dp_ctl, reg);
-			POSTING_READ(trans_dp_ctl);
-
-			/* disable DPLL_SEL */
-			temp = I915_READ(PCH_DPLL_SEL);
-			if (trans_dpll_sel == 0)
-				temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
-			else
-				temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
-			I915_WRITE(PCH_DPLL_SEL, temp);
-			I915_READ(PCH_DPLL_SEL);
-
-		}
-
-		/* disable PCH DPLL */
-		temp = I915_READ(pch_dpll_reg);
-		I915_WRITE(pch_dpll_reg, temp & ~DPLL_VCO_ENABLE);
-		I915_READ(pch_dpll_reg);
-
-		/* Switch from PCDclk to Rawclk */
-		temp = I915_READ(fdi_rx_reg);
-		temp &= ~FDI_SEL_PCDCLK;
-		I915_WRITE(fdi_rx_reg, temp);
-		I915_READ(fdi_rx_reg);
-
-		/* Disable CPU FDI TX PLL */
-		temp = I915_READ(fdi_tx_reg);
-		I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
-		I915_READ(fdi_tx_reg);
-		udelay(100);
-
-		temp = I915_READ(fdi_rx_reg);
-		temp &= ~FDI_RX_PLL_ENABLE;
-		I915_WRITE(fdi_rx_reg, temp);
-		I915_READ(fdi_rx_reg);
-
-		/* Wait for the clocks to turn off. */
-		udelay(100);
+		ironlake_crtc_disable(crtc);
 		break;
 	}
 }
 
 static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
 {
-	struct intel_overlay *overlay;
-	int ret;
-
 	if (!enable && intel_crtc->overlay) {
-		overlay = intel_crtc->overlay;
-		mutex_lock(&overlay->dev->struct_mutex);
-		for (;;) {
-			ret = intel_overlay_switch_off(overlay);
-			if (ret == 0)
-				break;
+		struct drm_device *dev = intel_crtc->base.dev;
 
-			ret = intel_overlay_recover_from_interrupt(overlay, 0);
-			if (ret != 0) {
-				/* overlay doesn't react anymore. Usually
-				 * results in a black screen and an unkillable
-				 * X server. */
-				BUG();
-				overlay->hw_wedged = HW_WEDGED;
-				break;
-			}
-		}
-		mutex_unlock(&overlay->dev->struct_mutex);
+		mutex_lock(&dev->struct_mutex);
+		(void) intel_overlay_switch_off(intel_crtc->overlay, false);
+		mutex_unlock(&dev->struct_mutex);
 	}
-	/* Let userspace switch the overlay on again. In most cases userspace
-	 * has to recompute where to put it anyway. */
 
-	return;
+	/* Let userspace switch the overlay on again. In most cases userspace
+	 * has to recompute where to put it anyway.
+	 */
 }
 
-static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+static void i9xx_crtc_enable(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;
 	int plane = intel_crtc->plane;
-	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-	int dspbase_reg = (plane == 0) ? DSPAADDR : DSPBADDR;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	u32 temp;
+	u32 reg, temp;
 
+	if (intel_crtc->active)
+		return;
+
+	intel_crtc->active = true;
+	intel_update_watermarks(dev);
+
+	/* Enable the DPLL */
+	reg = DPLL(pipe);
+	temp = I915_READ(reg);
+	if ((temp & DPLL_VCO_ENABLE) == 0) {
+		I915_WRITE(reg, temp);
+
+		/* Wait for the clocks to stabilize. */
+		POSTING_READ(reg);
+		udelay(150);
+
+		I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+
+		/* Wait for the clocks to stabilize. */
+		POSTING_READ(reg);
+		udelay(150);
+
+		I915_WRITE(reg, temp | DPLL_VCO_ENABLE);
+
+		/* Wait for the clocks to stabilize. */
+		POSTING_READ(reg);
+		udelay(150);
+	}
+
+	/* Enable the pipe */
+	reg = PIPECONF(pipe);
+	temp = I915_READ(reg);
+	if ((temp & PIPECONF_ENABLE) == 0)
+		I915_WRITE(reg, temp | PIPECONF_ENABLE);
+
+	/* Enable the plane */
+	reg = DSPCNTR(plane);
+	temp = I915_READ(reg);
+	if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+		I915_WRITE(reg, temp | DISPLAY_PLANE_ENABLE);
+		intel_flush_display_plane(dev, plane);
+	}
+
+	intel_crtc_load_lut(crtc);
+	intel_update_fbc(dev);
+
+	/* Give the overlay scaler a chance to enable if it's on this pipe */
+	intel_crtc_dpms_overlay(intel_crtc, true);
+	intel_crtc_update_cursor(crtc, true);
+}
+
+static void i9xx_crtc_disable(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;
+	int plane = intel_crtc->plane;
+	u32 reg, temp;
+
+	if (!intel_crtc->active)
+		return;
+
+	/* Give the overlay scaler a chance to disable if it's on this pipe */
+	intel_crtc_wait_for_pending_flips(crtc);
+	drm_vblank_off(dev, pipe);
+	intel_crtc_dpms_overlay(intel_crtc, false);
+	intel_crtc_update_cursor(crtc, false);
+
+	if (dev_priv->cfb_plane == plane &&
+	    dev_priv->display.disable_fbc)
+		dev_priv->display.disable_fbc(dev);
+
+	/* Disable display plane */
+	reg = DSPCNTR(plane);
+	temp = I915_READ(reg);
+	if (temp & DISPLAY_PLANE_ENABLE) {
+		I915_WRITE(reg, temp & ~DISPLAY_PLANE_ENABLE);
+		/* Flush the plane changes */
+		intel_flush_display_plane(dev, plane);
+
+		/* Wait for vblank for the disable to take effect */
+		if (IS_GEN2(dev))
+			intel_wait_for_vblank(dev, pipe);
+	}
+
+	/* Don't disable pipe A or pipe A PLLs if needed */
+	if (pipe == 0 && (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+		goto done;
+
+	/* Next, disable display pipes */
+	reg = PIPECONF(pipe);
+	temp = I915_READ(reg);
+	if (temp & PIPECONF_ENABLE) {
+		I915_WRITE(reg, temp & ~PIPECONF_ENABLE);
+
+		/* Wait for the pipe to turn off */
+		POSTING_READ(reg);
+		intel_wait_for_pipe_off(dev, pipe);
+	}
+
+	reg = DPLL(pipe);
+	temp = I915_READ(reg);
+	if (temp & DPLL_VCO_ENABLE) {
+		I915_WRITE(reg, temp & ~DPLL_VCO_ENABLE);
+
+		/* Wait for the clocks to turn off. */
+		POSTING_READ(reg);
+		udelay(150);
+	}
+
+done:
+	intel_crtc->active = false;
+	intel_update_fbc(dev);
+	intel_update_watermarks(dev);
+	intel_clear_scanline_wait(dev);
+}
+
+static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
 	/* XXX: When our outputs are all unaware of DPMS modes other than off
 	 * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
 	 */
@@ -2272,88 +2463,10 @@
 	case DRM_MODE_DPMS_ON:
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
-		/* Enable the DPLL */
-		temp = I915_READ(dpll_reg);
-		if ((temp & DPLL_VCO_ENABLE) == 0) {
-			I915_WRITE(dpll_reg, temp);
-			I915_READ(dpll_reg);
-			/* Wait for the clocks to stabilize. */
-			udelay(150);
-			I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-			I915_READ(dpll_reg);
-			/* Wait for the clocks to stabilize. */
-			udelay(150);
-			I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
-			I915_READ(dpll_reg);
-			/* Wait for the clocks to stabilize. */
-			udelay(150);
-		}
-
-		/* Enable the pipe */
-		temp = I915_READ(pipeconf_reg);
-		if ((temp & PIPEACONF_ENABLE) == 0)
-			I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
-
-		/* Enable the plane */
-		temp = I915_READ(dspcntr_reg);
-		if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
-			I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-		}
-
-		intel_crtc_load_lut(crtc);
-
-		if ((IS_I965G(dev) || plane == 0))
-			intel_update_fbc(crtc, &crtc->mode);
-
-		/* Give the overlay scaler a chance to enable if it's on this pipe */
-		intel_crtc_dpms_overlay(intel_crtc, true);
-	break;
+		i9xx_crtc_enable(crtc);
+		break;
 	case DRM_MODE_DPMS_OFF:
-		/* Give the overlay scaler a chance to disable if it's on this pipe */
-		intel_crtc_dpms_overlay(intel_crtc, false);
-		drm_vblank_off(dev, pipe);
-
-		if (dev_priv->cfb_plane == plane &&
-		    dev_priv->display.disable_fbc)
-			dev_priv->display.disable_fbc(dev);
-
-		/* Disable display plane */
-		temp = I915_READ(dspcntr_reg);
-		if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
-			I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
-			/* Flush the plane changes */
-			I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
-			I915_READ(dspbase_reg);
-		}
-
-		/* Wait for vblank for the disable to take effect */
-		intel_wait_for_vblank_off(dev, pipe);
-
-		/* Don't disable pipe A or pipe A PLLs if needed */
-		if (pipeconf_reg == PIPEACONF &&
-		    (dev_priv->quirks & QUIRK_PIPEA_FORCE))
-			goto skip_pipe_off;
-
-		/* Next, disable display pipes */
-		temp = I915_READ(pipeconf_reg);
-		if ((temp & PIPEACONF_ENABLE) != 0) {
-			I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
-			I915_READ(pipeconf_reg);
-		}
-
-		/* Wait for vblank for the disable to take effect. */
-		intel_wait_for_vblank_off(dev, pipe);
-
-		temp = I915_READ(dpll_reg);
-		if ((temp & DPLL_VCO_ENABLE) != 0) {
-			I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
-			I915_READ(dpll_reg);
-		}
-	skip_pipe_off:
-		/* Wait for the clocks to turn off. */
-		udelay(150);
+		i9xx_crtc_disable(crtc);
 		break;
 	}
 }
@@ -2374,26 +2487,9 @@
 		return;
 
 	intel_crtc->dpms_mode = mode;
-	intel_crtc->cursor_on = mode == DRM_MODE_DPMS_ON;
-
-	/* When switching on the display, ensure that SR is disabled
-	 * with multiple pipes prior to enabling to new pipe.
-	 *
-	 * When switching off the display, make sure the cursor is
-	 * properly hidden prior to disabling the pipe.
-	 */
-	if (mode == DRM_MODE_DPMS_ON)
-		intel_update_watermarks(dev);
-	else
-		intel_crtc_update_cursor(crtc);
 
 	dev_priv->display.dpms(crtc, mode);
 
-	if (mode == DRM_MODE_DPMS_ON)
-		intel_crtc_update_cursor(crtc);
-	else
-		intel_update_watermarks(dev);
-
 	if (!dev->primary->master)
 		return;
 
@@ -2418,16 +2514,46 @@
 	}
 }
 
-static void intel_crtc_prepare (struct drm_crtc *crtc)
+static void intel_crtc_disable(struct drm_crtc *crtc)
 {
 	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+	struct drm_device *dev = crtc->dev;
+
 	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+
+	if (crtc->fb) {
+		mutex_lock(&dev->struct_mutex);
+		i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj);
+		mutex_unlock(&dev->struct_mutex);
+	}
 }
 
-static void intel_crtc_commit (struct drm_crtc *crtc)
+/* Prepare for a mode set.
+ *
+ * Note we could be a lot smarter here.  We need to figure out which outputs
+ * will be enabled, which disabled (in short, how the config will changes)
+ * and perform the minimum necessary steps to accomplish that, e.g. updating
+ * watermarks, FBC configuration, making sure PLLs are programmed correctly,
+ * panel fitting is in the proper state, etc.
+ */
+static void i9xx_crtc_prepare(struct drm_crtc *crtc)
 {
-	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
-	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+	i9xx_crtc_disable(crtc);
+}
+
+static void i9xx_crtc_commit(struct drm_crtc *crtc)
+{
+	i9xx_crtc_enable(crtc);
+}
+
+static void ironlake_crtc_prepare(struct drm_crtc *crtc)
+{
+	ironlake_crtc_disable(crtc);
+}
+
+static void ironlake_crtc_commit(struct drm_crtc *crtc)
+{
+	ironlake_crtc_enable(crtc);
 }
 
 void intel_encoder_prepare (struct drm_encoder *encoder)
@@ -2446,13 +2572,7 @@
 
 void intel_encoder_destroy(struct drm_encoder *encoder)
 {
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-	if (intel_encoder->ddc_bus)
-		intel_i2c_destroy(intel_encoder->ddc_bus);
-
-	if (intel_encoder->i2c_bus)
-		intel_i2c_destroy(intel_encoder->i2c_bus);
+	struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
 
 	drm_encoder_cleanup(encoder);
 	kfree(intel_encoder);
@@ -2543,33 +2663,6 @@
 	return 133000;
 }
 
-/**
- * Return the pipe currently connected to the panel fitter,
- * or -1 if the panel fitter is not present or not in use
- */
-int intel_panel_fitter_pipe (struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32  pfit_control;
-
-	/* i830 doesn't have a panel fitter */
-	if (IS_I830(dev))
-		return -1;
-
-	pfit_control = I915_READ(PFIT_CONTROL);
-
-	/* See if the panel fitter is in use */
-	if ((pfit_control & PFIT_ENABLE) == 0)
-		return -1;
-
-	/* 965 can place panel fitter on either pipe */
-	if (IS_I965G(dev))
-		return (pfit_control >> 29) & 0x3;
-
-	/* older chips can only use pipe 1 */
-	return 1;
-}
-
 struct fdi_m_n {
 	u32        tu;
 	u32        gmch_m;
@@ -2888,7 +2981,7 @@
 		size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
 
 	DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-			plane ? "B" : "A", size);
+		      plane ? "B" : "A", size);
 
 	return size;
 }
@@ -2905,7 +2998,7 @@
 	size >>= 1; /* Convert to cachelines */
 
 	DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-			plane ? "B" : "A", size);
+		      plane ? "B" : "A", size);
 
 	return size;
 }
@@ -2920,8 +3013,8 @@
 	size >>= 2; /* Convert to cachelines */
 
 	DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-			plane ? "B" : "A",
-		  size);
+		      plane ? "B" : "A",
+		      size);
 
 	return size;
 }
@@ -2936,14 +3029,14 @@
 	size >>= 1; /* Convert to cachelines */
 
 	DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-			plane ? "B" : "A", size);
+		      plane ? "B" : "A", size);
 
 	return size;
 }
 
 static void pineview_update_wm(struct drm_device *dev,  int planea_clock,
-			  int planeb_clock, int sr_hdisplay, int unused,
-			  int pixel_size)
+			       int planeb_clock, int sr_hdisplay, int unused,
+			       int pixel_size)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	const struct cxsr_latency *latency;
@@ -3055,13 +3148,13 @@
 
 		/* Use ns/us then divide to preserve precision */
 		sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-			      pixel_size * sr_hdisplay;
+			pixel_size * sr_hdisplay;
 		sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 
 		entries_required = (((sr_latency_ns / line_time_us) +
 				     1000) / 1000) * pixel_size * 64;
 		entries_required = DIV_ROUND_UP(entries_required,
-					   g4x_cursor_wm_info.cacheline_size);
+						g4x_cursor_wm_info.cacheline_size);
 		cursor_sr = entries_required + g4x_cursor_wm_info.guard_size;
 
 		if (cursor_sr > g4x_cursor_wm_info.max_wm)
@@ -3073,7 +3166,7 @@
 	} else {
 		/* Turn off self refresh if both pipes are enabled */
 		I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
-					& ~FW_BLC_SELF_EN);
+			   & ~FW_BLC_SELF_EN);
 	}
 
 	DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
@@ -3111,7 +3204,7 @@
 
 		/* Use ns/us then divide to preserve precision */
 		sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-			      pixel_size * sr_hdisplay;
+			pixel_size * sr_hdisplay;
 		sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE);
 		DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
 		srwm = I965_FIFO_SIZE - sr_entries;
@@ -3120,11 +3213,11 @@
 		srwm &= 0x1ff;
 
 		sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-			     pixel_size * 64;
+			pixel_size * 64;
 		sr_entries = DIV_ROUND_UP(sr_entries,
 					  i965_cursor_wm_info.cacheline_size);
 		cursor_sr = i965_cursor_wm_info.fifo_size -
-			    (sr_entries + i965_cursor_wm_info.guard_size);
+			(sr_entries + i965_cursor_wm_info.guard_size);
 
 		if (cursor_sr > i965_cursor_wm_info.max_wm)
 			cursor_sr = i965_cursor_wm_info.max_wm;
@@ -3132,11 +3225,11 @@
 		DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
 			      "cursor %d\n", srwm, cursor_sr);
 
-		if (IS_I965GM(dev))
+		if (IS_CRESTLINE(dev))
 			I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
 	} else {
 		/* Turn off self refresh if both pipes are enabled */
-		if (IS_I965GM(dev))
+		if (IS_CRESTLINE(dev))
 			I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
 				   & ~FW_BLC_SELF_EN);
 	}
@@ -3166,9 +3259,9 @@
 	int sr_clock, sr_entries = 0;
 
 	/* Create copies of the base settings for each pipe */
-	if (IS_I965GM(dev) || IS_I945GM(dev))
+	if (IS_CRESTLINE(dev) || IS_I945GM(dev))
 		planea_params = planeb_params = i945_wm_info;
-	else if (IS_I9XX(dev))
+	else if (!IS_GEN2(dev))
 		planea_params = planeb_params = i915_wm_info;
 	else
 		planea_params = planeb_params = i855_wm_info;
@@ -3203,7 +3296,7 @@
 
 		/* Use ns/us then divide to preserve precision */
 		sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-			      pixel_size * sr_hdisplay;
+			pixel_size * sr_hdisplay;
 		sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size);
 		DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
 		srwm = total_size - sr_entries;
@@ -3228,7 +3321,7 @@
 	}
 
 	DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
-		  planea_wm, planeb_wm, cwm, srwm);
+		      planea_wm, planeb_wm, cwm, srwm);
 
 	fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
 	fwater_hi = (cwm & 0x1f);
@@ -3262,146 +3355,130 @@
 #define ILK_LP0_PLANE_LATENCY		700
 #define ILK_LP0_CURSOR_LATENCY		1300
 
-static void ironlake_update_wm(struct drm_device *dev,  int planea_clock,
-		       int planeb_clock, int sr_hdisplay, int sr_htotal,
-		       int pixel_size)
+static bool ironlake_compute_wm0(struct drm_device *dev,
+				 int pipe,
+				 int *plane_wm,
+				 int *cursor_wm)
+{
+	struct drm_crtc *crtc;
+	int htotal, hdisplay, clock, pixel_size = 0;
+	int line_time_us, line_count, entries;
+
+	crtc = intel_get_crtc_for_pipe(dev, pipe);
+	if (crtc->fb == NULL || !crtc->enabled)
+		return false;
+
+	htotal = crtc->mode.htotal;
+	hdisplay = crtc->mode.hdisplay;
+	clock = crtc->mode.clock;
+	pixel_size = crtc->fb->bits_per_pixel / 8;
+
+	/* Use the small buffer method to calculate plane watermark */
+	entries = ((clock * pixel_size / 1000) * ILK_LP0_PLANE_LATENCY) / 1000;
+	entries = DIV_ROUND_UP(entries,
+			       ironlake_display_wm_info.cacheline_size);
+	*plane_wm = entries + ironlake_display_wm_info.guard_size;
+	if (*plane_wm > (int)ironlake_display_wm_info.max_wm)
+		*plane_wm = ironlake_display_wm_info.max_wm;
+
+	/* Use the large buffer method to calculate cursor watermark */
+	line_time_us = ((htotal * 1000) / clock);
+	line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
+	entries = line_count * 64 * pixel_size;
+	entries = DIV_ROUND_UP(entries,
+			       ironlake_cursor_wm_info.cacheline_size);
+	*cursor_wm = entries + ironlake_cursor_wm_info.guard_size;
+	if (*cursor_wm > ironlake_cursor_wm_info.max_wm)
+		*cursor_wm = ironlake_cursor_wm_info.max_wm;
+
+	return true;
+}
+
+static void ironlake_update_wm(struct drm_device *dev,
+			       int planea_clock, int planeb_clock,
+			       int sr_hdisplay, int sr_htotal,
+			       int pixel_size)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
-	int sr_wm, cursor_wm;
-	unsigned long line_time_us;
-	int sr_clock, entries_required;
-	u32 reg_value;
-	int line_count;
-	int planea_htotal = 0, planeb_htotal = 0;
-	struct drm_crtc *crtc;
+	int plane_wm, cursor_wm, enabled;
+	int tmp;
 
-	/* Need htotal for all active display plane */
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
-			if (intel_crtc->plane == 0)
-				planea_htotal = crtc->mode.htotal;
-			else
-				planeb_htotal = crtc->mode.htotal;
-		}
+	enabled = 0;
+	if (ironlake_compute_wm0(dev, 0, &plane_wm, &cursor_wm)) {
+		I915_WRITE(WM0_PIPEA_ILK,
+			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+		DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+			      " plane %d, " "cursor: %d\n",
+			      plane_wm, cursor_wm);
+		enabled++;
 	}
 
-	/* Calculate and update the watermark for plane A */
-	if (planea_clock) {
-		entries_required = ((planea_clock / 1000) * pixel_size *
-				     ILK_LP0_PLANE_LATENCY) / 1000;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_display_wm_info.cacheline_size);
-		planea_wm = entries_required +
-			    ironlake_display_wm_info.guard_size;
-
-		if (planea_wm > (int)ironlake_display_wm_info.max_wm)
-			planea_wm = ironlake_display_wm_info.max_wm;
-
-		/* Use the large buffer method to calculate cursor watermark */
-		line_time_us = (planea_htotal * 1000) / planea_clock;
-
-		/* Use ns/us then divide to preserve precision */
-		line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
-
-		/* calculate the cursor watermark for cursor A */
-		entries_required = line_count * 64 * pixel_size;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_cursor_wm_info.cacheline_size);
-		cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-		if (cursora_wm > ironlake_cursor_wm_info.max_wm)
-			cursora_wm = ironlake_cursor_wm_info.max_wm;
-
-		reg_value = I915_READ(WM0_PIPEA_ILK);
-		reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-		reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) |
-			     (cursora_wm & WM0_PIPE_CURSOR_MASK);
-		I915_WRITE(WM0_PIPEA_ILK, reg_value);
-		DRM_DEBUG_KMS("FIFO watermarks For pipe A - plane %d, "
-				"cursor: %d\n", planea_wm, cursora_wm);
-	}
-	/* Calculate and update the watermark for plane B */
-	if (planeb_clock) {
-		entries_required = ((planeb_clock / 1000) * pixel_size *
-				     ILK_LP0_PLANE_LATENCY) / 1000;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_display_wm_info.cacheline_size);
-		planeb_wm = entries_required +
-			    ironlake_display_wm_info.guard_size;
-
-		if (planeb_wm > (int)ironlake_display_wm_info.max_wm)
-			planeb_wm = ironlake_display_wm_info.max_wm;
-
-		/* Use the large buffer method to calculate cursor watermark */
-		line_time_us = (planeb_htotal * 1000) / planeb_clock;
-
-		/* Use ns/us then divide to preserve precision */
-		line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000;
-
-		/* calculate the cursor watermark for cursor B */
-		entries_required = line_count * 64 * pixel_size;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_cursor_wm_info.cacheline_size);
-		cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size;
-		if (cursorb_wm > ironlake_cursor_wm_info.max_wm)
-			cursorb_wm = ironlake_cursor_wm_info.max_wm;
-
-		reg_value = I915_READ(WM0_PIPEB_ILK);
-		reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-		reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) |
-			     (cursorb_wm & WM0_PIPE_CURSOR_MASK);
-		I915_WRITE(WM0_PIPEB_ILK, reg_value);
-		DRM_DEBUG_KMS("FIFO watermarks For pipe B - plane %d, "
-				"cursor: %d\n", planeb_wm, cursorb_wm);
+	if (ironlake_compute_wm0(dev, 1, &plane_wm, &cursor_wm)) {
+		I915_WRITE(WM0_PIPEB_ILK,
+			   (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+		DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+			      " plane %d, cursor: %d\n",
+			      plane_wm, cursor_wm);
+		enabled++;
 	}
 
 	/*
 	 * Calculate and update the self-refresh watermark only when one
 	 * display plane is used.
 	 */
-	if (!planea_clock || !planeb_clock) {
-
+	tmp = 0;
+	if (enabled == 1 && /* XXX disabled due to buggy implmentation? */ 0) {
+		unsigned long line_time_us;
+		int small, large, plane_fbc;
+		int sr_clock, entries;
+		int line_count, line_size;
 		/* Read the self-refresh latency. The unit is 0.5us */
 		int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK;
 
 		sr_clock = planea_clock ? planea_clock : planeb_clock;
-		line_time_us = ((sr_htotal * 1000) / sr_clock);
+		line_time_us = (sr_htotal * 1000) / sr_clock;
 
 		/* Use ns/us then divide to preserve precision */
 		line_count = ((ilk_sr_latency * 500) / line_time_us + 1000)
-			       / 1000;
+			/ 1000;
+		line_size = sr_hdisplay * pixel_size;
 
-		/* calculate the self-refresh watermark for display plane */
-		entries_required = line_count * sr_hdisplay * pixel_size;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_display_srwm_info.cacheline_size);
-		sr_wm = entries_required +
-			ironlake_display_srwm_info.guard_size;
+		/* Use the minimum of the small and large buffer method for primary */
+		small = ((sr_clock * pixel_size / 1000) * (ilk_sr_latency * 500)) / 1000;
+		large = line_count * line_size;
+
+		entries = DIV_ROUND_UP(min(small, large),
+				       ironlake_display_srwm_info.cacheline_size);
+
+		plane_fbc = entries * 64;
+		plane_fbc = DIV_ROUND_UP(plane_fbc, line_size);
+
+		plane_wm = entries + ironlake_display_srwm_info.guard_size;
+		if (plane_wm > (int)ironlake_display_srwm_info.max_wm)
+			plane_wm = ironlake_display_srwm_info.max_wm;
 
 		/* calculate the self-refresh watermark for display cursor */
-		entries_required = line_count * pixel_size * 64;
-		entries_required = DIV_ROUND_UP(entries_required,
-						ironlake_cursor_srwm_info.cacheline_size);
-		cursor_wm = entries_required +
-			    ironlake_cursor_srwm_info.guard_size;
+		entries = line_count * pixel_size * 64;
+		entries = DIV_ROUND_UP(entries,
+				       ironlake_cursor_srwm_info.cacheline_size);
+
+		cursor_wm = entries + ironlake_cursor_srwm_info.guard_size;
+		if (cursor_wm > (int)ironlake_cursor_srwm_info.max_wm)
+			cursor_wm = ironlake_cursor_srwm_info.max_wm;
 
 		/* configure watermark and enable self-refresh */
-		reg_value = I915_READ(WM1_LP_ILK);
-		reg_value &= ~(WM1_LP_LATENCY_MASK | WM1_LP_SR_MASK |
-			       WM1_LP_CURSOR_MASK);
-		reg_value |= (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
-			     (sr_wm << WM1_LP_SR_SHIFT) | cursor_wm;
-
-		I915_WRITE(WM1_LP_ILK, reg_value);
-		DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
-				"cursor %d\n", sr_wm, cursor_wm);
-
-	} else {
-		/* Turn off self refresh if both pipes are enabled */
-		I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
+		tmp = (WM1_LP_SR_EN |
+		       (ilk_sr_latency << WM1_LP_LATENCY_SHIFT) |
+		       (plane_fbc << WM1_LP_FBC_SHIFT) |
+		       (plane_wm << WM1_LP_SR_SHIFT) |
+		       cursor_wm);
+		DRM_DEBUG_KMS("self-refresh watermark: display plane %d, fbc lines %d,"
+			      " cursor %d\n", plane_wm, plane_fbc, cursor_wm);
 	}
+	I915_WRITE(WM1_LP_ILK, tmp);
+	/* XXX setup WM2 and WM3 */
 }
+
 /**
  * intel_update_watermarks - update FIFO watermark values based on current modes
  *
@@ -3433,7 +3510,7 @@
  *
  * We don't use the sprite, so we can ignore that.  And on Crestline we have
  * to set the non-SR watermarks to 8.
-  */
+ */
 static void intel_update_watermarks(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3449,15 +3526,15 @@
 	/* Get the clock config from both planes */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		if (intel_crtc->dpms_mode == DRM_MODE_DPMS_ON) {
+		if (intel_crtc->active) {
 			enabled++;
 			if (intel_crtc->plane == 0) {
 				DRM_DEBUG_KMS("plane A (pipe %d) clock: %d\n",
-					  intel_crtc->pipe, crtc->mode.clock);
+					      intel_crtc->pipe, crtc->mode.clock);
 				planea_clock = crtc->mode.clock;
 			} else {
 				DRM_DEBUG_KMS("plane B (pipe %d) clock: %d\n",
-					  intel_crtc->pipe, crtc->mode.clock);
+					      intel_crtc->pipe, crtc->mode.clock);
 				planeb_clock = crtc->mode.clock;
 			}
 			sr_hdisplay = crtc->mode.hdisplay;
@@ -3488,62 +3565,35 @@
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
 	int plane = intel_crtc->plane;
-	int fp_reg = (pipe == 0) ? FPA0 : FPB0;
-	int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
-	int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
-	int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
-	int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
-	int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
-	int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
-	int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
-	int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
-	int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
-	int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
-	int dspsize_reg = (plane == 0) ? DSPASIZE : DSPBSIZE;
-	int dsppos_reg = (plane == 0) ? DSPAPOS : DSPBPOS;
-	int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+	u32 fp_reg, dpll_reg;
 	int refclk, num_connectors = 0;
 	intel_clock_t clock, reduced_clock;
-	u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
+	u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
 	bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
 	bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
 	struct intel_encoder *has_edp_encoder = NULL;
 	struct drm_mode_config *mode_config = &dev->mode_config;
-	struct drm_encoder *encoder;
+	struct intel_encoder *encoder;
 	const intel_limit_t *limit;
 	int ret;
 	struct fdi_m_n m_n = {0};
-	int data_m1_reg = (pipe == 0) ? PIPEA_DATA_M1 : PIPEB_DATA_M1;
-	int data_n1_reg = (pipe == 0) ? PIPEA_DATA_N1 : PIPEB_DATA_N1;
-	int link_m1_reg = (pipe == 0) ? PIPEA_LINK_M1 : PIPEB_LINK_M1;
-	int link_n1_reg = (pipe == 0) ? PIPEA_LINK_N1 : PIPEB_LINK_N1;
-	int pch_fp_reg = (pipe == 0) ? PCH_FPA0 : PCH_FPB0;
-	int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
-	int fdi_rx_reg = (pipe == 0) ? FDI_RXA_CTL : FDI_RXB_CTL;
-	int fdi_tx_reg = (pipe == 0) ? FDI_TXA_CTL : FDI_TXB_CTL;
-	int trans_dpll_sel = (pipe == 0) ? 0 : 1;
-	int lvds_reg = LVDS;
-	u32 temp;
-	int sdvo_pixel_multiply;
+	u32 reg, temp;
 	int target_clock;
 
 	drm_vblank_pre_modeset(dev, pipe);
 
-	list_for_each_entry(encoder, &mode_config->encoder_list, head) {
-		struct intel_encoder *intel_encoder;
-
-		if (encoder->crtc != crtc)
+	list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+		if (encoder->base.crtc != crtc)
 			continue;
 
-		intel_encoder = enc_to_intel_encoder(encoder);
-		switch (intel_encoder->type) {
+		switch (encoder->type) {
 		case INTEL_OUTPUT_LVDS:
 			is_lvds = true;
 			break;
 		case INTEL_OUTPUT_SDVO:
 		case INTEL_OUTPUT_HDMI:
 			is_sdvo = true;
-			if (intel_encoder->needs_tv_clock)
+			if (encoder->needs_tv_clock)
 				is_tv = true;
 			break;
 		case INTEL_OUTPUT_DVO:
@@ -3559,7 +3609,7 @@
 			is_dp = true;
 			break;
 		case INTEL_OUTPUT_EDP:
-			has_edp_encoder = intel_encoder;
+			has_edp_encoder = encoder;
 			break;
 		}
 
@@ -3569,15 +3619,14 @@
 	if (is_lvds && dev_priv->lvds_use_ssc && num_connectors < 2) {
 		refclk = dev_priv->lvds_ssc_freq * 1000;
 		DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-					refclk / 1000);
-	} else if (IS_I9XX(dev)) {
+			      refclk / 1000);
+	} else if (!IS_GEN2(dev)) {
 		refclk = 96000;
 		if (HAS_PCH_SPLIT(dev))
 			refclk = 120000; /* 120Mhz refclk */
 	} else {
 		refclk = 48000;
 	}
-	
 
 	/*
 	 * Returns a set of divisors for the desired target clock with the given
@@ -3593,13 +3642,13 @@
 	}
 
 	/* Ensure that the cursor is valid for the new mode before changing... */
-	intel_crtc_update_cursor(crtc);
+	intel_crtc_update_cursor(crtc, true);
 
 	if (is_lvds && dev_priv->lvds_downclock_avail) {
 		has_reduced_clock = limit->find_pll(limit, crtc,
-							    dev_priv->lvds_downclock,
-							    refclk,
-							    &reduced_clock);
+						    dev_priv->lvds_downclock,
+						    refclk,
+						    &reduced_clock);
 		if (has_reduced_clock && (clock.p != reduced_clock.p)) {
 			/*
 			 * If the different P is found, it means that we can't
@@ -3608,7 +3657,7 @@
 			 * feature.
 			 */
 			DRM_DEBUG_KMS("Different P is found for "
-						"LVDS clock/downclock\n");
+				      "LVDS clock/downclock\n");
 			has_reduced_clock = 0;
 		}
 	}
@@ -3616,14 +3665,14 @@
 	   this mirrors vbios setting. */
 	if (is_sdvo && is_tv) {
 		if (adjusted_mode->clock >= 100000
-				&& adjusted_mode->clock < 140500) {
+		    && adjusted_mode->clock < 140500) {
 			clock.p1 = 2;
 			clock.p2 = 10;
 			clock.n = 3;
 			clock.m1 = 16;
 			clock.m2 = 8;
 		} else if (adjusted_mode->clock >= 140500
-				&& adjusted_mode->clock <= 200000) {
+			   && adjusted_mode->clock <= 200000) {
 			clock.p1 = 1;
 			clock.p2 = 10;
 			clock.n = 6;
@@ -3648,21 +3697,28 @@
 				target_clock = mode->clock;
 			else
 				target_clock = adjusted_mode->clock;
-			link_bw = 270000;
+
+			/* FDI is a binary signal running at ~2.7GHz, encoding
+			 * each output octet as 10 bits. The actual frequency
+			 * is stored as a divider into a 100MHz clock, and the
+			 * mode pixel clock is stored in units of 1KHz.
+			 * Hence the bw of each lane in terms of the mode signal
+			 * is:
+			 */
+			link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
 		}
 
 		/* determine panel color depth */
-		temp = I915_READ(pipeconf_reg);
+		temp = I915_READ(PIPECONF(pipe));
 		temp &= ~PIPE_BPC_MASK;
 		if (is_lvds) {
-			int lvds_reg = I915_READ(PCH_LVDS);
 			/* the BPC will be 6 if it is 18-bit LVDS panel */
-			if ((lvds_reg & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+			if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
 				temp |= PIPE_8BPC;
 			else
 				temp |= PIPE_6BPC;
 		} else if (has_edp_encoder || (is_dp && intel_pch_has_edp(crtc))) {
-			switch (dev_priv->edp_bpp/3) {
+			switch (dev_priv->edp.bpp/3) {
 			case 8:
 				temp |= PIPE_8BPC;
 				break;
@@ -3678,8 +3734,7 @@
 			}
 		} else
 			temp |= PIPE_8BPC;
-		I915_WRITE(pipeconf_reg, temp);
-		I915_READ(pipeconf_reg);
+		I915_WRITE(PIPECONF(pipe), temp);
 
 		switch (temp & PIPE_BPC_MASK) {
 		case PIPE_8BPC:
@@ -3724,33 +3779,27 @@
 		/* Always enable nonspread source */
 		temp &= ~DREF_NONSPREAD_SOURCE_MASK;
 		temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-		I915_WRITE(PCH_DREF_CONTROL, temp);
-		POSTING_READ(PCH_DREF_CONTROL);
-
 		temp &= ~DREF_SSC_SOURCE_MASK;
 		temp |= DREF_SSC_SOURCE_ENABLE;
 		I915_WRITE(PCH_DREF_CONTROL, temp);
-		POSTING_READ(PCH_DREF_CONTROL);
 
+		POSTING_READ(PCH_DREF_CONTROL);
 		udelay(200);
 
 		if (has_edp_encoder) {
 			if (dev_priv->lvds_use_ssc) {
 				temp |= DREF_SSC1_ENABLE;
 				I915_WRITE(PCH_DREF_CONTROL, temp);
-				POSTING_READ(PCH_DREF_CONTROL);
 
+				POSTING_READ(PCH_DREF_CONTROL);
 				udelay(200);
 
 				temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 				temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
-				I915_WRITE(PCH_DREF_CONTROL, temp);
-				POSTING_READ(PCH_DREF_CONTROL);
 			} else {
 				temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-				I915_WRITE(PCH_DREF_CONTROL, temp);
-				POSTING_READ(PCH_DREF_CONTROL);
 			}
+			I915_WRITE(PCH_DREF_CONTROL, temp);
 		}
 	}
 
@@ -3766,21 +3815,24 @@
 				reduced_clock.m2;
 	}
 
+	dpll = 0;
 	if (!HAS_PCH_SPLIT(dev))
 		dpll = DPLL_VGA_MODE_DIS;
 
-	if (IS_I9XX(dev)) {
+	if (!IS_GEN2(dev)) {
 		if (is_lvds)
 			dpll |= DPLLB_MODE_LVDS;
 		else
 			dpll |= DPLLB_MODE_DAC_SERIAL;
 		if (is_sdvo) {
+			int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+			if (pixel_multiplier > 1) {
+				if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+					dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+				else if (HAS_PCH_SPLIT(dev))
+					dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+			}
 			dpll |= DPLL_DVO_HIGH_SPEED;
-			sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-			if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
-				dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
-			else if (HAS_PCH_SPLIT(dev))
-				dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
 		}
 		if (is_dp)
 			dpll |= DPLL_DVO_HIGH_SPEED;
@@ -3810,7 +3862,7 @@
 			dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
 			break;
 		}
-		if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev))
+		if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
 			dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
 	} else {
 		if (is_lvds) {
@@ -3837,7 +3889,7 @@
 		dpll |= PLL_REF_INPUT_DREFCLK;
 
 	/* setup pipeconf */
-	pipeconf = I915_READ(pipeconf_reg);
+	pipeconf = I915_READ(PIPECONF(pipe));
 
 	/* Set up the display plane register */
 	dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -3851,7 +3903,7 @@
 			dspcntr |= DISPPLANE_SEL_PIPE_B;
 	}
 
-	if (pipe == 0 && !IS_I965G(dev)) {
+	if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
 		/* Enable pixel doubling when the dot clock is > 90% of the (display)
 		 * core speed.
 		 *
@@ -3860,51 +3912,46 @@
 		 */
 		if (mode->clock >
 		    dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
-			pipeconf |= PIPEACONF_DOUBLE_WIDE;
+			pipeconf |= PIPECONF_DOUBLE_WIDE;
 		else
-			pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
+			pipeconf &= ~PIPECONF_DOUBLE_WIDE;
 	}
 
 	dspcntr |= DISPLAY_PLANE_ENABLE;
-	pipeconf |= PIPEACONF_ENABLE;
+	pipeconf |= PIPECONF_ENABLE;
 	dpll |= DPLL_VCO_ENABLE;
 
-
-	/* Disable the panel fitter if it was on our pipe */
-	if (!HAS_PCH_SPLIT(dev) && intel_panel_fitter_pipe(dev) == pipe)
-		I915_WRITE(PFIT_CONTROL, 0);
-
 	DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
 	drm_mode_debug_printmodeline(mode);
 
 	/* assign to Ironlake registers */
 	if (HAS_PCH_SPLIT(dev)) {
-		fp_reg = pch_fp_reg;
-		dpll_reg = pch_dpll_reg;
+		fp_reg = PCH_FP0(pipe);
+		dpll_reg = PCH_DPLL(pipe);
+	} else {
+		fp_reg = FP0(pipe);
+		dpll_reg = DPLL(pipe);
 	}
 
 	if (!has_edp_encoder) {
 		I915_WRITE(fp_reg, fp);
 		I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
-		I915_READ(dpll_reg);
+
+		POSTING_READ(dpll_reg);
 		udelay(150);
 	}
 
 	/* enable transcoder DPLL */
 	if (HAS_PCH_CPT(dev)) {
 		temp = I915_READ(PCH_DPLL_SEL);
-		if (trans_dpll_sel == 0)
-			temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+		if (pipe == 0)
+			temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
 		else
-			temp |=	(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+			temp |=	TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
 		I915_WRITE(PCH_DPLL_SEL, temp);
-		I915_READ(PCH_DPLL_SEL);
-		udelay(150);
-	}
 
-	if (HAS_PCH_SPLIT(dev)) {
-		pipeconf &= ~PIPE_ENABLE_DITHER;
-		pipeconf &= ~PIPE_DITHER_TYPE_MASK;
+		POSTING_READ(PCH_DPLL_SEL);
+		udelay(150);
 	}
 
 	/* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -3912,55 +3959,57 @@
 	 * things on.
 	 */
 	if (is_lvds) {
-		u32 lvds;
-
+		reg = LVDS;
 		if (HAS_PCH_SPLIT(dev))
-			lvds_reg = PCH_LVDS;
+			reg = PCH_LVDS;
 
-		lvds = I915_READ(lvds_reg);
-		lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+		temp = I915_READ(reg);
+		temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
 		if (pipe == 1) {
 			if (HAS_PCH_CPT(dev))
-				lvds |= PORT_TRANS_B_SEL_CPT;
+				temp |= PORT_TRANS_B_SEL_CPT;
 			else
-				lvds |= LVDS_PIPEB_SELECT;
+				temp |= LVDS_PIPEB_SELECT;
 		} else {
 			if (HAS_PCH_CPT(dev))
-				lvds &= ~PORT_TRANS_SEL_MASK;
+				temp &= ~PORT_TRANS_SEL_MASK;
 			else
-				lvds &= ~LVDS_PIPEB_SELECT;
+				temp &= ~LVDS_PIPEB_SELECT;
 		}
 		/* set the corresponsding LVDS_BORDER bit */
-		lvds |= dev_priv->lvds_border_bits;
+		temp |= dev_priv->lvds_border_bits;
 		/* Set the B0-B3 data pairs corresponding to whether we're going to
 		 * set the DPLLs for dual-channel mode or not.
 		 */
 		if (clock.p2 == 7)
-			lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+			temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
 		else
-			lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+			temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
 
 		/* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
 		 * appropriately here, but we need to look more thoroughly into how
 		 * panels behave in the two modes.
 		 */
-		/* set the dithering flag */
-		if (IS_I965G(dev)) {
-			if (dev_priv->lvds_dither) {
-				if (HAS_PCH_SPLIT(dev)) {
-					pipeconf |= PIPE_ENABLE_DITHER;
-					pipeconf |= PIPE_DITHER_TYPE_ST01;
-				} else
-					lvds |= LVDS_ENABLE_DITHER;
-			} else {
-				if (!HAS_PCH_SPLIT(dev)) {
-					lvds &= ~LVDS_ENABLE_DITHER;
-				}
-			}
+		/* set the dithering flag on non-PCH LVDS as needed */
+		if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+			if (dev_priv->lvds_dither)
+				temp |= LVDS_ENABLE_DITHER;
+			else
+				temp &= ~LVDS_ENABLE_DITHER;
 		}
-		I915_WRITE(lvds_reg, lvds);
-		I915_READ(lvds_reg);
+		I915_WRITE(reg, temp);
 	}
+
+	/* set the dithering flag and clear for anything other than a panel. */
+	if (HAS_PCH_SPLIT(dev)) {
+		pipeconf &= ~PIPECONF_DITHER_EN;
+		pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+		if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+			pipeconf |= PIPECONF_DITHER_EN;
+			pipeconf |= PIPECONF_DITHER_TYPE_ST1;
+		}
+	}
+
 	if (is_dp)
 		intel_dp_set_m_n(crtc, mode, adjusted_mode);
 	else if (HAS_PCH_SPLIT(dev)) {
@@ -3981,26 +4030,32 @@
 	if (!has_edp_encoder) {
 		I915_WRITE(fp_reg, fp);
 		I915_WRITE(dpll_reg, dpll);
-		I915_READ(dpll_reg);
+
 		/* Wait for the clocks to stabilize. */
+		POSTING_READ(dpll_reg);
 		udelay(150);
 
-		if (IS_I965G(dev) && !HAS_PCH_SPLIT(dev)) {
+		if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
+			temp = 0;
 			if (is_sdvo) {
-				sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-				I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
-					((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
-			} else
-				I915_WRITE(dpll_md_reg, 0);
+				temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+				if (temp > 1)
+					temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+				else
+					temp = 0;
+			}
+			I915_WRITE(DPLL_MD(pipe), temp);
 		} else {
 			/* write it again -- the BIOS does, after all */
 			I915_WRITE(dpll_reg, dpll);
 		}
-		I915_READ(dpll_reg);
+
 		/* Wait for the clocks to stabilize. */
+		POSTING_READ(dpll_reg);
 		udelay(150);
 	}
 
+	intel_crtc->lowfreq_avail = false;
 	if (is_lvds && has_reduced_clock && i915_powersave) {
 		I915_WRITE(fp_reg + 4, fp2);
 		intel_crtc->lowfreq_avail = true;
@@ -4010,7 +4065,6 @@
 		}
 	} else {
 		I915_WRITE(fp_reg + 4, fp);
-		intel_crtc->lowfreq_avail = false;
 		if (HAS_PIPE_CXSR(dev)) {
 			DRM_DEBUG_KMS("disabling CxSR downclocking\n");
 			pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -4029,58 +4083,72 @@
 	} else
 		pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
 
-	I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+	I915_WRITE(HTOTAL(pipe),
+		   (adjusted_mode->crtc_hdisplay - 1) |
 		   ((adjusted_mode->crtc_htotal - 1) << 16));
-	I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+	I915_WRITE(HBLANK(pipe),
+		   (adjusted_mode->crtc_hblank_start - 1) |
 		   ((adjusted_mode->crtc_hblank_end - 1) << 16));
-	I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+	I915_WRITE(HSYNC(pipe),
+		   (adjusted_mode->crtc_hsync_start - 1) |
 		   ((adjusted_mode->crtc_hsync_end - 1) << 16));
-	I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+
+	I915_WRITE(VTOTAL(pipe),
+		   (adjusted_mode->crtc_vdisplay - 1) |
 		   ((adjusted_mode->crtc_vtotal - 1) << 16));
-	I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+	I915_WRITE(VBLANK(pipe),
+		   (adjusted_mode->crtc_vblank_start - 1) |
 		   ((adjusted_mode->crtc_vblank_end - 1) << 16));
-	I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+	I915_WRITE(VSYNC(pipe),
+		   (adjusted_mode->crtc_vsync_start - 1) |
 		   ((adjusted_mode->crtc_vsync_end - 1) << 16));
-	/* pipesrc and dspsize control the size that is scaled from, which should
-	 * always be the user's requested size.
+
+	/* pipesrc and dspsize control the size that is scaled from,
+	 * which should always be the user's requested size.
 	 */
 	if (!HAS_PCH_SPLIT(dev)) {
-		I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) |
-				(mode->hdisplay - 1));
-		I915_WRITE(dsppos_reg, 0);
+		I915_WRITE(DSPSIZE(plane),
+			   ((mode->vdisplay - 1) << 16) |
+			   (mode->hdisplay - 1));
+		I915_WRITE(DSPPOS(plane), 0);
 	}
-	I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+	I915_WRITE(PIPESRC(pipe),
+		   ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
 
 	if (HAS_PCH_SPLIT(dev)) {
-		I915_WRITE(data_m1_reg, TU_SIZE(m_n.tu) | m_n.gmch_m);
-		I915_WRITE(data_n1_reg, TU_SIZE(m_n.tu) | m_n.gmch_n);
-		I915_WRITE(link_m1_reg, m_n.link_m);
-		I915_WRITE(link_n1_reg, m_n.link_n);
+		I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+		I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+		I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+		I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
 
 		if (has_edp_encoder) {
 			ironlake_set_pll_edp(crtc, adjusted_mode->clock);
 		} else {
 			/* enable FDI RX PLL too */
-			temp = I915_READ(fdi_rx_reg);
-			I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-			I915_READ(fdi_rx_reg);
+			reg = FDI_RX_CTL(pipe);
+			temp = I915_READ(reg);
+			I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
+
+			POSTING_READ(reg);
 			udelay(200);
 
 			/* enable FDI TX PLL too */
-			temp = I915_READ(fdi_tx_reg);
-			I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-			I915_READ(fdi_tx_reg);
+			reg = FDI_TX_CTL(pipe);
+			temp = I915_READ(reg);
+			I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
 
 			/* enable FDI RX PCDCLK */
-			temp = I915_READ(fdi_rx_reg);
-			I915_WRITE(fdi_rx_reg, temp | FDI_SEL_PCDCLK);
-			I915_READ(fdi_rx_reg);
+			reg = FDI_RX_CTL(pipe);
+			temp = I915_READ(reg);
+			I915_WRITE(reg, temp | FDI_PCDCLK);
+
+			POSTING_READ(reg);
 			udelay(200);
 		}
 	}
 
-	I915_WRITE(pipeconf_reg, pipeconf);
-	I915_READ(pipeconf_reg);
+	I915_WRITE(PIPECONF(pipe), pipeconf);
+	POSTING_READ(PIPECONF(pipe));
 
 	intel_wait_for_vblank(dev, pipe);
 
@@ -4090,9 +4158,8 @@
 		I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
 	}
 
-	I915_WRITE(dspcntr_reg, dspcntr);
+	I915_WRITE(DSPCNTR(plane), dspcntr);
 
-	/* Flush the plane changes */
 	ret = intel_pipe_set_base(crtc, x, y, old_fb);
 
 	intel_update_watermarks(dev);
@@ -4185,7 +4252,8 @@
 }
 
 /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
-static void intel_crtc_update_cursor(struct drm_crtc *crtc)
+static void intel_crtc_update_cursor(struct drm_crtc *crtc,
+				     bool on)
 {
 	struct drm_device *dev = crtc->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4198,7 +4266,7 @@
 
 	pos = 0;
 
-	if (intel_crtc->cursor_on && crtc->fb) {
+	if (on && crtc->enabled && crtc->fb) {
 		base = intel_crtc->cursor_addr;
 		if (x > (int) crtc->fb->width)
 			base = 0;
@@ -4310,7 +4378,7 @@
 		addr = obj_priv->phys_obj->handle->busaddr;
 	}
 
-	if (!IS_I9XX(dev))
+	if (IS_GEN2(dev))
 		I915_WRITE(CURSIZE, (height << 12) | width);
 
  finish:
@@ -4330,7 +4398,7 @@
 	intel_crtc->cursor_width = width;
 	intel_crtc->cursor_height = height;
 
-	intel_crtc_update_cursor(crtc);
+	intel_crtc_update_cursor(crtc, true);
 
 	return 0;
 fail_unpin:
@@ -4349,7 +4417,7 @@
 	intel_crtc->cursor_x = x;
 	intel_crtc->cursor_y = y;
 
-	intel_crtc_update_cursor(crtc);
+	intel_crtc_update_cursor(crtc, true);
 
 	return 0;
 }
@@ -4418,7 +4486,7 @@
 	struct intel_crtc *intel_crtc;
 	struct drm_crtc *possible_crtc;
 	struct drm_crtc *supported_crtc =NULL;
-	struct drm_encoder *encoder = &intel_encoder->enc;
+	struct drm_encoder *encoder = &intel_encoder->base;
 	struct drm_crtc *crtc = NULL;
 	struct drm_device *dev = encoder->dev;
 	struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4499,7 +4567,7 @@
 void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
 				    struct drm_connector *connector, int dpms_mode)
 {
-	struct drm_encoder *encoder = &intel_encoder->enc;
+	struct drm_encoder *encoder = &intel_encoder->base;
 	struct drm_device *dev = encoder->dev;
 	struct drm_crtc *crtc = encoder->crtc;
 	struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
@@ -4545,7 +4613,7 @@
 		clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
 	}
 
-	if (IS_I9XX(dev)) {
+	if (!IS_GEN2(dev)) {
 		if (IS_PINEVIEW(dev))
 			clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >>
 				DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW);
@@ -4649,8 +4717,6 @@
 	struct drm_device *dev = (struct drm_device *)arg;
 	drm_i915_private_t *dev_priv = dev->dev_private;
 
-	DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
 	dev_priv->busy = false;
 
 	queue_work(dev_priv->wq, &dev_priv->idle_work);
@@ -4664,14 +4730,12 @@
 	struct drm_crtc *crtc = &intel_crtc->base;
 	drm_i915_private_t *dev_priv = crtc->dev->dev_private;
 
-	DRM_DEBUG_DRIVER("idle timer fired, downclocking\n");
-
 	intel_crtc->busy = false;
 
 	queue_work(dev_priv->wq, &dev_priv->idle_work);
 }
 
-static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
+static void intel_increase_pllclock(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -4706,9 +4770,8 @@
 	}
 
 	/* Schedule downclock */
-	if (schedule)
-		mod_timer(&intel_crtc->idle_timer, jiffies +
-			  msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
+	mod_timer(&intel_crtc->idle_timer, jiffies +
+		  msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
 }
 
 static void intel_decrease_pllclock(struct drm_crtc *crtc)
@@ -4844,7 +4907,7 @@
 					I915_WRITE(FW_BLC_SELF, fw_blc_self | FW_BLC_SELF_EN_MASK);
 				}
 				/* Non-busy -> busy, upclock */
-				intel_increase_pllclock(crtc, true);
+				intel_increase_pllclock(crtc);
 				intel_crtc->busy = true;
 			} else {
 				/* Busy -> busy, put off timer */
@@ -4858,8 +4921,22 @@
 static void intel_crtc_destroy(struct drm_crtc *crtc)
 {
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct intel_unpin_work *work;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	work = intel_crtc->unpin_work;
+	intel_crtc->unpin_work = NULL;
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	if (work) {
+		cancel_work_sync(&work->work);
+		kfree(work);
+	}
 
 	drm_crtc_cleanup(crtc);
+
 	kfree(intel_crtc);
 }
 
@@ -4919,7 +4996,7 @@
 	/* Initial scanout buffer will have a 0 pending flip count */
 	if ((atomic_read(&obj_priv->pending_flip) == 0) ||
 	    atomic_dec_and_test(&obj_priv->pending_flip))
-		DRM_WAKEUP(&dev_priv->pending_flip_queue);
+		wake_up(&dev_priv->pending_flip_queue);
 	schedule_work(&work->work);
 
 	trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
@@ -5000,7 +5077,7 @@
 	obj = intel_fb->obj;
 
 	mutex_lock(&dev->struct_mutex);
-	ret = intel_pin_and_fence_fb_obj(dev, obj);
+	ret = intel_pin_and_fence_fb_obj(dev, obj, true);
 	if (ret)
 		goto cleanup_work;
 
@@ -5009,9 +5086,6 @@
 	drm_gem_object_reference(obj);
 
 	crtc->fb = fb;
-	ret = i915_gem_object_flush_write_domain(obj);
-	if (ret)
-		goto cleanup_objs;
 
 	ret = drm_vblank_get(dev, intel_crtc->pipe);
 	if (ret)
@@ -5024,14 +5098,16 @@
 	if (IS_GEN3(dev) || IS_GEN2(dev)) {
 		u32 flip_mask;
 
+		/* Can't queue multiple flips, so wait for the previous
+		 * one to finish before executing the next.
+		 */
+		BEGIN_LP_RING(2);
 		if (intel_crtc->plane)
 			flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
 		else
 			flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
-
-		BEGIN_LP_RING(2);
 		OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
-		OUT_RING(0);
+		OUT_RING(MI_NOOP);
 		ADVANCE_LP_RING();
 	}
 
@@ -5112,15 +5188,14 @@
 	return ret;
 }
 
-static const struct drm_crtc_helper_funcs intel_helper_funcs = {
+static struct drm_crtc_helper_funcs intel_helper_funcs = {
 	.dpms = intel_crtc_dpms,
 	.mode_fixup = intel_crtc_mode_fixup,
 	.mode_set = intel_crtc_mode_set,
 	.mode_set_base = intel_pipe_set_base,
 	.mode_set_base_atomic = intel_pipe_set_base_atomic,
-	.prepare = intel_crtc_prepare,
-	.commit = intel_crtc_commit,
 	.load_lut = intel_crtc_load_lut,
+	.disable = intel_crtc_disable,
 };
 
 static const struct drm_crtc_funcs intel_crtc_funcs = {
@@ -5146,8 +5221,6 @@
 	drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
 
 	drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
-	intel_crtc->pipe = pipe;
-	intel_crtc->plane = pipe;
 	for (i = 0; i < 256; i++) {
 		intel_crtc->lut_r[i] = i;
 		intel_crtc->lut_g[i] = i;
@@ -5157,9 +5230,9 @@
 	/* Swap pipes & planes for FBC on pre-965 */
 	intel_crtc->pipe = pipe;
 	intel_crtc->plane = pipe;
-	if (IS_MOBILE(dev) && (IS_I9XX(dev) && !IS_I965G(dev))) {
+	if (IS_MOBILE(dev) && IS_GEN3(dev)) {
 		DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
-		intel_crtc->plane = ((pipe == 0) ? 1 : 0);
+		intel_crtc->plane = !pipe;
 	}
 
 	BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
@@ -5169,6 +5242,16 @@
 
 	intel_crtc->cursor_addr = 0;
 	intel_crtc->dpms_mode = -1;
+	intel_crtc->active = true; /* force the pipe off on setup_init_config */
+
+	if (HAS_PCH_SPLIT(dev)) {
+		intel_helper_funcs.prepare = ironlake_crtc_prepare;
+		intel_helper_funcs.commit = ironlake_crtc_commit;
+	} else {
+		intel_helper_funcs.prepare = i9xx_crtc_prepare;
+		intel_helper_funcs.commit = i9xx_crtc_commit;
+	}
+
 	drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
 
 	intel_crtc->busy = false;
@@ -5204,38 +5287,25 @@
 	return 0;
 }
 
-struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
-{
-	struct drm_crtc *crtc = NULL;
-
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-		if (intel_crtc->pipe == pipe)
-			break;
-	}
-	return crtc;
-}
-
 static int intel_encoder_clones(struct drm_device *dev, int type_mask)
 {
+	struct intel_encoder *encoder;
 	int index_mask = 0;
-	struct drm_encoder *encoder;
 	int entry = 0;
 
-        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-		if (type_mask & intel_encoder->clone_mask)
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+		if (type_mask & encoder->clone_mask)
 			index_mask |= (1 << entry);
 		entry++;
 	}
+
 	return index_mask;
 }
 
-
 static void intel_setup_outputs(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_encoder *encoder;
+	struct intel_encoder *encoder;
 	bool dpd_is_edp = false;
 
 	if (IS_MOBILE(dev) && !IS_I830(dev))
@@ -5324,12 +5394,10 @@
 	if (SUPPORTS_TV(dev))
 		intel_tv_init(dev);
 
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-
-		encoder->possible_crtcs = intel_encoder->crtc_mask;
-		encoder->possible_clones = intel_encoder_clones(dev,
-						intel_encoder->clone_mask);
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+		encoder->base.possible_crtcs = encoder->crtc_mask;
+		encoder->base.possible_clones =
+			intel_encoder_clones(dev, encoder->clone_mask);
 	}
 }
 
@@ -5363,8 +5431,25 @@
 			   struct drm_mode_fb_cmd *mode_cmd,
 			   struct drm_gem_object *obj)
 {
+	struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
 	int ret;
 
+	if (obj_priv->tiling_mode == I915_TILING_Y)
+		return -EINVAL;
+
+	if (mode_cmd->pitch & 63)
+		return -EINVAL;
+
+	switch (mode_cmd->bpp) {
+	case 8:
+	case 16:
+	case 24:
+	case 32:
+		break;
+	default:
+		return -EINVAL;
+	}
+
 	ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
 	if (ret) {
 		DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -5473,6 +5558,10 @@
 	u32 rgvmodectl = I915_READ(MEMMODECTL);
 	u8 fmax, fmin, fstart, vstart;
 
+	/* Enable temp reporting */
+	I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
+	I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+
 	/* 100ms RC evaluation intervals */
 	I915_WRITE(RCUPEI, 100000);
 	I915_WRITE(RCDNEI, 100000);
@@ -5515,7 +5604,7 @@
 	rgvmodectl |= MEMMODE_SWMODE_EN;
 	I915_WRITE(MEMMODECTL, rgvmodectl);
 
-	if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 1, 0))
+	if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
 		DRM_ERROR("stuck trying to change perf mode\n");
 	msleep(1);
 
@@ -5714,20 +5803,20 @@
 		if (IS_GM45(dev))
 			dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
 		I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-	} else if (IS_I965GM(dev)) {
+	} else if (IS_CRESTLINE(dev)) {
 		I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
 		I915_WRITE(RENCLK_GATE_D2, 0);
 		I915_WRITE(DSPCLK_GATE_D, 0);
 		I915_WRITE(RAMCLK_GATE_D, 0);
 		I915_WRITE16(DEUC, 0);
-	} else if (IS_I965G(dev)) {
+	} else if (IS_BROADWATER(dev)) {
 		I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
 		       I965_RCC_CLOCK_GATE_DISABLE |
 		       I965_RCPB_CLOCK_GATE_DISABLE |
 		       I965_ISC_CLOCK_GATE_DISABLE |
 		       I965_FBC_CLOCK_GATE_DISABLE);
 		I915_WRITE(RENCLK_GATE_D2, 0);
-	} else if (IS_I9XX(dev)) {
+	} else if (IS_GEN3(dev)) {
 		u32 dstate = I915_READ(D_STATE);
 
 		dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
@@ -5809,7 +5898,7 @@
 			dev_priv->display.fbc_enabled = g4x_fbc_enabled;
 			dev_priv->display.enable_fbc = g4x_enable_fbc;
 			dev_priv->display.disable_fbc = g4x_disable_fbc;
-		} else if (IS_I965GM(dev)) {
+		} else if (IS_CRESTLINE(dev)) {
 			dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
 			dev_priv->display.enable_fbc = i8xx_enable_fbc;
 			dev_priv->display.disable_fbc = i8xx_disable_fbc;
@@ -5869,9 +5958,9 @@
 			dev_priv->display.update_wm = pineview_update_wm;
 	} else if (IS_G4X(dev))
 		dev_priv->display.update_wm = g4x_update_wm;
-	else if (IS_I965G(dev))
+	else if (IS_GEN4(dev))
 		dev_priv->display.update_wm = i965_update_wm;
-	else if (IS_I9XX(dev)) {
+	else if (IS_GEN3(dev)) {
 		dev_priv->display.update_wm = i9xx_update_wm;
 		dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
 	} else if (IS_I85X(dev)) {
@@ -5985,24 +6074,24 @@
 
 	intel_init_display(dev);
 
-	if (IS_I965G(dev)) {
-		dev->mode_config.max_width = 8192;
-		dev->mode_config.max_height = 8192;
-	} else if (IS_I9XX(dev)) {
+	if (IS_GEN2(dev)) {
+		dev->mode_config.max_width = 2048;
+		dev->mode_config.max_height = 2048;
+	} else if (IS_GEN3(dev)) {
 		dev->mode_config.max_width = 4096;
 		dev->mode_config.max_height = 4096;
 	} else {
-		dev->mode_config.max_width = 2048;
-		dev->mode_config.max_height = 2048;
+		dev->mode_config.max_width = 8192;
+		dev->mode_config.max_height = 8192;
 	}
 
 	/* set memory base */
-	if (IS_I9XX(dev))
-		dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
-	else
+	if (IS_GEN2(dev))
 		dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
+	else
+		dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
 
-	if (IS_MOBILE(dev) || IS_I9XX(dev))
+	if (IS_MOBILE(dev) || !IS_GEN2(dev))
 		dev_priv->num_pipe = 2;
 	else
 		dev_priv->num_pipe = 1;
@@ -6038,10 +6127,8 @@
 	struct drm_crtc *crtc;
 	struct intel_crtc *intel_crtc;
 
-	mutex_lock(&dev->struct_mutex);
-
 	drm_kms_helper_poll_fini(dev);
-	intel_fbdev_fini(dev);
+	mutex_lock(&dev->struct_mutex);
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		/* Skip inactive CRTCs */
@@ -6049,12 +6136,9 @@
 			continue;
 
 		intel_crtc = to_intel_crtc(crtc);
-		intel_increase_pllclock(crtc, false);
-		del_timer_sync(&intel_crtc->idle_timer);
+		intel_increase_pllclock(crtc);
 	}
 
-	del_timer_sync(&dev_priv->idle_timer);
-
 	if (dev_priv->display.disable_fbc)
 		dev_priv->display.disable_fbc(dev);
 
@@ -6083,33 +6167,36 @@
 
 	mutex_unlock(&dev->struct_mutex);
 
+	/* Disable the irq before mode object teardown, for the irq might
+	 * enqueue unpin/hotplug work. */
+	drm_irq_uninstall(dev);
+	cancel_work_sync(&dev_priv->hotplug_work);
+
+	/* Shut off idle work before the crtcs get freed. */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		intel_crtc = to_intel_crtc(crtc);
+		del_timer_sync(&intel_crtc->idle_timer);
+	}
+	del_timer_sync(&dev_priv->idle_timer);
+	cancel_work_sync(&dev_priv->idle_work);
+
 	drm_mode_config_cleanup(dev);
 }
 
-
 /*
  * Return which encoder is currently attached for connector.
  */
-struct drm_encoder *intel_attached_encoder (struct drm_connector *connector)
+struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
 {
-	struct drm_mode_object *obj;
-	struct drm_encoder *encoder;
-	int i;
+	return &intel_attached_encoder(connector)->base;
+}
 
-	for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-		if (connector->encoder_ids[i] == 0)
-			break;
-
-		obj = drm_mode_object_find(connector->dev,
-                                           connector->encoder_ids[i],
-                                           DRM_MODE_OBJECT_ENCODER);
-		if (!obj)
-			continue;
-
-		encoder = obj_to_encoder(obj);
-		return encoder;
-	}
-	return NULL;
+void intel_connector_attach_encoder(struct intel_connector *connector,
+				    struct intel_encoder *encoder)
+{
+	connector->encoder = encoder;
+	drm_mode_connector_attach_encoder(&connector->base,
+					  &encoder->base);
 }
 
 /*
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1a51ee0..152d945 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -58,14 +58,23 @@
 	struct i2c_adapter adapter;
 	struct i2c_algo_dp_aux_data algo;
 	bool is_pch_edp;
+	uint8_t	train_set[4];
+	uint8_t link_status[DP_LINK_STATUS_SIZE];
 };
 
 static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_dp, base);
+	return container_of(encoder, struct intel_dp, base.base);
 }
 
-static void intel_dp_link_train(struct intel_dp *intel_dp);
+static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_dp, base);
+}
+
+static void intel_dp_start_link_train(struct intel_dp *intel_dp);
+static void intel_dp_complete_link_train(struct intel_dp *intel_dp);
 static void intel_dp_link_down(struct intel_dp *intel_dp);
 
 void
@@ -130,7 +139,7 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
 	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
-		return (pixel_clock * dev_priv->edp_bpp) / 8;
+		return (pixel_clock * dev_priv->edp.bpp + 7) / 8;
 	else
 		return pixel_clock * 3;
 }
@@ -145,8 +154,7 @@
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
@@ -233,7 +241,7 @@
 		uint8_t *recv, int recv_size)
 {
 	uint32_t output_reg = intel_dp->output_reg;
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t ch_ctl = output_reg + 0x10;
 	uint32_t ch_data = ch_ctl + 4;
@@ -246,8 +254,11 @@
 	/* The clock divider is based off the hrawclk,
 	 * and would like to run at 2MHz. So, take the
 	 * hrawclk value and divide by 2 and use that
+	 *
+	 * Note that PCH attached eDP panels should use a 125MHz input
+	 * clock divider.
 	 */
-	if (IS_eDP(intel_dp)) {
+	if (IS_eDP(intel_dp) && !IS_PCH_eDP(intel_dp)) {
 		if (IS_GEN6(dev))
 			aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
 		else
@@ -642,7 +653,7 @@
 		if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
 			lane_count = intel_dp->lane_count;
 			if (IS_PCH_eDP(intel_dp))
-				bpp = dev_priv->edp_bpp;
+				bpp = dev_priv->edp.bpp;
 			break;
 		}
 	}
@@ -698,7 +709,7 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-	struct drm_crtc *crtc = intel_dp->base.enc.crtc;
+	struct drm_crtc *crtc = intel_dp->base.base.crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
 	intel_dp->DP = (DP_VOLTAGE_0_4 |
@@ -754,13 +765,14 @@
 	}
 }
 
-static void ironlake_edp_panel_on (struct drm_device *dev)
+/* Returns true if the panel was already on when called */
+static bool ironlake_edp_panel_on (struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pp;
 
 	if (I915_READ(PCH_PP_STATUS) & PP_ON)
-		return;
+		return true;
 
 	pp = I915_READ(PCH_PP_CONTROL);
 
@@ -769,17 +781,24 @@
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
 
-	pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
+	pp |= POWER_TARGET_ON;
 	I915_WRITE(PCH_PP_CONTROL, pp);
 
-	if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000, 10))
+	/* Ouch. We need to wait here for some panels, like Dell e6510
+	 * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+	 */
+	msleep(300);
+
+	if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000))
 		DRM_ERROR("panel on wait timed out: 0x%08x\n",
 			  I915_READ(PCH_PP_STATUS));
 
-	pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD);
+	pp &= ~(PANEL_UNLOCK_REGS);
 	pp |= PANEL_POWER_RESET; /* restore panel reset bit */
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
+
+	return false;
 }
 
 static void ironlake_edp_panel_off (struct drm_device *dev)
@@ -797,14 +816,43 @@
 	pp &= ~POWER_TARGET_ON;
 	I915_WRITE(PCH_PP_CONTROL, pp);
 
-	if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000, 10))
+	if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000))
 		DRM_ERROR("panel off wait timed out: 0x%08x\n",
 			  I915_READ(PCH_PP_STATUS));
 
 	/* Make sure VDD is enabled so DP AUX will work */
-	pp |= EDP_FORCE_VDD | PANEL_POWER_RESET; /* restore panel reset bit */
+	pp |= PANEL_POWER_RESET; /* restore panel reset bit */
 	I915_WRITE(PCH_PP_CONTROL, pp);
 	POSTING_READ(PCH_PP_CONTROL);
+
+	/* Ouch. We need to wait here for some panels, like Dell e6510
+	 * https://bugs.freedesktop.org/show_bug.cgi?id=29278i
+	 */
+	msleep(300);
+}
+
+static void ironlake_edp_panel_vdd_on(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 pp;
+
+	pp = I915_READ(PCH_PP_CONTROL);
+	pp |= EDP_FORCE_VDD;
+	I915_WRITE(PCH_PP_CONTROL, pp);
+	POSTING_READ(PCH_PP_CONTROL);
+	msleep(300);
+}
+
+static void ironlake_edp_panel_vdd_off(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 pp;
+
+	pp = I915_READ(PCH_PP_CONTROL);
+	pp &= ~EDP_FORCE_VDD;
+	I915_WRITE(PCH_PP_CONTROL, pp);
+	POSTING_READ(PCH_PP_CONTROL);
+	msleep(300);
 }
 
 static void ironlake_edp_backlight_on (struct drm_device *dev)
@@ -850,6 +898,7 @@
 	dpa_ctl = I915_READ(DP_A);
 	dpa_ctl |= DP_PLL_ENABLE;
 	I915_WRITE(DP_A, dpa_ctl);
+	POSTING_READ(DP_A);
 	udelay(200);
 }
 
@@ -860,9 +909,10 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-	if (IS_eDP(intel_dp)) {
+	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
+		ironlake_edp_panel_off(dev);
 		ironlake_edp_backlight_off(dev);
-		ironlake_edp_panel_on(dev);
+		ironlake_edp_panel_vdd_on(dev);
 		ironlake_edp_pll_on(encoder);
 	}
 	if (dp_reg & DP_PORT_EN)
@@ -873,14 +923,17 @@
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	struct drm_device *dev = encoder->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint32_t dp_reg = I915_READ(intel_dp->output_reg);
 
-	if (!(dp_reg & DP_PORT_EN)) {
-		intel_dp_link_train(intel_dp);
-	}
+	intel_dp_start_link_train(intel_dp);
+
+	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+		ironlake_edp_panel_on(dev);
+
+	intel_dp_complete_link_train(intel_dp);
+
 	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
 		ironlake_edp_backlight_on(dev);
+	intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
 }
 
 static void
@@ -902,9 +955,10 @@
 			ironlake_edp_pll_off(encoder);
 	} else {
 		if (!(dp_reg & DP_PORT_EN)) {
+			intel_dp_start_link_train(intel_dp);
 			if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
 				ironlake_edp_panel_on(dev);
-			intel_dp_link_train(intel_dp);
+			intel_dp_complete_link_train(intel_dp);
 			if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
 				ironlake_edp_backlight_on(dev);
 		}
@@ -917,14 +971,13 @@
  * link status information
  */
 static bool
-intel_dp_get_link_status(struct intel_dp *intel_dp,
-			 uint8_t link_status[DP_LINK_STATUS_SIZE])
+intel_dp_get_link_status(struct intel_dp *intel_dp)
 {
 	int ret;
 
 	ret = intel_dp_aux_native_read(intel_dp,
 				       DP_LANE0_1_STATUS,
-				       link_status, DP_LINK_STATUS_SIZE);
+				       intel_dp->link_status, DP_LINK_STATUS_SIZE);
 	if (ret != DP_LINK_STATUS_SIZE)
 		return false;
 	return true;
@@ -999,18 +1052,15 @@
 }
 
 static void
-intel_get_adjust_train(struct intel_dp *intel_dp,
-		       uint8_t link_status[DP_LINK_STATUS_SIZE],
-		       int lane_count,
-		       uint8_t train_set[4])
+intel_get_adjust_train(struct intel_dp *intel_dp)
 {
 	uint8_t v = 0;
 	uint8_t p = 0;
 	int lane;
 
-	for (lane = 0; lane < lane_count; lane++) {
-		uint8_t this_v = intel_get_adjust_request_voltage(link_status, lane);
-		uint8_t this_p = intel_get_adjust_request_pre_emphasis(link_status, lane);
+	for (lane = 0; lane < intel_dp->lane_count; lane++) {
+		uint8_t this_v = intel_get_adjust_request_voltage(intel_dp->link_status, lane);
+		uint8_t this_p = intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane);
 
 		if (this_v > v)
 			v = this_v;
@@ -1025,7 +1075,7 @@
 		p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
 	for (lane = 0; lane < 4; lane++)
-		train_set[lane] = v | p;
+		intel_dp->train_set[lane] = v | p;
 }
 
 static uint32_t
@@ -1116,18 +1166,18 @@
 			 DP_LANE_CHANNEL_EQ_DONE|\
 			 DP_LANE_SYMBOL_LOCKED)
 static bool
-intel_channel_eq_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+intel_channel_eq_ok(struct intel_dp *intel_dp)
 {
 	uint8_t lane_align;
 	uint8_t lane_status;
 	int lane;
 
-	lane_align = intel_dp_link_status(link_status,
+	lane_align = intel_dp_link_status(intel_dp->link_status,
 					  DP_LANE_ALIGN_STATUS_UPDATED);
 	if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
 		return false;
-	for (lane = 0; lane < lane_count; lane++) {
-		lane_status = intel_get_lane_status(link_status, lane);
+	for (lane = 0; lane < intel_dp->lane_count; lane++) {
+		lane_status = intel_get_lane_status(intel_dp->link_status, lane);
 		if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS)
 			return false;
 	}
@@ -1137,48 +1187,47 @@
 static bool
 intel_dp_set_link_train(struct intel_dp *intel_dp,
 			uint32_t dp_reg_value,
-			uint8_t dp_train_pat,
-			uint8_t train_set[4],
-			bool first)
+			uint8_t dp_train_pat)
 {
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.enc.crtc);
 	int ret;
 
 	I915_WRITE(intel_dp->output_reg, dp_reg_value);
 	POSTING_READ(intel_dp->output_reg);
-	if (first)
-		intel_wait_for_vblank(dev, intel_crtc->pipe);
 
 	intel_dp_aux_native_write_1(intel_dp,
 				    DP_TRAINING_PATTERN_SET,
 				    dp_train_pat);
 
 	ret = intel_dp_aux_native_write(intel_dp,
-					DP_TRAINING_LANE0_SET, train_set, 4);
+					DP_TRAINING_LANE0_SET,
+					intel_dp->train_set, 4);
 	if (ret != 4)
 		return false;
 
 	return true;
 }
 
+/* Enable corresponding port and start training pattern 1 */
 static void
-intel_dp_link_train(struct intel_dp *intel_dp)
+intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	uint8_t	train_set[4];
-	uint8_t link_status[DP_LINK_STATUS_SIZE];
+	struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
 	int i;
 	uint8_t voltage;
 	bool clock_recovery = false;
-	bool channel_eq = false;
-	bool first = true;
 	int tries;
 	u32 reg;
 	uint32_t DP = intel_dp->DP;
 
+	/* Enable output, wait for it to become active */
+	I915_WRITE(intel_dp->output_reg, intel_dp->DP);
+	POSTING_READ(intel_dp->output_reg);
+	intel_wait_for_vblank(dev, intel_crtc->pipe);
+
 	/* Write the link configuration data */
 	intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
 				  intel_dp->link_configuration,
@@ -1189,18 +1238,18 @@
 		DP &= ~DP_LINK_TRAIN_MASK_CPT;
 	else
 		DP &= ~DP_LINK_TRAIN_MASK;
-	memset(train_set, 0, 4);
+	memset(intel_dp->train_set, 0, 4);
 	voltage = 0xff;
 	tries = 0;
 	clock_recovery = false;
 	for (;;) {
-		/* Use train_set[0] to set the voltage and pre emphasis values */
+		/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
 		uint32_t    signal_levels;
 		if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
-			signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+			signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
 			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
 		} else {
-			signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+			signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
 			DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
 		}
 
@@ -1210,52 +1259,64 @@
 			reg = DP | DP_LINK_TRAIN_PAT_1;
 
 		if (!intel_dp_set_link_train(intel_dp, reg,
-					     DP_TRAINING_PATTERN_1, train_set, first))
+					     DP_TRAINING_PATTERN_1))
 			break;
-		first = false;
 		/* Set training pattern 1 */
 
 		udelay(100);
-		if (!intel_dp_get_link_status(intel_dp, link_status))
+		if (!intel_dp_get_link_status(intel_dp))
 			break;
 
-		if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) {
+		if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
 			clock_recovery = true;
 			break;
 		}
 
 		/* Check to see if we've tried the max voltage */
 		for (i = 0; i < intel_dp->lane_count; i++)
-			if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+			if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
 				break;
 		if (i == intel_dp->lane_count)
 			break;
 
 		/* Check to see if we've tried the same voltage 5 times */
-		if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
 			++tries;
 			if (tries == 5)
 				break;
 		} else
 			tries = 0;
-		voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
-		/* Compute new train_set as requested by target */
-		intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
+		/* Compute new intel_dp->train_set as requested by target */
+		intel_get_adjust_train(intel_dp);
 	}
 
+	intel_dp->DP = DP;
+}
+
+static void
+intel_dp_complete_link_train(struct intel_dp *intel_dp)
+{
+	struct drm_device *dev = intel_dp->base.base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	bool channel_eq = false;
+	int tries;
+	u32 reg;
+	uint32_t DP = intel_dp->DP;
+
 	/* channel equalization */
 	tries = 0;
 	channel_eq = false;
 	for (;;) {
-		/* Use train_set[0] to set the voltage and pre emphasis values */
+		/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
 		uint32_t    signal_levels;
 
 		if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
-			signal_levels = intel_gen6_edp_signal_levels(train_set[0]);
+			signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
 			DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
 		} else {
-			signal_levels = intel_dp_signal_levels(train_set[0], intel_dp->lane_count);
+			signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
 			DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
 		}
 
@@ -1266,15 +1327,14 @@
 
 		/* channel eq pattern */
 		if (!intel_dp_set_link_train(intel_dp, reg,
-					     DP_TRAINING_PATTERN_2, train_set,
-					     false))
+					     DP_TRAINING_PATTERN_2))
 			break;
 
 		udelay(400);
-		if (!intel_dp_get_link_status(intel_dp, link_status))
+		if (!intel_dp_get_link_status(intel_dp))
 			break;
 
-		if (intel_channel_eq_ok(link_status, intel_dp->lane_count)) {
+		if (intel_channel_eq_ok(intel_dp)) {
 			channel_eq = true;
 			break;
 		}
@@ -1283,8 +1343,8 @@
 		if (tries > 5)
 			break;
 
-		/* Compute new train_set as requested by target */
-		intel_get_adjust_train(intel_dp, link_status, intel_dp->lane_count, train_set);
+		/* Compute new intel_dp->train_set as requested by target */
+		intel_get_adjust_train(intel_dp);
 		++tries;
 	}
 
@@ -1302,7 +1362,7 @@
 static void
 intel_dp_link_down(struct intel_dp *intel_dp)
 {
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t DP = intel_dp->DP;
 
@@ -1318,14 +1378,13 @@
 	if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp)) {
 		DP &= ~DP_LINK_TRAIN_MASK_CPT;
 		I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
-		POSTING_READ(intel_dp->output_reg);
 	} else {
 		DP &= ~DP_LINK_TRAIN_MASK;
 		I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
-		POSTING_READ(intel_dp->output_reg);
 	}
+	POSTING_READ(intel_dp->output_reg);
 
-	udelay(17000);
+	msleep(17);
 
 	if (IS_eDP(intel_dp))
 		DP |= DP_LINK_TRAIN_OFF;
@@ -1345,27 +1404,29 @@
 static void
 intel_dp_check_link_status(struct intel_dp *intel_dp)
 {
-	uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-	if (!intel_dp->base.enc.crtc)
+	if (!intel_dp->base.base.crtc)
 		return;
 
-	if (!intel_dp_get_link_status(intel_dp, link_status)) {
+	if (!intel_dp_get_link_status(intel_dp)) {
 		intel_dp_link_down(intel_dp);
 		return;
 	}
 
-	if (!intel_channel_eq_ok(link_status, intel_dp->lane_count))
-		intel_dp_link_train(intel_dp);
+	if (!intel_channel_eq_ok(intel_dp)) {
+		intel_dp_start_link_train(intel_dp);
+		intel_dp_complete_link_train(intel_dp);
+	}
 }
 
 static enum drm_connector_status
 ironlake_dp_detect(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
 	enum drm_connector_status status;
 
+	/* Panel needs power for AUX to work */
+	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+		ironlake_edp_panel_vdd_on(connector->dev);
 	status = connector_status_disconnected;
 	if (intel_dp_aux_native_read(intel_dp,
 				     0x000, intel_dp->dpcd,
@@ -1376,6 +1437,8 @@
 	}
 	DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
 		      intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
+	if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
+		ironlake_edp_panel_vdd_off(connector->dev);
 	return status;
 }
 
@@ -1388,9 +1451,8 @@
 static enum drm_connector_status
 intel_dp_detect(struct drm_connector *connector, bool force)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t temp, bit;
 	enum drm_connector_status status;
@@ -1432,16 +1494,15 @@
 
 static int intel_dp_get_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-	struct drm_device *dev = intel_dp->base.enc.dev;
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct drm_device *dev = intel_dp->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
 	/* We should parse the EDID data and find out if it has an audio sink
 	 */
 
-	ret = intel_ddc_get_modes(connector, intel_dp->base.ddc_bus);
+	ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
 	if (ret) {
 		if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
 		    !dev_priv->panel_fixed_mode) {
@@ -1479,6 +1540,15 @@
 	kfree(connector);
 }
 
+static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+
+	i2c_del_adapter(&intel_dp->adapter);
+	drm_encoder_cleanup(encoder);
+	kfree(intel_dp);
+}
+
 static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
 	.dpms = intel_dp_dpms,
 	.mode_fixup = intel_dp_mode_fixup,
@@ -1497,14 +1567,14 @@
 static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
 	.get_modes = intel_dp_get_modes,
 	.mode_valid = intel_dp_mode_valid,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_dp_enc_funcs = {
-	.destroy = intel_encoder_destroy,
+	.destroy = intel_dp_encoder_destroy,
 };
 
-void
+static void
 intel_dp_hot_plug(struct intel_encoder *intel_encoder)
 {
 	struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base);
@@ -1613,12 +1683,11 @@
 	intel_dp->has_audio = false;
 	intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_dp_enc_funcs,
+	drm_encoder_init(dev, &intel_encoder->base, &intel_dp_enc_funcs,
 			 DRM_MODE_ENCODER_TMDS);
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_dp_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_dp_helper_funcs);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base,
-					  &intel_encoder->enc);
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	drm_sysfs_connector_add(connector);
 
 	/* Set up the DDC bus. */
@@ -1648,7 +1717,6 @@
 
 	intel_dp_i2c_init(intel_dp, intel_connector, name);
 
-	intel_encoder->ddc_bus = &intel_dp->adapter;
 	intel_encoder->hot_plug = intel_dp_hot_plug;
 
 	if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ad312ca..40e99bf 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -26,14 +26,12 @@
 #define __INTEL_DRV_H__
 
 #include <linux/i2c.h>
-#include <linux/i2c-id.h>
-#include <linux/i2c-algo-bit.h>
 #include "i915_drv.h"
 #include "drm_crtc.h"
-
 #include "drm_crtc_helper.h"
+#include "drm_fb_helper.h"
 
-#define wait_for(COND, MS, W) ({ \
+#define _wait_for(COND, MS, W) ({ \
 	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);	\
 	int ret__ = 0;							\
 	while (! (COND)) {						\
@@ -41,11 +39,24 @@
 			ret__ = -ETIMEDOUT;				\
 			break;						\
 		}							\
-		if (W) msleep(W);					\
+		if (W && !in_dbg_master()) msleep(W);			\
 	}								\
 	ret__;								\
 })
 
+#define wait_for(COND, MS) _wait_for(COND, MS, 1)
+#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
+
+#define MSLEEP(x) do { \
+	if (in_dbg_master()) \
+	       	mdelay(x); \
+	else \
+		msleep(x); \
+} while(0)
+
+#define KHz(x) (1000*x)
+#define MHz(x) KHz(1000*x)
+
 /*
  * Display related stuff
  */
@@ -96,24 +107,39 @@
 #define INTEL_DVO_CHIP_TMDS 2
 #define INTEL_DVO_CHIP_TVOUT 4
 
-struct intel_i2c_chan {
-	struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */
-	u32 reg; /* GPIO reg */
-	struct i2c_adapter adapter;
-	struct i2c_algo_bit_data algo;
-};
+/* drm_display_mode->private_flags */
+#define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
+#define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
+
+static inline void
+intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
+				int multiplier)
+{
+	mode->clock *= multiplier;
+	mode->private_flags |= multiplier;
+}
+
+static inline int
+intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
+{
+	return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
+}
 
 struct intel_framebuffer {
 	struct drm_framebuffer base;
 	struct drm_gem_object *obj;
 };
 
+struct intel_fbdev {
+	struct drm_fb_helper helper;
+	struct intel_framebuffer ifb;
+	struct list_head fbdev_list;
+	struct drm_display_mode *our_mode;
+};
 
 struct intel_encoder {
-	struct drm_encoder enc;
+	struct drm_encoder base;
 	int type;
-	struct i2c_adapter *i2c_bus;
-	struct i2c_adapter *ddc_bus;
 	bool load_detect_temp;
 	bool needs_tv_clock;
 	void (*hot_plug)(struct intel_encoder *);
@@ -123,32 +149,7 @@
 
 struct intel_connector {
 	struct drm_connector base;
-};
-
-struct intel_crtc;
-struct intel_overlay {
-	struct drm_device *dev;
-	struct intel_crtc *crtc;
-	struct drm_i915_gem_object *vid_bo;
-	struct drm_i915_gem_object *old_vid_bo;
-	int active;
-	int pfit_active;
-	u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
-	u32 color_key;
-	u32 brightness, contrast, saturation;
-	u32 old_xscale, old_yscale;
-	/* register access */
-	u32 flip_addr;
-	struct drm_i915_gem_object *reg_bo;
-	void *virt_addr;
-	/* flip handling */
-	uint32_t last_flip_req;
-	int hw_wedged;
-#define HW_WEDGED		1
-#define NEEDS_WAIT_FOR_FLIP	2
-#define RELEASE_OLD_VID		3
-#define SWITCH_OFF_STAGE_1	4
-#define SWITCH_OFF_STAGE_2	5
+	struct intel_encoder *encoder;
 };
 
 struct intel_crtc {
@@ -157,6 +158,7 @@
 	enum plane plane;
 	u8 lut_r[256], lut_g[256], lut_b[256];
 	int dpms_mode;
+	bool active; /* is the crtc on? independent of the dpms mode */
 	bool busy; /* is scanout buffer being updated frequently? */
 	struct timer_list idle_timer;
 	bool lowfreq_avail;
@@ -168,14 +170,21 @@
 	uint32_t cursor_addr;
 	int16_t cursor_x, cursor_y;
 	int16_t cursor_width, cursor_height;
-	bool cursor_visible, cursor_on;
+	bool cursor_visible;
 };
 
 #define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
 #define to_intel_connector(x) container_of(x, struct intel_connector, base)
-#define enc_to_intel_encoder(x) container_of(x, struct intel_encoder, enc)
+#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
 #define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
 
+static inline struct drm_crtc *
+intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	return dev_priv->pipe_to_crtc_mapping[pipe];
+}
+
 struct intel_unpin_work {
 	struct work_struct work;
 	struct drm_device *dev;
@@ -186,13 +195,8 @@
 	bool enable_stall_check;
 };
 
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
-				     const char *name);
-void intel_i2c_destroy(struct i2c_adapter *adapter);
 int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
-extern bool intel_ddc_probe(struct intel_encoder *intel_encoder);
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable);
-void intel_i2c_reset_gmbus(struct drm_device *dev);
+extern bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus);
 
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
@@ -209,29 +213,37 @@
 extern bool intel_dpd_is_edp(struct drm_device *dev);
 extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
 
-
+/* intel_panel.c */
 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,
 				    int fitting_mode,
 				    struct drm_display_mode *mode,
 				    struct drm_display_mode *adjusted_mode);
+extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
+extern u32 intel_panel_get_backlight(struct drm_device *dev);
+extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
 
-extern int intel_panel_fitter_pipe (struct drm_device *dev);
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
 extern void intel_encoder_commit (struct drm_encoder *encoder);
 extern void intel_encoder_destroy(struct drm_encoder *encoder);
 
-extern struct drm_encoder *intel_attached_encoder(struct drm_connector *connector);
+static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
+{
+	return to_intel_connector(connector)->encoder;
+}
+
+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);
 int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
 				struct drm_file *file_priv);
-extern void intel_wait_for_vblank_off(struct drm_device *dev, int pipe);
 extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
+extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
 extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
 						   struct drm_connector *connector,
 						   struct drm_display_mode *mode,
@@ -253,7 +265,8 @@
 extern void ironlake_disable_drps(struct drm_device *dev);
 
 extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
-				      struct drm_gem_object *obj);
+				      struct drm_gem_object *obj,
+				      bool pipelined);
 
 extern int intel_framebuffer_init(struct drm_device *dev,
 				  struct intel_framebuffer *ifb,
@@ -268,9 +281,8 @@
 
 extern void intel_setup_overlay(struct drm_device *dev);
 extern void intel_cleanup_overlay(struct drm_device *dev);
-extern int intel_overlay_switch_off(struct intel_overlay *overlay);
-extern int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
-						int interruptible);
+extern int intel_overlay_switch_off(struct intel_overlay *overlay,
+				    bool interruptible);
 extern int intel_overlay_put_image(struct drm_device *dev, void *data,
 				   struct drm_file *file_priv);
 extern int intel_overlay_attrs(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 7c9ec14..ea37328 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -72,7 +72,7 @@
 		.name = "ch7017",
 		.dvo_reg = DVOC,
 		.slave_addr = 0x75,
-		.gpio = GPIOE,
+		.gpio = GMBUS_PORT_DPB,
 		.dev_ops = &ch7017_ops,
 	}
 };
@@ -88,7 +88,13 @@
 
 static struct intel_dvo *enc_to_intel_dvo(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_dvo, base);
+	return container_of(encoder, struct intel_dvo, base.base);
+}
+
+static struct intel_dvo *intel_attached_dvo(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_dvo, base);
 }
 
 static void intel_dvo_dpms(struct drm_encoder *encoder, int mode)
@@ -112,8 +118,7 @@
 static int intel_dvo_mode_valid(struct drm_connector *connector,
 				struct drm_display_mode *mode)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 
 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 		return MODE_NO_DBLESCAN;
@@ -224,23 +229,22 @@
 static enum drm_connector_status
 intel_dvo_detect(struct drm_connector *connector, bool force)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
-
+	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 	return intel_dvo->dev.dev_ops->detect(&intel_dvo->dev);
 }
 
 static int intel_dvo_get_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+	struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
 	/* We should probably have an i2c driver get_modes function for those
 	 * devices which will have a fixed set of modes determined by the chip
 	 * (TV-out, for example), but for now with just TMDS and LVDS,
 	 * that's not the case.
 	 */
-	intel_ddc_get_modes(connector, intel_dvo->base.ddc_bus);
+	intel_ddc_get_modes(connector,
+			    &dev_priv->gmbus[GMBUS_PORT_DPC].adapter);
 	if (!list_empty(&connector->probed_modes))
 		return 1;
 
@@ -281,7 +285,7 @@
 static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
 	.mode_valid = intel_dvo_mode_valid,
 	.get_modes = intel_dvo_get_modes,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static void intel_dvo_enc_destroy(struct drm_encoder *encoder)
@@ -311,8 +315,7 @@
 {
 	struct drm_device *dev = connector->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_dvo *intel_dvo = enc_to_intel_dvo(encoder);
+	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;
 
@@ -323,7 +326,7 @@
 		struct drm_crtc *crtc;
 		int pipe = (dvo_val & DVO_PIPE_B_SELECT) ? 1 : 0;
 
-		crtc = intel_get_crtc_from_pipe(dev, pipe);
+		crtc = intel_get_crtc_for_pipe(dev, pipe);
 		if (crtc) {
 			mode = intel_crtc_mode_get(dev, crtc);
 			if (mode) {
@@ -341,11 +344,10 @@
 
 void intel_dvo_init(struct drm_device *dev)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *intel_encoder;
 	struct intel_dvo *intel_dvo;
 	struct intel_connector *intel_connector;
-	struct i2c_adapter *i2cbus = NULL;
-	int ret = 0;
 	int i;
 	int encoder_type = DRM_MODE_ENCODER_NONE;
 
@@ -360,16 +362,14 @@
 	}
 
 	intel_encoder = &intel_dvo->base;
-
-	/* Set up the DDC bus */
-	intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "DVODDC_D");
-	if (!intel_encoder->ddc_bus)
-		goto free_intel;
+	drm_encoder_init(dev, &intel_encoder->base,
+			 &intel_dvo_enc_funcs, encoder_type);
 
 	/* Now, try to find a controller */
 	for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
 		struct drm_connector *connector = &intel_connector->base;
 		const struct intel_dvo_device *dvo = &intel_dvo_devices[i];
+		struct i2c_adapter *i2c;
 		int gpio;
 
 		/* Allow the I2C driver info to specify the GPIO to be used in
@@ -379,24 +379,18 @@
 		if (dvo->gpio != 0)
 			gpio = dvo->gpio;
 		else if (dvo->type == INTEL_DVO_CHIP_LVDS)
-			gpio = GPIOB;
+			gpio = GMBUS_PORT_SSC;
 		else
-			gpio = GPIOE;
+			gpio = GMBUS_PORT_DPB;
 
 		/* Set up the I2C bus necessary for the chip we're probing.
 		 * It appears that everything is on GPIOE except for panels
 		 * on i830 laptops, which are on GPIOB (DVOA).
 		 */
-		if (i2cbus != NULL)
-			intel_i2c_destroy(i2cbus);
-		if (!(i2cbus = intel_i2c_create(dev, gpio,
-			gpio == GPIOB ? "DVOI2C_B" : "DVOI2C_E"))) {
-			continue;
-		}
+		i2c = &dev_priv->gmbus[gpio].adapter;
 
 		intel_dvo->dev = *dvo;
-		ret = dvo->dev_ops->init(&intel_dvo->dev, i2cbus);
-		if (!ret)
+		if (!dvo->dev_ops->init(&intel_dvo->dev, i2c))
 			continue;
 
 		intel_encoder->type = INTEL_OUTPUT_DVO;
@@ -427,13 +421,10 @@
 		connector->interlace_allowed = false;
 		connector->doublescan_allowed = false;
 
-		drm_encoder_init(dev, &intel_encoder->enc,
-				 &intel_dvo_enc_funcs, encoder_type);
-		drm_encoder_helper_add(&intel_encoder->enc,
+		drm_encoder_helper_add(&intel_encoder->base,
 				       &intel_dvo_helper_funcs);
 
-		drm_mode_connector_attach_encoder(&intel_connector->base,
-						  &intel_encoder->enc);
+		intel_connector_attach_encoder(intel_connector, intel_encoder);
 		if (dvo->type == INTEL_DVO_CHIP_LVDS) {
 			/* For our LVDS chipsets, we should hopefully be able
 			 * to dig the fixed panel mode out of the BIOS data.
@@ -451,11 +442,7 @@
 		return;
 	}
 
-	intel_i2c_destroy(intel_encoder->ddc_bus);
-	/* Didn't find a chip, so tear down. */
-	if (i2cbus != NULL)
-		intel_i2c_destroy(i2cbus);
-free_intel:
+	drm_encoder_cleanup(&intel_encoder->base);
 	kfree(intel_dvo);
 	kfree(intel_connector);
 }
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 7bdc962..7dc50ac 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -44,13 +44,6 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-struct intel_fbdev {
-	struct drm_fb_helper helper;
-	struct intel_framebuffer ifb;
-	struct list_head fbdev_list;
-	struct drm_display_mode *our_mode;
-};
-
 static struct fb_ops intelfb_ops = {
 	.owner = THIS_MODULE,
 	.fb_check_var = drm_fb_helper_check_var,
@@ -75,7 +68,7 @@
 	struct drm_gem_object *fbo = NULL;
 	struct drm_i915_gem_object *obj_priv;
 	struct device *device = &dev->pdev->dev;
-	int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+	int size, ret, mmio_bar = IS_GEN2(dev) ? 1 : 0;
 
 	/* we don't do packed 24bpp */
 	if (sizes->surface_bpp == 24)
@@ -100,19 +93,13 @@
 
 	mutex_lock(&dev->struct_mutex);
 
-	ret = intel_pin_and_fence_fb_obj(dev, fbo);
+	/* Flush everything out, we'll be doing GTT only from now on */
+	ret = intel_pin_and_fence_fb_obj(dev, fbo, false);
 	if (ret) {
 		DRM_ERROR("failed to pin fb: %d\n", ret);
 		goto out_unref;
 	}
 
-	/* Flush everything out, we'll be doing GTT only from now on */
-	ret = i915_gem_object_set_to_gtt_domain(fbo, 1);
-	if (ret) {
-		DRM_ERROR("failed to bind fb: %d.\n", ret);
-		goto out_unpin;
-	}
-
 	info = framebuffer_alloc(0, device);
 	if (!info) {
 		ret = -ENOMEM;
@@ -142,7 +129,7 @@
 		goto out_unpin;
 	}
 	info->apertures->ranges[0].base = dev->mode_config.fb_base;
-	if (IS_I9XX(dev))
+	if (!IS_GEN2(dev))
 		info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 2);
 	else
 		info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
@@ -219,8 +206,8 @@
 	.fb_probe = intel_fb_find_or_create_single,
 };
 
-int intel_fbdev_destroy(struct drm_device *dev,
-			struct intel_fbdev *ifbdev)
+static void intel_fbdev_destroy(struct drm_device *dev,
+				struct intel_fbdev *ifbdev)
 {
 	struct fb_info *info;
 	struct intel_framebuffer *ifb = &ifbdev->ifb;
@@ -238,9 +225,7 @@
 
 	drm_framebuffer_cleanup(&ifb->base);
 	if (ifb->obj)
-		drm_gem_object_unreference(ifb->obj);
-
-	return 0;
+		drm_gem_object_unreference_unlocked(ifb->obj);
 }
 
 int intel_fbdev_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 926934a..9fb9501 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -40,12 +40,19 @@
 struct intel_hdmi {
 	struct intel_encoder base;
 	u32 sdvox_reg;
+	int ddc_bus;
 	bool has_hdmi_sink;
 };
 
 static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_hdmi, base);
+	return container_of(encoder, struct intel_hdmi, base.base);
+}
+
+static struct intel_hdmi *intel_attached_hdmi(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_hdmi, base);
 }
 
 static void intel_hdmi_mode_set(struct drm_encoder *encoder,
@@ -141,13 +148,14 @@
 static enum drm_connector_status
 intel_hdmi_detect(struct drm_connector *connector, bool force)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-	struct edid *edid = NULL;
+	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
+	struct edid *edid;
 	enum drm_connector_status status = connector_status_disconnected;
 
 	intel_hdmi->has_hdmi_sink = false;
-	edid = drm_get_edid(connector, intel_hdmi->base.ddc_bus);
+	edid = drm_get_edid(connector,
+			    &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
 
 	if (edid) {
 		if (edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -163,14 +171,15 @@
 
 static int intel_hdmi_get_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 
 	/* We should parse the EDID data and find out if it's an HDMI sink so
 	 * we can send audio to it.
 	 */
 
-	return intel_ddc_get_modes(connector, intel_hdmi->base.ddc_bus);
+	return intel_ddc_get_modes(connector,
+				   &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
 }
 
 static void intel_hdmi_destroy(struct drm_connector *connector)
@@ -198,7 +207,7 @@
 static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
 	.get_modes = intel_hdmi_get_modes,
 	.mode_valid = intel_hdmi_mode_valid,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
@@ -224,6 +233,9 @@
 	}
 
 	intel_encoder = &intel_hdmi->base;
+	drm_encoder_init(dev, &intel_encoder->base, &intel_hdmi_enc_funcs,
+			 DRM_MODE_ENCODER_TMDS);
+
 	connector = &intel_connector->base;
 	drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
 			   DRM_MODE_CONNECTOR_HDMIA);
@@ -239,39 +251,31 @@
 	/* Set up the DDC bus. */
 	if (sdvox_reg == SDVOB) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
 		dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
 	} else if (sdvox_reg == SDVOC) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
 		dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
 	} else if (sdvox_reg == HDMIB) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
-								"HDMIB");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
 		dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
 	} else if (sdvox_reg == HDMIC) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
-								"HDMIC");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
 		dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
 	} else if (sdvox_reg == HDMID) {
 		intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
-		intel_encoder->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
-								"HDMID");
+		intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
 		dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
 	}
-	if (!intel_encoder->ddc_bus)
-		goto err_connector;
 
 	intel_hdmi->sdvox_reg = sdvox_reg;
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_hdmi_enc_funcs,
-			 DRM_MODE_ENCODER_TMDS);
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_hdmi_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base,
-					  &intel_encoder->enc);
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	drm_sysfs_connector_add(connector);
 
 	/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
@@ -282,13 +286,4 @@
 		u32 temp = I915_READ(PEG_BAND_GAP_DATA);
 		I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
 	}
-
-	return;
-
-err_connector:
-	drm_connector_cleanup(connector);
-	kfree(intel_hdmi);
-	kfree(intel_connector);
-
-	return;
 }
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index c2649c7..2449a74 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
- * Copyright © 2006-2008 Intel Corporation
+ * Copyright © 2006-2008,2010 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -24,10 +24,9 @@
  *
  * Authors:
  *	Eric Anholt <eric@anholt.net>
+ *	Chris Wilson <chris@chris-wilson.co.uk>
  */
 #include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/i2c-id.h>
 #include <linux/i2c-algo-bit.h>
 #include "drmP.h"
 #include "drm.h"
@@ -35,79 +34,106 @@
 #include "i915_drm.h"
 #include "i915_drv.h"
 
-void intel_i2c_quirk_set(struct drm_device *dev, bool enable)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	/* When using bit bashing for I2C, this bit needs to be set to 1 */
-	if (!IS_PINEVIEW(dev))
-		return;
-	if (enable)
-		I915_WRITE(DSPCLK_GATE_D,
-			I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE);
-	else
-		I915_WRITE(DSPCLK_GATE_D,
-			I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE));
-}
-
-/*
- * Intel GPIO access functions
- */
+/* Intel GPIO access functions */
 
 #define I2C_RISEFALL_TIME 20
 
-static int get_clock(void *data)
+static inline struct intel_gmbus *
+to_intel_gmbus(struct i2c_adapter *i2c)
 {
-	struct intel_i2c_chan *chan = data;
-	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+	return container_of(i2c, struct intel_gmbus, adapter);
+}
+
+struct intel_gpio {
+	struct i2c_adapter adapter;
+	struct i2c_algo_bit_data algo;
+	struct drm_i915_private *dev_priv;
+	u32 reg;
+};
+
+void
+intel_i2c_reset(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	if (HAS_PCH_SPLIT(dev))
+		I915_WRITE(PCH_GMBUS0, 0);
+	else
+		I915_WRITE(GMBUS0, 0);
+}
+
+static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
+{
 	u32 val;
 
-	val = I915_READ(chan->reg);
-	return ((val & GPIO_CLOCK_VAL_IN) != 0);
+	/* When using bit bashing for I2C, this bit needs to be set to 1 */
+	if (!IS_PINEVIEW(dev_priv->dev))
+		return;
+
+	val = I915_READ(DSPCLK_GATE_D);
+	if (enable)
+		val |= DPCUNIT_CLOCK_GATE_DISABLE;
+	else
+		val &= ~DPCUNIT_CLOCK_GATE_DISABLE;
+	I915_WRITE(DSPCLK_GATE_D, val);
+}
+
+static u32 get_reserved(struct intel_gpio *gpio)
+{
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	struct drm_device *dev = dev_priv->dev;
+	u32 reserved = 0;
+
+	/* On most chips, these bits must be preserved in software. */
+	if (!IS_I830(dev) && !IS_845G(dev))
+		reserved = I915_READ(gpio->reg) & (GPIO_DATA_PULLUP_DISABLE |
+						   GPIO_CLOCK_PULLUP_DISABLE);
+
+	return reserved;
+}
+
+static int get_clock(void *data)
+{
+	struct intel_gpio *gpio = data;
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	u32 reserved = get_reserved(gpio);
+	I915_WRITE(gpio->reg, reserved | GPIO_CLOCK_DIR_MASK);
+	I915_WRITE(gpio->reg, reserved);
+	return (I915_READ(gpio->reg) & GPIO_CLOCK_VAL_IN) != 0;
 }
 
 static int get_data(void *data)
 {
-	struct intel_i2c_chan *chan = data;
-	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-	u32 val;
-
-	val = I915_READ(chan->reg);
-	return ((val & GPIO_DATA_VAL_IN) != 0);
+	struct intel_gpio *gpio = data;
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	u32 reserved = get_reserved(gpio);
+	I915_WRITE(gpio->reg, reserved | GPIO_DATA_DIR_MASK);
+	I915_WRITE(gpio->reg, reserved);
+	return (I915_READ(gpio->reg) & GPIO_DATA_VAL_IN) != 0;
 }
 
 static void set_clock(void *data, int state_high)
 {
-	struct intel_i2c_chan *chan = data;
-	struct drm_device *dev = chan->drm_dev;
-	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-	u32 reserved = 0, clock_bits;
-
-	/* On most chips, these bits must be preserved in software. */
-	if (!IS_I830(dev) && !IS_845G(dev))
-		reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
-						   GPIO_CLOCK_PULLUP_DISABLE);
+	struct intel_gpio *gpio = data;
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	u32 reserved = get_reserved(gpio);
+	u32 clock_bits;
 
 	if (state_high)
 		clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
 	else
 		clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
 			GPIO_CLOCK_VAL_MASK;
-	I915_WRITE(chan->reg, reserved | clock_bits);
-	udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+
+	I915_WRITE(gpio->reg, reserved | clock_bits);
+	POSTING_READ(gpio->reg);
 }
 
 static void set_data(void *data, int state_high)
 {
-	struct intel_i2c_chan *chan = data;
-	struct drm_device *dev = chan->drm_dev;
-	struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
-	u32 reserved = 0, data_bits;
-
-	/* On most chips, these bits must be preserved in software. */
-	if (!IS_I830(dev) && !IS_845G(dev))
-		reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
-						   GPIO_CLOCK_PULLUP_DISABLE);
+	struct intel_gpio *gpio = data;
+	struct drm_i915_private *dev_priv = gpio->dev_priv;
+	u32 reserved = get_reserved(gpio);
+	u32 data_bits;
 
 	if (state_high)
 		data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
@@ -115,109 +141,312 @@
 		data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
 			GPIO_DATA_VAL_MASK;
 
-	I915_WRITE(chan->reg, reserved | data_bits);
-	udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+	I915_WRITE(gpio->reg, reserved | data_bits);
+	POSTING_READ(gpio->reg);
 }
 
-/* Clears the GMBUS setup.  Our driver doesn't make use of the GMBUS I2C
- * engine, but if the BIOS leaves it enabled, then that can break our use
- * of the bit-banging I2C interfaces.  This is notably the case with the
- * Mac Mini in EFI mode.
- */
-void
-intel_i2c_reset_gmbus(struct drm_device *dev)
+static struct i2c_adapter *
+intel_gpio_create(struct drm_i915_private *dev_priv, u32 pin)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
+	static const int map_pin_to_reg[] = {
+		0,
+		GPIOB,
+		GPIOA,
+		GPIOC,
+		GPIOD,
+		GPIOE,
+		GPIOF,
+	};
+	struct intel_gpio *gpio;
 
-	if (HAS_PCH_SPLIT(dev)) {
-		I915_WRITE(PCH_GMBUS0, 0);
-	} else {
-		I915_WRITE(GMBUS0, 0);
-	}
-}
+	if (pin < 1 || pin > 7)
+		return NULL;
 
-/**
- * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg
- * @dev: DRM device
- * @output: driver specific output device
- * @reg: GPIO reg to use
- * @name: name for this bus
- * @slave_addr: slave address (if fixed)
- *
- * Creates and registers a new i2c bus with the Linux i2c layer, for use
- * in output probing and control (e.g. DDC or SDVO control functions).
- *
- * Possible values for @reg include:
- *   %GPIOA
- *   %GPIOB
- *   %GPIOC
- *   %GPIOD
- *   %GPIOE
- *   %GPIOF
- *   %GPIOG
- *   %GPIOH
- * see PRM for details on how these different busses are used.
- */
-struct i2c_adapter *intel_i2c_create(struct drm_device *dev, const u32 reg,
-				     const char *name)
-{
-	struct intel_i2c_chan *chan;
+	gpio = kzalloc(sizeof(struct intel_gpio), GFP_KERNEL);
+	if (gpio == NULL)
+		return NULL;
 
-	chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL);
-	if (!chan)
+	gpio->reg = map_pin_to_reg[pin];
+	if (HAS_PCH_SPLIT(dev_priv->dev))
+		gpio->reg += PCH_GPIOA - GPIOA;
+	gpio->dev_priv = dev_priv;
+
+	snprintf(gpio->adapter.name, I2C_NAME_SIZE, "GPIO%c", "?BACDEF?"[pin]);
+	gpio->adapter.owner = THIS_MODULE;
+	gpio->adapter.algo_data	= &gpio->algo;
+	gpio->adapter.dev.parent = &dev_priv->dev->pdev->dev;
+	gpio->algo.setsda = set_data;
+	gpio->algo.setscl = set_clock;
+	gpio->algo.getsda = get_data;
+	gpio->algo.getscl = get_clock;
+	gpio->algo.udelay = I2C_RISEFALL_TIME;
+	gpio->algo.timeout = usecs_to_jiffies(2200);
+	gpio->algo.data = gpio;
+
+	if (i2c_bit_add_bus(&gpio->adapter))
 		goto out_free;
 
-	chan->drm_dev = dev;
-	chan->reg = reg;
-	snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name);
-	chan->adapter.owner = THIS_MODULE;
-	chan->adapter.algo_data	= &chan->algo;
-	chan->adapter.dev.parent = &dev->pdev->dev;
-	chan->algo.setsda = set_data;
-	chan->algo.setscl = set_clock;
-	chan->algo.getsda = get_data;
-	chan->algo.getscl = get_clock;
-	chan->algo.udelay = 20;
-	chan->algo.timeout = usecs_to_jiffies(2200);
-	chan->algo.data = chan;
-
-	i2c_set_adapdata(&chan->adapter, chan);
-
-	if(i2c_bit_add_bus(&chan->adapter))
-		goto out_free;
-
-	intel_i2c_reset_gmbus(dev);
-
-	/* JJJ:  raise SCL and SDA? */
-	intel_i2c_quirk_set(dev, true);
-	set_data(chan, 1);
-	set_clock(chan, 1);
-	intel_i2c_quirk_set(dev, false);
-	udelay(20);
-
-	return &chan->adapter;
+	return &gpio->adapter;
 
 out_free:
-	kfree(chan);
+	kfree(gpio);
 	return NULL;
 }
 
-/**
- * intel_i2c_destroy - unregister and free i2c bus resources
- * @output: channel to free
- *
- * Unregister the adapter from the i2c layer, then free the structure.
- */
-void intel_i2c_destroy(struct i2c_adapter *adapter)
+static int
+intel_i2c_quirk_xfer(struct drm_i915_private *dev_priv,
+		     struct i2c_adapter *adapter,
+		     struct i2c_msg *msgs,
+		     int num)
 {
-	struct intel_i2c_chan *chan;
+	struct intel_gpio *gpio = container_of(adapter,
+					       struct intel_gpio,
+					       adapter);
+	int ret;
 
-	if (!adapter)
+	intel_i2c_reset(dev_priv->dev);
+
+	intel_i2c_quirk_set(dev_priv, true);
+	set_data(gpio, 1);
+	set_clock(gpio, 1);
+	udelay(I2C_RISEFALL_TIME);
+
+	ret = adapter->algo->master_xfer(adapter, msgs, num);
+
+	set_data(gpio, 1);
+	set_clock(gpio, 1);
+	intel_i2c_quirk_set(dev_priv, false);
+
+	return ret;
+}
+
+static int
+gmbus_xfer(struct i2c_adapter *adapter,
+	   struct i2c_msg *msgs,
+	   int num)
+{
+	struct intel_gmbus *bus = container_of(adapter,
+					       struct intel_gmbus,
+					       adapter);
+	struct drm_i915_private *dev_priv = adapter->algo_data;
+	int i, reg_offset;
+
+	if (bus->force_bit)
+		return intel_i2c_quirk_xfer(dev_priv,
+					    bus->force_bit, msgs, num);
+
+	reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
+
+	I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
+
+	for (i = 0; i < num; i++) {
+		u16 len = msgs[i].len;
+		u8 *buf = msgs[i].buf;
+
+		if (msgs[i].flags & I2C_M_RD) {
+			I915_WRITE(GMBUS1 + reg_offset,
+				   GMBUS_CYCLE_WAIT | (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
+				   (len << GMBUS_BYTE_COUNT_SHIFT) |
+				   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+				   GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+			POSTING_READ(GMBUS2+reg_offset);
+			do {
+				u32 val, loop = 0;
+
+				if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+					goto timeout;
+				if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+					return 0;
+
+				val = I915_READ(GMBUS3 + reg_offset);
+				do {
+					*buf++ = val & 0xff;
+					val >>= 8;
+				} while (--len && ++loop < 4);
+			} while (len);
+		} else {
+			u32 val, loop;
+
+			val = loop = 0;
+			do {
+				val |= *buf++ << (8 * loop);
+			} while (--len && ++loop < 4);
+
+			I915_WRITE(GMBUS3 + reg_offset, val);
+			I915_WRITE(GMBUS1 + reg_offset,
+				   (i + 1 == num ? GMBUS_CYCLE_STOP : GMBUS_CYCLE_WAIT) |
+				   (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
+				   (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
+				   GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+			POSTING_READ(GMBUS2+reg_offset);
+
+			while (len) {
+				if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
+					goto timeout;
+				if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+					return 0;
+
+				val = loop = 0;
+				do {
+					val |= *buf++ << (8 * loop);
+				} while (--len && ++loop < 4);
+
+				I915_WRITE(GMBUS3 + reg_offset, val);
+				POSTING_READ(GMBUS2+reg_offset);
+			}
+		}
+
+		if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+			goto timeout;
+		if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+			return 0;
+	}
+
+	return num;
+
+timeout:
+	DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
+		 bus->reg0 & 0xff, bus->adapter.name);
+	/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
+	bus->force_bit = intel_gpio_create(dev_priv, bus->reg0 & 0xff);
+	if (!bus->force_bit)
+		return -ENOMEM;
+
+	return intel_i2c_quirk_xfer(dev_priv, bus->force_bit, msgs, num);
+}
+
+static u32 gmbus_func(struct i2c_adapter *adapter)
+{
+	struct intel_gmbus *bus = container_of(adapter,
+					       struct intel_gmbus,
+					       adapter);
+
+	if (bus->force_bit)
+		bus->force_bit->algo->functionality(bus->force_bit);
+
+	return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+		/* I2C_FUNC_10BIT_ADDR | */
+		I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+		I2C_FUNC_SMBUS_BLOCK_PROC_CALL);
+}
+
+static const struct i2c_algorithm gmbus_algorithm = {
+	.master_xfer	= gmbus_xfer,
+	.functionality	= gmbus_func
+};
+
+/**
+ * intel_gmbus_setup - instantiate all Intel i2c GMBuses
+ * @dev: DRM device
+ */
+int intel_setup_gmbus(struct drm_device *dev)
+{
+	static const char *names[GMBUS_NUM_PORTS] = {
+		"disabled",
+		"ssc",
+		"vga",
+		"panel",
+		"dpc",
+		"dpb",
+		"reserved"
+		"dpd",
+	};
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret, i;
+
+	dev_priv->gmbus = kcalloc(sizeof(struct intel_gmbus), GMBUS_NUM_PORTS,
+				  GFP_KERNEL);
+	if (dev_priv->gmbus == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+		struct intel_gmbus *bus = &dev_priv->gmbus[i];
+
+		bus->adapter.owner = THIS_MODULE;
+		bus->adapter.class = I2C_CLASS_DDC;
+		snprintf(bus->adapter.name,
+			 I2C_NAME_SIZE,
+			 "gmbus %s",
+			 names[i]);
+
+		bus->adapter.dev.parent = &dev->pdev->dev;
+		bus->adapter.algo_data	= dev_priv;
+
+		bus->adapter.algo = &gmbus_algorithm;
+		ret = i2c_add_adapter(&bus->adapter);
+		if (ret)
+			goto err;
+
+		/* By default use a conservative clock rate */
+		bus->reg0 = i | GMBUS_RATE_100KHZ;
+
+		/* XXX force bit banging until GMBUS is fully debugged */
+		bus->force_bit = intel_gpio_create(dev_priv, i);
+	}
+
+	intel_i2c_reset(dev_priv->dev);
+
+	return 0;
+
+err:
+	while (--i) {
+		struct intel_gmbus *bus = &dev_priv->gmbus[i];
+		i2c_del_adapter(&bus->adapter);
+	}
+	kfree(dev_priv->gmbus);
+	dev_priv->gmbus = NULL;
+	return ret;
+}
+
+void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
+{
+	struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+	/* speed:
+	 * 0x0 = 100 KHz
+	 * 0x1 = 50 KHz
+	 * 0x2 = 400 KHz
+	 * 0x3 = 1000 Khz
+	 */
+	bus->reg0 = (bus->reg0 & ~(0x3 << 8)) | (speed << 8);
+}
+
+void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
+{
+	struct intel_gmbus *bus = to_intel_gmbus(adapter);
+
+	if (force_bit) {
+		if (bus->force_bit == NULL) {
+			struct drm_i915_private *dev_priv = adapter->algo_data;
+			bus->force_bit = intel_gpio_create(dev_priv,
+							   bus->reg0 & 0xff);
+		}
+	} else {
+		if (bus->force_bit) {
+			i2c_del_adapter(bus->force_bit);
+			kfree(bus->force_bit);
+			bus->force_bit = NULL;
+		}
+	}
+}
+
+void intel_teardown_gmbus(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int i;
+
+	if (dev_priv->gmbus == NULL)
 		return;
 
-	chan = container_of(adapter,
-			    struct intel_i2c_chan,
-			    adapter);
-	i2c_del_adapter(&chan->adapter);
-	kfree(chan);
+	for (i = 0; i < GMBUS_NUM_PORTS; i++) {
+		struct intel_gmbus *bus = &dev_priv->gmbus[i];
+		if (bus->force_bit) {
+			i2c_del_adapter(bus->force_bit);
+			kfree(bus->force_bit);
+		}
+		i2c_del_adapter(&bus->adapter);
+	}
+
+	kfree(dev_priv->gmbus);
+	dev_priv->gmbus = NULL;
 }
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 6ec39a8..f1a6499 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -43,102 +43,76 @@
 /* Private structure for the integrated LVDS support */
 struct intel_lvds {
 	struct intel_encoder base;
+
+	struct edid *edid;
+
 	int fitting_mode;
 	u32 pfit_control;
 	u32 pfit_pgm_ratios;
+	bool pfit_dirty;
+
+	struct drm_display_mode *fixed_mode;
 };
 
-static struct intel_lvds *enc_to_intel_lvds(struct drm_encoder *encoder)
+static struct intel_lvds *to_intel_lvds(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_lvds, base);
+	return container_of(encoder, struct intel_lvds, base.base);
 }
 
-/**
- * Sets the backlight level.
- *
- * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
- */
-static void intel_lvds_set_backlight(struct drm_device *dev, int level)
+static struct intel_lvds *intel_attached_lvds(struct drm_connector *connector)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 blc_pwm_ctl, reg;
-
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_CPU_CTL;
-	else
-		reg = BLC_PWM_CTL;
-
-	blc_pwm_ctl = I915_READ(reg) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-	I915_WRITE(reg, (blc_pwm_ctl |
-				 (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
-}
-
-/**
- * Returns the maximum level of the backlight duty cycle field.
- */
-static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg;
-
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_PCH_CTL2;
-	else
-		reg = BLC_PWM_CTL;
-
-	return ((I915_READ(reg) & BACKLIGHT_MODULATION_FREQ_MASK) >>
-		BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_lvds, base);
 }
 
 /**
  * Sets the power state for the panel.
  */
-static void intel_lvds_set_power(struct drm_device *dev, bool on)
+static void intel_lvds_set_power(struct intel_lvds *intel_lvds, bool on)
 {
+	struct drm_device *dev = intel_lvds->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 ctl_reg, status_reg, lvds_reg;
+	u32 ctl_reg, lvds_reg;
 
 	if (HAS_PCH_SPLIT(dev)) {
 		ctl_reg = PCH_PP_CONTROL;
-		status_reg = PCH_PP_STATUS;
 		lvds_reg = PCH_LVDS;
 	} else {
 		ctl_reg = PP_CONTROL;
-		status_reg = PP_STATUS;
 		lvds_reg = LVDS;
 	}
 
 	if (on) {
 		I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN);
-		POSTING_READ(lvds_reg);
-
-		I915_WRITE(ctl_reg, I915_READ(ctl_reg) |
-			   POWER_TARGET_ON);
-		if (wait_for(I915_READ(status_reg) & PP_ON, 1000, 0))
-			DRM_ERROR("timed out waiting to enable LVDS pipe");
-
-		intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
+		I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);
+		intel_panel_set_backlight(dev, dev_priv->backlight_level);
 	} else {
-		intel_lvds_set_backlight(dev, 0);
+		dev_priv->backlight_level = intel_panel_get_backlight(dev);
 
-		I915_WRITE(ctl_reg, I915_READ(ctl_reg) &
-			   ~POWER_TARGET_ON);
-		if (wait_for((I915_READ(status_reg) & PP_ON) == 0, 1000, 0))
-			DRM_ERROR("timed out waiting for LVDS pipe to turn off");
+		intel_panel_set_backlight(dev, 0);
+		I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON);
+
+		if (intel_lvds->pfit_control) {
+			if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+				DRM_ERROR("timed out waiting for panel to power off\n");
+			I915_WRITE(PFIT_CONTROL, 0);
+			intel_lvds->pfit_control = 0;
+			intel_lvds->pfit_dirty = false;
+		}
 
 		I915_WRITE(lvds_reg, I915_READ(lvds_reg) & ~LVDS_PORT_EN);
-		POSTING_READ(lvds_reg);
 	}
+	POSTING_READ(lvds_reg);
 }
 
 static void intel_lvds_dpms(struct drm_encoder *encoder, int mode)
 {
-	struct drm_device *dev = encoder->dev;
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
 	if (mode == DRM_MODE_DPMS_ON)
-		intel_lvds_set_power(dev, true);
+		intel_lvds_set_power(intel_lvds, true);
 	else
-		intel_lvds_set_power(dev, false);
+		intel_lvds_set_power(intel_lvds, false);
 
 	/* XXX: We never power down the LVDS pairs. */
 }
@@ -146,16 +120,13 @@
 static int intel_lvds_mode_valid(struct drm_connector *connector,
 				 struct drm_display_mode *mode)
 {
-	struct drm_device *dev = connector->dev;
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
+	struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
+	struct drm_display_mode *fixed_mode = intel_lvds->fixed_mode;
 
-	if (fixed_mode)	{
-		if (mode->hdisplay > fixed_mode->hdisplay)
-			return MODE_PANEL;
-		if (mode->vdisplay > fixed_mode->vdisplay)
-			return MODE_PANEL;
-	}
+	if (mode->hdisplay > fixed_mode->hdisplay)
+		return MODE_PANEL;
+	if (mode->vdisplay > fixed_mode->vdisplay)
+		return MODE_PANEL;
 
 	return MODE_OK;
 }
@@ -223,12 +194,12 @@
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
-	struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 	struct drm_encoder *tmp_encoder;
 	u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
 
 	/* Should never happen!! */
-	if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
+	if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) {
 		DRM_ERROR("Can't support LVDS on pipe A\n");
 		return false;
 	}
@@ -241,9 +212,6 @@
 			return false;
 		}
 	}
-	/* If we don't have a panel mode, there is nothing we can do */
-	if (dev_priv->panel_fixed_mode == NULL)
-		return true;
 
 	/*
 	 * We have timings from the BIOS for the panel, put them in
@@ -251,7 +219,7 @@
 	 * with the panel scaling set up to source from the H/VDisplay
 	 * of the original mode.
 	 */
-	intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
+	intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
 
 	if (HAS_PCH_SPLIT(dev)) {
 		intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
@@ -260,8 +228,8 @@
 	}
 
 	/* Make sure pre-965s set dither correctly */
-	if (!IS_I965G(dev)) {
-		if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
+	if (INTEL_INFO(dev)->gen < 4) {
+		if (dev_priv->lvds_dither)
 			pfit_control |= PANEL_8TO6_DITHER_ENABLE;
 	}
 
@@ -271,7 +239,7 @@
 		goto out;
 
 	/* 965+ wants fuzzy fitting */
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
 				 PFIT_FILTER_FUZZY);
 
@@ -297,7 +265,7 @@
 
 	case DRM_MODE_SCALE_ASPECT:
 		/* Scale but preserve the aspect ratio */
-		if (IS_I965G(dev)) {
+		if (INTEL_INFO(dev)->gen >= 4) {
 			u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
 			u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
 
@@ -356,7 +324,7 @@
 		 * Fortunately this is all done for us in hw.
 		 */
 		pfit_control |= PFIT_ENABLE;
-		if (IS_I965G(dev))
+		if (INTEL_INFO(dev)->gen >= 4)
 			pfit_control |= PFIT_SCALING_AUTO;
 		else
 			pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
@@ -369,8 +337,12 @@
 	}
 
 out:
-	intel_lvds->pfit_control = pfit_control;
-	intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+	if (pfit_control != intel_lvds->pfit_control ||
+	    pfit_pgm_ratios != intel_lvds->pfit_pgm_ratios) {
+		intel_lvds->pfit_control = pfit_control;
+		intel_lvds->pfit_pgm_ratios = pfit_pgm_ratios;
+		intel_lvds->pfit_dirty = true;
+	}
 	dev_priv->lvds_border_bits = border;
 
 	/*
@@ -386,30 +358,60 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	u32 reg;
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-	if (HAS_PCH_SPLIT(dev))
-		reg = BLC_PWM_CPU_CTL;
-	else
-		reg = BLC_PWM_CTL;
+	dev_priv->backlight_level = intel_panel_get_backlight(dev);
 
-	dev_priv->saveBLC_PWM_CTL = I915_READ(reg);
-	dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
-				       BACKLIGHT_DUTY_CYCLE_MASK);
+	/* We try to do the minimum that is necessary in order to unlock
+	 * the registers for mode setting.
+	 *
+	 * On Ironlake, this is quite simple as we just set the unlock key
+	 * and ignore all subtleties. (This may cause some issues...)
+	 *
+	 * Prior to Ironlake, we must disable the pipe if we want to adjust
+	 * the panel fitter. However at all other times we can just reset
+	 * the registers regardless.
+	 */
 
-	intel_lvds_set_power(dev, false);
+	if (HAS_PCH_SPLIT(dev)) {
+		I915_WRITE(PCH_PP_CONTROL,
+			   I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+	} else if (intel_lvds->pfit_dirty) {
+		I915_WRITE(PP_CONTROL,
+			   (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS)
+			   & ~POWER_TARGET_ON);
+	} else {
+		I915_WRITE(PP_CONTROL,
+			   I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+	}
 }
 
-static void intel_lvds_commit( struct drm_encoder *encoder)
+static void intel_lvds_commit(struct drm_encoder *encoder)
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
-	if (dev_priv->backlight_duty_cycle == 0)
-		dev_priv->backlight_duty_cycle =
-			intel_lvds_get_max_backlight(dev);
+	if (dev_priv->backlight_level == 0)
+		dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
 
-	intel_lvds_set_power(dev, true);
+	/* Undo any unlocking done in prepare to prevent accidental
+	 * adjustment of the registers.
+	 */
+	if (HAS_PCH_SPLIT(dev)) {
+		u32 val = I915_READ(PCH_PP_CONTROL);
+		if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+			I915_WRITE(PCH_PP_CONTROL, val & 0x3);
+	} else {
+		u32 val = I915_READ(PP_CONTROL);
+		if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS)
+			I915_WRITE(PP_CONTROL, val & 0x3);
+	}
+
+	/* Always do a full power on as we do not know what state
+	 * we were left in.
+	 */
+	intel_lvds_set_power(intel_lvds, true);
 }
 
 static void intel_lvds_mode_set(struct drm_encoder *encoder,
@@ -418,7 +420,7 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+	struct intel_lvds *intel_lvds = to_intel_lvds(encoder);
 
 	/*
 	 * The LVDS pin pair will already have been turned on in the
@@ -429,13 +431,23 @@
 	if (HAS_PCH_SPLIT(dev))
 		return;
 
+	if (!intel_lvds->pfit_dirty)
+		return;
+
 	/*
 	 * Enable automatic panel scaling so that non-native modes fill the
 	 * screen.  Should be enabled before the pipe is enabled, according to
 	 * register description and PRM.
 	 */
+	DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
+		      intel_lvds->pfit_control,
+		      intel_lvds->pfit_pgm_ratios);
+	if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000))
+		DRM_ERROR("timed out waiting for panel to power off\n");
+
 	I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios);
 	I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control);
+	intel_lvds->pfit_dirty = false;
 }
 
 /**
@@ -465,38 +477,22 @@
  */
 static int intel_lvds_get_modes(struct drm_connector *connector)
 {
+	struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
 	struct drm_device *dev = connector->dev;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder);
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	int ret = 0;
+	struct drm_display_mode *mode;
 
-	if (dev_priv->lvds_edid_good) {
-		ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus);
-
-		if (ret)
-			return ret;
+	if (intel_lvds->edid) {
+		drm_mode_connector_update_edid_property(connector,
+							intel_lvds->edid);
+		return drm_add_edid_modes(connector, intel_lvds->edid);
 	}
 
-	/* Didn't get an EDID, so
-	 * Set wide sync ranges so we get all modes
-	 * handed to valid_mode for checking
-	 */
-	connector->display_info.min_vfreq = 0;
-	connector->display_info.max_vfreq = 200;
-	connector->display_info.min_hfreq = 0;
-	connector->display_info.max_hfreq = 200;
+	mode = drm_mode_duplicate(dev, intel_lvds->fixed_mode);
+	if (mode == 0)
+		return 0;
 
-	if (dev_priv->panel_fixed_mode != NULL) {
-		struct drm_display_mode *mode;
-
-		mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
-		drm_mode_probed_add(connector, mode);
-
-		return 1;
-	}
-
-	return 0;
+	drm_mode_probed_add(connector, mode);
+	return 1;
 }
 
 static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id)
@@ -587,18 +583,17 @@
 				   struct drm_property *property,
 				   uint64_t value)
 {
+	struct intel_lvds *intel_lvds = intel_attached_lvds(connector);
 	struct drm_device *dev = connector->dev;
 
-	if (property == dev->mode_config.scaling_mode_property &&
-				connector->encoder) {
-		struct drm_crtc *crtc = connector->encoder->crtc;
-		struct drm_encoder *encoder = connector->encoder;
-		struct intel_lvds *intel_lvds = enc_to_intel_lvds(encoder);
+	if (property == dev->mode_config.scaling_mode_property) {
+		struct drm_crtc *crtc = intel_lvds->base.base.crtc;
 
 		if (value == DRM_MODE_SCALE_NONE) {
 			DRM_DEBUG_KMS("no scaling not supported\n");
-			return 0;
+			return -EINVAL;
 		}
+
 		if (intel_lvds->fitting_mode == value) {
 			/* the LVDS scaling property is not changed */
 			return 0;
@@ -628,7 +623,7 @@
 static const struct drm_connector_helper_funcs intel_lvds_connector_helper_funcs = {
 	.get_modes = intel_lvds_get_modes,
 	.mode_valid = intel_lvds_mode_valid,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_connector_funcs intel_lvds_connector_funcs = {
@@ -726,16 +721,14 @@
  * Find the reduced downclock for LVDS in EDID.
  */
 static void intel_find_lvds_downclock(struct drm_device *dev,
-				struct drm_connector *connector)
+				      struct drm_display_mode *fixed_mode,
+				      struct drm_connector *connector)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct drm_display_mode *scan, *panel_fixed_mode;
+	struct drm_display_mode *scan;
 	int temp_downclock;
 
-	panel_fixed_mode = dev_priv->panel_fixed_mode;
-	temp_downclock = panel_fixed_mode->clock;
-
-	mutex_lock(&dev->mode_config.mutex);
+	temp_downclock = fixed_mode->clock;
 	list_for_each_entry(scan, &connector->probed_modes, head) {
 		/*
 		 * If one mode has the same resolution with the fixed_panel
@@ -744,14 +737,14 @@
 		 * case we can set the different FPx0/1 to dynamically select
 		 * between low and high frequency.
 		 */
-		if (scan->hdisplay == panel_fixed_mode->hdisplay &&
-			scan->hsync_start == panel_fixed_mode->hsync_start &&
-			scan->hsync_end == panel_fixed_mode->hsync_end &&
-			scan->htotal == panel_fixed_mode->htotal &&
-			scan->vdisplay == panel_fixed_mode->vdisplay &&
-			scan->vsync_start == panel_fixed_mode->vsync_start &&
-			scan->vsync_end == panel_fixed_mode->vsync_end &&
-			scan->vtotal == panel_fixed_mode->vtotal) {
+		if (scan->hdisplay == fixed_mode->hdisplay &&
+		    scan->hsync_start == fixed_mode->hsync_start &&
+		    scan->hsync_end == fixed_mode->hsync_end &&
+		    scan->htotal == fixed_mode->htotal &&
+		    scan->vdisplay == fixed_mode->vdisplay &&
+		    scan->vsync_start == fixed_mode->vsync_start &&
+		    scan->vsync_end == fixed_mode->vsync_end &&
+		    scan->vtotal == fixed_mode->vtotal) {
 			if (scan->clock < temp_downclock) {
 				/*
 				 * The downclock is already found. But we
@@ -761,17 +754,14 @@
 			}
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
-	if (temp_downclock < panel_fixed_mode->clock &&
-	    i915_lvds_downclock) {
+	if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) {
 		/* We found the downclock for LVDS. */
 		dev_priv->lvds_downclock_avail = 1;
 		dev_priv->lvds_downclock = temp_downclock;
 		DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
-				"Normal clock %dKhz, downclock %dKhz\n",
-				panel_fixed_mode->clock, temp_downclock);
+			      "Normal clock %dKhz, downclock %dKhz\n",
+			      fixed_mode->clock, temp_downclock);
 	}
-	return;
 }
 
 /*
@@ -780,38 +770,67 @@
  * If it is present, return 1.
  * If it is not present, return false.
  * If no child dev is parsed from VBT, it assumes that the LVDS is present.
- * Note: The addin_offset should also be checked for LVDS panel.
- * Only when it is non-zero, it is assumed that it is present.
  */
-static int lvds_is_present_in_vbt(struct drm_device *dev)
+static bool lvds_is_present_in_vbt(struct drm_device *dev,
+				   u8 *i2c_pin)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct child_device_config *p_child;
-	int i, ret;
+	int i;
 
 	if (!dev_priv->child_dev_num)
-		return 1;
+		return true;
 
-	ret = 0;
 	for (i = 0; i < dev_priv->child_dev_num; i++) {
-		p_child = dev_priv->child_dev + i;
-		/*
-		 * If the device type is not LFP, continue.
-		 * If the device type is 0x22, it is also regarded as LFP.
+		struct child_device_config *child = dev_priv->child_dev + i;
+
+		/* If the device type is not LFP, continue.
+		 * We have to check both the new identifiers as well as the
+		 * old for compatibility with some BIOSes.
 		 */
-		if (p_child->device_type != DEVICE_TYPE_INT_LFP &&
-			p_child->device_type != DEVICE_TYPE_LFP)
+		if (child->device_type != DEVICE_TYPE_INT_LFP &&
+		    child->device_type != DEVICE_TYPE_LFP)
 			continue;
 
-		/* The addin_offset should be checked. Only when it is
-		 * non-zero, it is regarded as present.
+		if (child->i2c_pin)
+		    *i2c_pin = child->i2c_pin;
+
+		/* However, we cannot trust the BIOS writers to populate
+		 * the VBT correctly.  Since LVDS requires additional
+		 * information from AIM blocks, a non-zero addin offset is
+		 * a good indicator that the LVDS is actually present.
 		 */
-		if (p_child->addin_offset) {
-			ret = 1;
-			break;
-		}
+		if (child->addin_offset)
+			return true;
+
+		/* But even then some BIOS writers perform some black magic
+		 * and instantiate the device without reference to any
+		 * additional data.  Trust that if the VBT was written into
+		 * the OpRegion then they have validated the LVDS's existence.
+		 */
+		if (dev_priv->opregion.vbt)
+			return true;
 	}
-	return ret;
+
+	return false;
+}
+
+static bool intel_lvds_ddc_probe(struct drm_device *dev, u8 pin)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u8 buf = 0;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = 0xA0,
+			.flags = 0,
+			.len = 1,
+			.buf = &buf,
+		},
+	};
+	struct i2c_adapter *i2c = &dev_priv->gmbus[pin].adapter;
+	/* XXX this only appears to work when using GMBUS */
+	if (intel_gmbus_is_forced_bit(i2c))
+		return true;
+	return i2c_transfer(i2c, msgs, 1) == 1;
 }
 
 /**
@@ -832,13 +851,15 @@
 	struct drm_display_mode *scan; /* *modes, *bios_mode; */
 	struct drm_crtc *crtc;
 	u32 lvds;
-	int pipe, gpio = GPIOC;
+	int pipe;
+	u8 pin;
 
 	/* Skip init on machines we know falsely report LVDS */
 	if (dmi_check_system(intel_no_lvds))
 		return;
 
-	if (!lvds_is_present_in_vbt(dev)) {
+	pin = GMBUS_PORT_PANEL;
+	if (!lvds_is_present_in_vbt(dev, &pin)) {
 		DRM_DEBUG_KMS("LVDS is not present in VBT\n");
 		return;
 	}
@@ -846,11 +867,15 @@
 	if (HAS_PCH_SPLIT(dev)) {
 		if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
 			return;
-		if (dev_priv->edp_support) {
+		if (dev_priv->edp.support) {
 			DRM_DEBUG_KMS("disable LVDS for eDP support\n");
 			return;
 		}
-		gpio = PCH_GPIOC;
+	}
+
+	if (!intel_lvds_ddc_probe(dev, pin)) {
+		DRM_DEBUG_KMS("LVDS did not respond to DDC probe\n");
+		return;
 	}
 
 	intel_lvds = kzalloc(sizeof(struct intel_lvds), GFP_KERNEL);
@@ -864,16 +889,20 @@
 		return;
 	}
 
+	if (!HAS_PCH_SPLIT(dev)) {
+		intel_lvds->pfit_control = I915_READ(PFIT_CONTROL);
+	}
+
 	intel_encoder = &intel_lvds->base;
-	encoder = &intel_encoder->enc;
+	encoder = &intel_encoder->base;
 	connector = &intel_connector->base;
 	drm_connector_init(dev, &intel_connector->base, &intel_lvds_connector_funcs,
 			   DRM_MODE_CONNECTOR_LVDS);
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_lvds_enc_funcs,
+	drm_encoder_init(dev, &intel_encoder->base, &intel_lvds_enc_funcs,
 			 DRM_MODE_ENCODER_LVDS);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	intel_encoder->type = INTEL_OUTPUT_LVDS;
 
 	intel_encoder->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
@@ -904,43 +933,41 @@
 	 *    if closed, act like it's not there for now
 	 */
 
-	/* Set up the DDC bus. */
-	intel_encoder->ddc_bus = intel_i2c_create(dev, gpio, "LVDSDDC_C");
-	if (!intel_encoder->ddc_bus) {
-		dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
-			   "failed.\n");
-		goto failed;
-	}
-
 	/*
 	 * Attempt to get the fixed panel mode from DDC.  Assume that the
 	 * preferred mode is the right one.
 	 */
-	dev_priv->lvds_edid_good = true;
+	intel_lvds->edid = drm_get_edid(connector,
+					&dev_priv->gmbus[pin].adapter);
 
-	if (!intel_ddc_get_modes(connector, intel_encoder->ddc_bus))
-		dev_priv->lvds_edid_good = false;
+	if (!intel_lvds->edid) {
+		/* Didn't get an EDID, so
+		 * Set wide sync ranges so we get all modes
+		 * handed to valid_mode for checking
+		 */
+		connector->display_info.min_vfreq = 0;
+		connector->display_info.max_vfreq = 200;
+		connector->display_info.min_hfreq = 0;
+		connector->display_info.max_hfreq = 200;
+	}
 
 	list_for_each_entry(scan, &connector->probed_modes, head) {
-		mutex_lock(&dev->mode_config.mutex);
 		if (scan->type & DRM_MODE_TYPE_PREFERRED) {
-			dev_priv->panel_fixed_mode =
+			intel_lvds->fixed_mode =
 				drm_mode_duplicate(dev, scan);
-			mutex_unlock(&dev->mode_config.mutex);
-			intel_find_lvds_downclock(dev, connector);
+			intel_find_lvds_downclock(dev,
+						  intel_lvds->fixed_mode,
+						  connector);
 			goto out;
 		}
-		mutex_unlock(&dev->mode_config.mutex);
 	}
 
 	/* Failed to get EDID, what about VBT? */
 	if (dev_priv->lfp_lvds_vbt_mode) {
-		mutex_lock(&dev->mode_config.mutex);
-		dev_priv->panel_fixed_mode =
+		intel_lvds->fixed_mode =
 			drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
-		mutex_unlock(&dev->mode_config.mutex);
-		if (dev_priv->panel_fixed_mode) {
-			dev_priv->panel_fixed_mode->type |=
+		if (intel_lvds->fixed_mode) {
+			intel_lvds->fixed_mode->type |=
 				DRM_MODE_TYPE_PREFERRED;
 			goto out;
 		}
@@ -958,19 +985,19 @@
 
 	lvds = I915_READ(LVDS);
 	pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
-	crtc = intel_get_crtc_from_pipe(dev, pipe);
+	crtc = intel_get_crtc_for_pipe(dev, pipe);
 
 	if (crtc && (lvds & LVDS_PORT_EN)) {
-		dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc);
-		if (dev_priv->panel_fixed_mode) {
-			dev_priv->panel_fixed_mode->type |=
+		intel_lvds->fixed_mode = intel_crtc_mode_get(dev, crtc);
+		if (intel_lvds->fixed_mode) {
+			intel_lvds->fixed_mode->type |=
 				DRM_MODE_TYPE_PREFERRED;
 			goto out;
 		}
 	}
 
 	/* If we still don't have a mode after all that, give up. */
-	if (!dev_priv->panel_fixed_mode)
+	if (!intel_lvds->fixed_mode)
 		goto failed;
 
 out:
@@ -997,8 +1024,6 @@
 
 failed:
 	DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
-	if (intel_encoder->ddc_bus)
-		intel_i2c_destroy(intel_encoder->ddc_bus);
 	drm_connector_cleanup(connector);
 	drm_encoder_cleanup(encoder);
 	kfree(intel_lvds);
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index 4b1fd3d..f70b7cf 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (c) 2007 Intel Corporation
+ * Copyright (c) 2007, 2010 Intel Corporation
  *   Jesse Barnes <jesse.barnes@intel.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -34,11 +34,11 @@
  * intel_ddc_probe
  *
  */
-bool intel_ddc_probe(struct intel_encoder *intel_encoder)
+bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
 {
+	struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
 	u8 out_buf[] = { 0x0, 0x0};
 	u8 buf[2];
-	int ret;
 	struct i2c_msg msgs[] = {
 		{
 			.addr = 0x50,
@@ -54,13 +54,7 @@
 		}
 	};
 
-	intel_i2c_quirk_set(intel_encoder->enc.dev, true);
-	ret = i2c_transfer(intel_encoder->ddc_bus, msgs, 2);
-	intel_i2c_quirk_set(intel_encoder->enc.dev, false);
-	if (ret == 2)
-		return true;
-
-	return false;
+	return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2;
 }
 
 /**
@@ -76,9 +70,7 @@
 	struct edid *edid;
 	int ret = 0;
 
-	intel_i2c_quirk_set(connector->dev, true);
 	edid = drm_get_edid(connector, adapter);
-	intel_i2c_quirk_set(connector->dev, false);
 	if (edid) {
 		drm_mode_connector_update_edid_property(connector, edid);
 		ret = drm_add_edid_modes(connector, edid);
diff --git a/drivers/gpu/drm/i915/i915_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
similarity index 81%
rename from drivers/gpu/drm/i915/i915_opregion.c
rename to drivers/gpu/drm/i915/intel_opregion.c
index ea5d3fe..917c7dc 100644
--- a/drivers/gpu/drm/i915/i915_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -31,17 +31,16 @@
 #include "drmP.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include "intel_drv.h"
 
 #define PCI_ASLE 0xe4
-#define PCI_LBPC 0xf4
 #define PCI_ASLS 0xfc
 
-#define OPREGION_SZ            (8*1024)
 #define OPREGION_HEADER_OFFSET 0
 #define OPREGION_ACPI_OFFSET   0x100
 #define OPREGION_SWSCI_OFFSET  0x200
 #define OPREGION_ASLE_OFFSET   0x300
-#define OPREGION_VBT_OFFSET    0x1000
+#define OPREGION_VBT_OFFSET    0x400
 
 #define OPREGION_SIGNATURE "IntelGraphicsMem"
 #define MBOX_ACPI      (1<<0)
@@ -143,40 +142,22 @@
 #define ACPI_DIGITAL_OUTPUT (3<<8)
 #define ACPI_LVDS_OUTPUT (4<<8)
 
+#ifdef CONFIG_ACPI
 static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 blc_pwm_ctl, blc_pwm_ctl2;
-	u32 max_backlight, level, shift;
+	u32 max;
 
 	if (!(bclp & ASLE_BCLP_VALID))
 		return ASLE_BACKLIGHT_FAILED;
 
 	bclp &= ASLE_BCLP_MSK;
-	if (bclp < 0 || bclp > 255)
+	if (bclp > 255)
 		return ASLE_BACKLIGHT_FAILED;
 
-	blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
-	blc_pwm_ctl2 = I915_READ(BLC_PWM_CTL2);
-
-	if (IS_I965G(dev) && (blc_pwm_ctl2 & BLM_COMBINATION_MODE))
-		pci_write_config_dword(dev->pdev, PCI_LBPC, bclp);
-	else {
-		if (IS_PINEVIEW(dev)) {
-			blc_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
-			max_backlight = (blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-					BACKLIGHT_MODULATION_FREQ_SHIFT;
-			shift = BACKLIGHT_DUTY_CYCLE_SHIFT + 1;
-		} else {
-			blc_pwm_ctl &= ~BACKLIGHT_DUTY_CYCLE_MASK;
-			max_backlight = ((blc_pwm_ctl & BACKLIGHT_MODULATION_FREQ_MASK) >> 
-					BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
-			shift = BACKLIGHT_DUTY_CYCLE_SHIFT;
-		}
-		level = (bclp * max_backlight) / 255;
-		I915_WRITE(BLC_PWM_CTL, blc_pwm_ctl | (level << shift));
-	}
+	max = intel_panel_get_max_backlight(dev);
+	intel_panel_set_backlight(dev, bclp * max / 255);
 	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
 
 	return 0;
@@ -211,7 +192,7 @@
 	return 0;
 }
 
-void opregion_asle_intr(struct drm_device *dev)
+void intel_opregion_asle_intr(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -243,37 +224,8 @@
 	asle->aslc = asle_stat;
 }
 
-static u32 asle_set_backlight_ironlake(struct drm_device *dev, u32 bclp)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct opregion_asle *asle = dev_priv->opregion.asle;
-	u32 cpu_pwm_ctl, pch_pwm_ctl2;
-	u32 max_backlight, level;
-
-	if (!(bclp & ASLE_BCLP_VALID))
-		return ASLE_BACKLIGHT_FAILED;
-
-	bclp &= ASLE_BCLP_MSK;
-	if (bclp < 0 || bclp > 255)
-		return ASLE_BACKLIGHT_FAILED;
-
-	cpu_pwm_ctl = I915_READ(BLC_PWM_CPU_CTL);
-	pch_pwm_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
-	/* get the max PWM frequency */
-	max_backlight = (pch_pwm_ctl2 >> 16) & BACKLIGHT_DUTY_CYCLE_MASK;
-	/* calculate the expected PMW frequency */
-	level = (bclp * max_backlight) / 255;
-	/* reserve the high 16 bits */
-	cpu_pwm_ctl &= ~(BACKLIGHT_DUTY_CYCLE_MASK);
-	/* write the updated PWM frequency */
-	I915_WRITE(BLC_PWM_CPU_CTL, cpu_pwm_ctl | level);
-
-	asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
-
-	return 0;
-}
-
-void ironlake_opregion_gse_intr(struct drm_device *dev)
+/* Only present on Ironlake+ */
+void intel_opregion_gse_intr(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -296,7 +248,7 @@
 	}
 
 	if (asle_req & ASLE_SET_BACKLIGHT)
-		asle_stat |= asle_set_backlight_ironlake(dev, asle->bclp);
+		asle_stat |= asle_set_backlight(dev, asle->bclp);
 
 	if (asle_req & ASLE_SET_PFIT) {
 		DRM_DEBUG_DRIVER("Pfit is not supported\n");
@@ -315,7 +267,7 @@
 #define ASLE_PFIT_EN   (1<<2)
 #define ASLE_PFMB_EN   (1<<3)
 
-void opregion_enable_asle(struct drm_device *dev)
+void intel_opregion_enable_asle(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct opregion_asle *asle = dev_priv->opregion.asle;
@@ -464,7 +416,58 @@
 	goto end;
 }
 
-int intel_opregion_init(struct drm_device *dev, int resume)
+void intel_opregion_init(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_opregion *opregion = &dev_priv->opregion;
+
+	if (!opregion->header)
+		return;
+
+	if (opregion->acpi) {
+		if (drm_core_check_feature(dev, DRIVER_MODESET))
+			intel_didl_outputs(dev);
+
+		/* Notify BIOS we are ready to handle ACPI video ext notifs.
+		 * Right now, all the events are handled by the ACPI video module.
+		 * We don't actually need to do anything with them. */
+		opregion->acpi->csts = 0;
+		opregion->acpi->drdy = 1;
+
+		system_opregion = opregion;
+		register_acpi_notifier(&intel_opregion_notifier);
+	}
+
+	if (opregion->asle)
+		intel_opregion_enable_asle(dev);
+}
+
+void intel_opregion_fini(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_opregion *opregion = &dev_priv->opregion;
+
+	if (!opregion->header)
+		return;
+
+	if (opregion->acpi) {
+		opregion->acpi->drdy = 0;
+
+		system_opregion = NULL;
+		unregister_acpi_notifier(&intel_opregion_notifier);
+	}
+
+	/* just clear all opregion memory pointers now */
+	iounmap(opregion->header);
+	opregion->header = NULL;
+	opregion->acpi = NULL;
+	opregion->swsci = NULL;
+	opregion->asle = NULL;
+	opregion->vbt = NULL;
+}
+#endif
+
+int intel_opregion_setup(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_opregion *opregion = &dev_priv->opregion;
@@ -479,29 +482,23 @@
 		return -ENOTSUPP;
 	}
 
-	base = ioremap(asls, OPREGION_SZ);
+	base = ioremap(asls, OPREGION_SIZE);
 	if (!base)
 		return -ENOMEM;
 
-	opregion->header = base;
-	if (memcmp(opregion->header->signature, OPREGION_SIGNATURE, 16)) {
+	if (memcmp(base, OPREGION_SIGNATURE, 16)) {
 		DRM_DEBUG_DRIVER("opregion signature mismatch\n");
 		err = -EINVAL;
 		goto err_out;
 	}
+	opregion->header = base;
+	opregion->vbt = base + OPREGION_VBT_OFFSET;
 
 	mboxes = opregion->header->mboxes;
 	if (mboxes & MBOX_ACPI) {
 		DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
 		opregion->acpi = base + OPREGION_ACPI_OFFSET;
-		if (drm_core_check_feature(dev, DRIVER_MODESET))
-			intel_didl_outputs(dev);
-	} else {
-		DRM_DEBUG_DRIVER("Public ACPI methods not supported\n");
-		err = -ENOTSUPP;
-		goto err_out;
 	}
-	opregion->enabled = 1;
 
 	if (mboxes & MBOX_SWSCI) {
 		DRM_DEBUG_DRIVER("SWSCI supported\n");
@@ -510,53 +507,11 @@
 	if (mboxes & MBOX_ASLE) {
 		DRM_DEBUG_DRIVER("ASLE supported\n");
 		opregion->asle = base + OPREGION_ASLE_OFFSET;
-		opregion_enable_asle(dev);
 	}
 
-	if (!resume)
-		acpi_video_register();
-
-
-	/* Notify BIOS we are ready to handle ACPI video ext notifs.
-	 * Right now, all the events are handled by the ACPI video module.
-	 * We don't actually need to do anything with them. */
-	opregion->acpi->csts = 0;
-	opregion->acpi->drdy = 1;
-
-	system_opregion = opregion;
-	register_acpi_notifier(&intel_opregion_notifier);
-
 	return 0;
 
 err_out:
 	iounmap(opregion->header);
-	opregion->header = NULL;
-	acpi_video_register();
 	return err;
 }
-
-void intel_opregion_free(struct drm_device *dev, int suspend)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_opregion *opregion = &dev_priv->opregion;
-
-	if (!opregion->enabled)
-		return;
-
-	if (!suspend)
-		acpi_video_unregister();
-
-	opregion->acpi->drdy = 0;
-
-	system_opregion = NULL;
-	unregister_acpi_notifier(&intel_opregion_notifier);
-
-	/* just clear all opregion memory pointers now */
-	iounmap(opregion->header);
-	opregion->header = NULL;
-	opregion->acpi = NULL;
-	opregion->swsci = NULL;
-	opregion->asle = NULL;
-
-	opregion->enabled = 0;
-}
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 1d306a4..375316a 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -170,57 +170,143 @@
     u16 RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
 };
 
-/* overlay flip addr flag */
-#define OFC_UPDATE		0x1
+struct intel_overlay {
+	struct drm_device *dev;
+	struct intel_crtc *crtc;
+	struct drm_i915_gem_object *vid_bo;
+	struct drm_i915_gem_object *old_vid_bo;
+	int active;
+	int pfit_active;
+	u32 pfit_vscale_ratio; /* shifted-point number, (1<<12) == 1.0 */
+	u32 color_key;
+	u32 brightness, contrast, saturation;
+	u32 old_xscale, old_yscale;
+	/* register access */
+	u32 flip_addr;
+	struct drm_i915_gem_object *reg_bo;
+	/* flip handling */
+	uint32_t last_flip_req;
+	void (*flip_tail)(struct intel_overlay *);
+};
 
-#define OVERLAY_NONPHYSICAL(dev) (IS_G33(dev) || IS_I965G(dev))
-#define OVERLAY_EXISTS(dev) (!IS_G4X(dev) && !IS_IRONLAKE(dev) && !IS_GEN6(dev))
-
-
-static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
+static struct overlay_registers *
+intel_overlay_map_regs(struct intel_overlay *overlay)
 {
         drm_i915_private_t *dev_priv = overlay->dev->dev_private;
 	struct overlay_registers *regs;
 
-	/* no recursive mappings */
-	BUG_ON(overlay->virt_addr);
-
-	if (OVERLAY_NONPHYSICAL(overlay->dev)) {
-		regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
-						overlay->reg_bo->gtt_offset,
-						KM_USER0);
-
-		if (!regs) {
-			DRM_ERROR("failed to map overlay regs in GTT\n");
-			return NULL;
-		}
-	} else
+	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
 		regs = overlay->reg_bo->phys_obj->handle->vaddr;
+	else
+		regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
+					 overlay->reg_bo->gtt_offset);
 
-	return overlay->virt_addr = regs;
+	return regs;
 }
 
-static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
+static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
+				     struct overlay_registers *regs)
 {
-	if (OVERLAY_NONPHYSICAL(overlay->dev))
-		io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0);
+	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+		io_mapping_unmap(regs);
+}
 
-	overlay->virt_addr = NULL;
+static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
+					 struct drm_i915_gem_request *request,
+					 bool interruptible,
+					 void (*tail)(struct intel_overlay *))
+{
+	struct drm_device *dev = overlay->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	int ret;
 
-	return;
+	BUG_ON(overlay->last_flip_req);
+	overlay->last_flip_req =
+		i915_add_request(dev, NULL, request, &dev_priv->render_ring);
+	if (overlay->last_flip_req == 0)
+		return -ENOMEM;
+
+	overlay->flip_tail = tail;
+	ret = i915_do_wait_request(dev,
+				   overlay->last_flip_req, true,
+				   &dev_priv->render_ring);
+	if (ret)
+		return ret;
+
+	overlay->last_flip_req = 0;
+	return 0;
+}
+
+/* Workaround for i830 bug where pipe a must be enable to change control regs */
+static int
+i830_activate_pipe_a(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct intel_crtc *crtc;
+	struct drm_crtc_helper_funcs *crtc_funcs;
+	struct drm_display_mode vesa_640x480 = {
+		DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
+			 752, 800, 0, 480, 489, 492, 525, 0,
+			 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+	}, *mode;
+
+	crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[0]);
+	if (crtc->dpms_mode == DRM_MODE_DPMS_ON)
+		return 0;
+
+	/* most i8xx have pipe a forced on, so don't trust dpms mode */
+	if (I915_READ(PIPEACONF) & PIPECONF_ENABLE)
+		return 0;
+
+	crtc_funcs = crtc->base.helper_private;
+	if (crtc_funcs->dpms == NULL)
+		return 0;
+
+	DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
+
+	mode = drm_mode_duplicate(dev, &vesa_640x480);
+	drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+	if(!drm_crtc_helper_set_mode(&crtc->base, mode,
+				       crtc->base.x, crtc->base.y,
+				       crtc->base.fb))
+		return 0;
+
+	crtc_funcs->dpms(&crtc->base, DRM_MODE_DPMS_ON);
+	return 1;
+}
+
+static void
+i830_deactivate_pipe_a(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
+	struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+	crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 /* overlay needs to be disable in OCMD reg */
 static int intel_overlay_on(struct intel_overlay *overlay)
 {
 	struct drm_device *dev = overlay->dev;
+	struct drm_i915_gem_request *request;
+	int pipe_a_quirk = 0;
 	int ret;
-	drm_i915_private_t *dev_priv = dev->dev_private;
 
 	BUG_ON(overlay->active);
-
 	overlay->active = 1;
-	overlay->hw_wedged = NEEDS_WAIT_FOR_FLIP;
+
+	if (IS_I830(dev)) {
+		pipe_a_quirk = i830_activate_pipe_a(dev);
+		if (pipe_a_quirk < 0)
+			return pipe_a_quirk;
+	}
+
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
 
 	BEGIN_LP_RING(4);
 	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
@@ -229,32 +315,30 @@
 	OUT_RING(MI_NOOP);
 	ADVANCE_LP_RING();
 
-	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-	if (overlay->last_flip_req == 0)
-		return -ENOMEM;
+	ret = intel_overlay_do_wait_request(overlay, request, true, NULL);
+out:
+	if (pipe_a_quirk)
+		i830_deactivate_pipe_a(dev);
 
-	ret = i915_do_wait_request(dev,
-			overlay->last_flip_req, 1, &dev_priv->render_ring);
-	if (ret != 0)
-		return ret;
-
-	overlay->hw_wedged = 0;
-	overlay->last_flip_req = 0;
-	return 0;
+	return ret;
 }
 
 /* overlay needs to be enabled in OCMD reg */
-static void intel_overlay_continue(struct intel_overlay *overlay,
-			    bool load_polyphase_filter)
+static int intel_overlay_continue(struct intel_overlay *overlay,
+				  bool load_polyphase_filter)
 {
 	struct drm_device *dev = overlay->dev;
         drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_gem_request *request;
 	u32 flip_addr = overlay->flip_addr;
 	u32 tmp;
 
 	BUG_ON(!overlay->active);
 
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL)
+		return -ENOMEM;
+
 	if (load_polyphase_filter)
 		flip_addr |= OFC_UPDATE;
 
@@ -269,111 +353,18 @@
         ADVANCE_LP_RING();
 
 	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-}
-
-static int intel_overlay_wait_flip(struct intel_overlay *overlay)
-{
-	struct drm_device *dev = overlay->dev;
-        drm_i915_private_t *dev_priv = dev->dev_private;
-	int ret;
-	u32 tmp;
-
-	if (overlay->last_flip_req != 0) {
-		ret = i915_do_wait_request(dev, overlay->last_flip_req,
-				1, &dev_priv->render_ring);
-		if (ret == 0) {
-			overlay->last_flip_req = 0;
-
-			tmp = I915_READ(ISR);
-
-			if (!(tmp & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT))
-				return 0;
-		}
-	}
-
-	/* synchronous slowpath */
-	overlay->hw_wedged = RELEASE_OLD_VID;
-
-	BEGIN_LP_RING(2);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-        ADVANCE_LP_RING();
-
-	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-	if (overlay->last_flip_req == 0)
-		return -ENOMEM;
-
-	ret = i915_do_wait_request(dev, overlay->last_flip_req,
-			1, &dev_priv->render_ring);
-	if (ret != 0)
-		return ret;
-
-	overlay->hw_wedged = 0;
-	overlay->last_flip_req = 0;
+		i915_add_request(dev, NULL, request, &dev_priv->render_ring);
 	return 0;
 }
 
-/* overlay needs to be disabled in OCMD reg */
-static int intel_overlay_off(struct intel_overlay *overlay)
+static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
 {
-	u32 flip_addr = overlay->flip_addr;
-	struct drm_device *dev = overlay->dev;
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	int ret;
+	struct drm_gem_object *obj = &overlay->old_vid_bo->base;
 
-	BUG_ON(!overlay->active);
+	i915_gem_object_unpin(obj);
+	drm_gem_object_unreference(obj);
 
-	/* According to intel docs the overlay hw may hang (when switching
-	 * off) without loading the filter coeffs. It is however unclear whether
-	 * this applies to the disabling of the overlay or to the switching off
-	 * of the hw. Do it in both cases */
-	flip_addr |= OFC_UPDATE;
-
-	/* wait for overlay to go idle */
-	overlay->hw_wedged = SWITCH_OFF_STAGE_1;
-
-	BEGIN_LP_RING(4);
-	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
-	OUT_RING(flip_addr);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-        ADVANCE_LP_RING();
-
-	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-	if (overlay->last_flip_req == 0)
-		return -ENOMEM;
-
-	ret = i915_do_wait_request(dev, overlay->last_flip_req,
-			1, &dev_priv->render_ring);
-	if (ret != 0)
-		return ret;
-
-	/* turn overlay off */
-	overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
-	BEGIN_LP_RING(4);
-        OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
-	OUT_RING(flip_addr);
-        OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-        OUT_RING(MI_NOOP);
-	ADVANCE_LP_RING();
-
-	overlay->last_flip_req =
-		i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-	if (overlay->last_flip_req == 0)
-		return -ENOMEM;
-
-	ret = i915_do_wait_request(dev, overlay->last_flip_req,
-			1, &dev_priv->render_ring);
-	if (ret != 0)
-		return ret;
-
-	overlay->hw_wedged = 0;
-	overlay->last_flip_req = 0;
-	return ret;
+	overlay->old_vid_bo = NULL;
 }
 
 static void intel_overlay_off_tail(struct intel_overlay *overlay)
@@ -393,96 +384,101 @@
 	overlay->active = 0;
 }
 
-/* recover from an interruption due to a signal
- * We have to be careful not to repeat work forever an make forward progess. */
-int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
-					 int interruptible)
+/* overlay needs to be disabled in OCMD reg */
+static int intel_overlay_off(struct intel_overlay *overlay,
+			     bool interruptible)
 {
 	struct drm_device *dev = overlay->dev;
-	struct drm_gem_object *obj;
+	u32 flip_addr = overlay->flip_addr;
+	struct drm_i915_gem_request *request;
+
+	BUG_ON(!overlay->active);
+
+	request = kzalloc(sizeof(*request), GFP_KERNEL);
+	if (request == NULL)
+		return -ENOMEM;
+
+	/* According to intel docs the overlay hw may hang (when switching
+	 * off) without loading the filter coeffs. It is however unclear whether
+	 * this applies to the disabling of the overlay or to the switching off
+	 * of the hw. Do it in both cases */
+	flip_addr |= OFC_UPDATE;
+
+	BEGIN_LP_RING(6);
+	/* wait for overlay to go idle */
+	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
+	OUT_RING(flip_addr);
+	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+	/* turn overlay off */
+	OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+	OUT_RING(flip_addr);
+	OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+	ADVANCE_LP_RING();
+
+	return intel_overlay_do_wait_request(overlay, request, interruptible,
+					     intel_overlay_off_tail);
+}
+
+/* recover from an interruption due to a signal
+ * We have to be careful not to repeat work forever an make forward progess. */
+static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
+						bool interruptible)
+{
+	struct drm_device *dev = overlay->dev;
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 flip_addr;
 	int ret;
 
-	if (overlay->hw_wedged == HW_WEDGED)
-		return -EIO;
-
-	if (overlay->last_flip_req == 0) {
-		overlay->last_flip_req =
-			i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
-		if (overlay->last_flip_req == 0)
-			return -ENOMEM;
-	}
+	if (overlay->last_flip_req == 0)
+		return 0;
 
 	ret = i915_do_wait_request(dev, overlay->last_flip_req,
-			interruptible, &dev_priv->render_ring);
-	if (ret != 0)
+				   interruptible, &dev_priv->render_ring);
+	if (ret)
 		return ret;
 
-	switch (overlay->hw_wedged) {
-		case RELEASE_OLD_VID:
-			obj = &overlay->old_vid_bo->base;
-			i915_gem_object_unpin(obj);
-			drm_gem_object_unreference(obj);
-			overlay->old_vid_bo = NULL;
-			break;
-		case SWITCH_OFF_STAGE_1:
-			flip_addr = overlay->flip_addr;
-			flip_addr |= OFC_UPDATE;
+	if (overlay->flip_tail)
+		overlay->flip_tail(overlay);
 
-			overlay->hw_wedged = SWITCH_OFF_STAGE_2;
-
-			BEGIN_LP_RING(4);
-			OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
-			OUT_RING(flip_addr);
-			OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
-			OUT_RING(MI_NOOP);
-			ADVANCE_LP_RING();
-
-			overlay->last_flip_req = i915_add_request(dev, NULL,
-					0, &dev_priv->render_ring);
-			if (overlay->last_flip_req == 0)
-				return -ENOMEM;
-
-			ret = i915_do_wait_request(dev, overlay->last_flip_req,
-					interruptible, &dev_priv->render_ring);
-			if (ret != 0)
-				return ret;
-
-		case SWITCH_OFF_STAGE_2:
-			intel_overlay_off_tail(overlay);
-			break;
-		default:
-			BUG_ON(overlay->hw_wedged != NEEDS_WAIT_FOR_FLIP);
-	}
-
-	overlay->hw_wedged = 0;
 	overlay->last_flip_req = 0;
 	return 0;
 }
 
 /* Wait for pending overlay flip and release old frame.
  * Needs to be called before the overlay register are changed
- * via intel_overlay_(un)map_regs_atomic */
+ * via intel_overlay_(un)map_regs
+ */
 static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
 {
+	struct drm_device *dev = overlay->dev;
+	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret;
-	struct drm_gem_object *obj;
 
-	/* only wait if there is actually an old frame to release to
-	 * guarantee forward progress */
+	/* Only wait if there is actually an old frame to release to
+	 * guarantee forward progress.
+	 */
 	if (!overlay->old_vid_bo)
 		return 0;
 
-	ret = intel_overlay_wait_flip(overlay);
-	if (ret != 0)
-		return ret;
+	if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) {
+		struct drm_i915_gem_request *request;
 
-	obj = &overlay->old_vid_bo->base;
-	i915_gem_object_unpin(obj);
-	drm_gem_object_unreference(obj);
-	overlay->old_vid_bo = NULL;
+		/* synchronous slowpath */
+		request = kzalloc(sizeof(*request), GFP_KERNEL);
+		if (request == NULL)
+			return -ENOMEM;
 
+		BEGIN_LP_RING(2);
+		OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+		OUT_RING(MI_NOOP);
+		ADVANCE_LP_RING();
+
+		ret = intel_overlay_do_wait_request(overlay, request, true,
+						    intel_overlay_release_old_vid_tail);
+		if (ret)
+			return ret;
+	}
+
+	intel_overlay_release_old_vid_tail(overlay);
 	return 0;
 }
 
@@ -506,65 +502,65 @@
 static int packed_depth_bytes(u32 format)
 {
 	switch (format & I915_OVERLAY_DEPTH_MASK) {
-		case I915_OVERLAY_YUV422:
-			return 4;
-		case I915_OVERLAY_YUV411:
-			/* return 6; not implemented */
-		default:
-			return -EINVAL;
+	case I915_OVERLAY_YUV422:
+		return 4;
+	case I915_OVERLAY_YUV411:
+		/* return 6; not implemented */
+	default:
+		return -EINVAL;
 	}
 }
 
 static int packed_width_bytes(u32 format, short width)
 {
 	switch (format & I915_OVERLAY_DEPTH_MASK) {
-		case I915_OVERLAY_YUV422:
-			return width << 1;
-		default:
-			return -EINVAL;
+	case I915_OVERLAY_YUV422:
+		return width << 1;
+	default:
+		return -EINVAL;
 	}
 }
 
 static int uv_hsubsampling(u32 format)
 {
 	switch (format & I915_OVERLAY_DEPTH_MASK) {
-		case I915_OVERLAY_YUV422:
-		case I915_OVERLAY_YUV420:
-			return 2;
-		case I915_OVERLAY_YUV411:
-		case I915_OVERLAY_YUV410:
-			return 4;
-		default:
-			return -EINVAL;
+	case I915_OVERLAY_YUV422:
+	case I915_OVERLAY_YUV420:
+		return 2;
+	case I915_OVERLAY_YUV411:
+	case I915_OVERLAY_YUV410:
+		return 4;
+	default:
+		return -EINVAL;
 	}
 }
 
 static int uv_vsubsampling(u32 format)
 {
 	switch (format & I915_OVERLAY_DEPTH_MASK) {
-		case I915_OVERLAY_YUV420:
-		case I915_OVERLAY_YUV410:
-			return 2;
-		case I915_OVERLAY_YUV422:
-		case I915_OVERLAY_YUV411:
-			return 1;
-		default:
-			return -EINVAL;
+	case I915_OVERLAY_YUV420:
+	case I915_OVERLAY_YUV410:
+		return 2;
+	case I915_OVERLAY_YUV422:
+	case I915_OVERLAY_YUV411:
+		return 1;
+	default:
+		return -EINVAL;
 	}
 }
 
 static u32 calc_swidthsw(struct drm_device *dev, u32 offset, u32 width)
 {
 	u32 mask, shift, ret;
-	if (IS_I9XX(dev)) {
-		mask = 0x3f;
-		shift = 6;
-	} else {
+	if (IS_GEN2(dev)) {
 		mask = 0x1f;
 		shift = 5;
+	} else {
+		mask = 0x3f;
+		shift = 6;
 	}
 	ret = ((offset + width + mask) >> shift) - (offset >> shift);
-	if (IS_I9XX(dev))
+	if (!IS_GEN2(dev))
 		ret <<= 1;
 	ret -=1;
 	return ret << 2;
@@ -587,7 +583,9 @@
 	0x3020, 0xb340, 0x1fb8, 0x34a0, 0xb060,
 	0x3020, 0xb240, 0x1fe0, 0x32e0, 0xb040,
 	0x3020, 0xb140, 0x1ff8, 0x3160, 0xb020,
-	0xb000, 0x3000, 0x0800, 0x3000, 0xb000};
+	0xb000, 0x3000, 0x0800, 0x3000, 0xb000
+};
+
 static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
 	0x3000, 0x1800, 0x1800, 0xb000, 0x18d0, 0x2e60,
 	0xb000, 0x1990, 0x2ce0, 0xb020, 0x1a68, 0x2b40,
@@ -597,7 +595,8 @@
 	0xb100, 0x1eb8, 0x3620, 0xb100, 0x1f18, 0x34a0,
 	0xb100, 0x1f68, 0x3360, 0xb0e0, 0x1fa8, 0x3240,
 	0xb0c0, 0x1fe0, 0x3140, 0xb060, 0x1ff0, 0x30a0,
-	0x3000, 0x0800, 0x3000};
+	0x3000, 0x0800, 0x3000
+};
 
 static void update_polyphase_filter(struct overlay_registers *regs)
 {
@@ -630,29 +629,31 @@
 		yscale = 1 << FP_SHIFT;
 
 	/*if (params->format & I915_OVERLAY_YUV_PLANAR) {*/
-		xscale_UV = xscale/uv_hscale;
-		yscale_UV = yscale/uv_vscale;
-		/* make the Y scale to UV scale ratio an exact multiply */
-		xscale = xscale_UV * uv_hscale;
-		yscale = yscale_UV * uv_vscale;
+	xscale_UV = xscale/uv_hscale;
+	yscale_UV = yscale/uv_vscale;
+	/* make the Y scale to UV scale ratio an exact multiply */
+	xscale = xscale_UV * uv_hscale;
+	yscale = yscale_UV * uv_vscale;
 	/*} else {
-		xscale_UV = 0;
-		yscale_UV = 0;
-	}*/
+	  xscale_UV = 0;
+	  yscale_UV = 0;
+	  }*/
 
 	if (xscale != overlay->old_xscale || yscale != overlay->old_yscale)
 		scale_changed = true;
 	overlay->old_xscale = xscale;
 	overlay->old_yscale = yscale;
 
-	regs->YRGBSCALE = ((yscale & FRACT_MASK) << 20)
-		| ((xscale >> FP_SHIFT) << 16)
-		| ((xscale & FRACT_MASK) << 3);
-	regs->UVSCALE = ((yscale_UV & FRACT_MASK) << 20)
-		| ((xscale_UV >> FP_SHIFT) << 16)
-		| ((xscale_UV & FRACT_MASK) << 3);
-	regs->UVSCALEV = ((yscale >> FP_SHIFT) << 16)
-		| ((yscale_UV >> FP_SHIFT) << 0);
+	regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
+			   ((xscale >> FP_SHIFT)  << 16) |
+			   ((xscale & FRACT_MASK) << 3));
+
+	regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
+			 ((xscale_UV >> FP_SHIFT)  << 16) |
+			 ((xscale_UV & FRACT_MASK) << 3));
+
+	regs->UVSCALEV = ((((yscale    >> FP_SHIFT) << 16) |
+			   ((yscale_UV >> FP_SHIFT) << 0)));
 
 	if (scale_changed)
 		update_polyphase_filter(regs);
@@ -664,22 +665,28 @@
 			    struct overlay_registers *regs)
 {
 	u32 key = overlay->color_key;
+
 	switch (overlay->crtc->base.fb->bits_per_pixel) {
-		case 8:
-			regs->DCLRKV = 0;
-			regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
-		case 16:
-			if (overlay->crtc->base.fb->depth == 15) {
-				regs->DCLRKV = RGB15_TO_COLORKEY(key);
-				regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
-			} else {
-				regs->DCLRKV = RGB16_TO_COLORKEY(key);
-				regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
-			}
-		case 24:
-		case 32:
-			regs->DCLRKV = key;
-			regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+	case 8:
+		regs->DCLRKV = 0;
+		regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
+		break;
+
+	case 16:
+		if (overlay->crtc->base.fb->depth == 15) {
+			regs->DCLRKV = RGB15_TO_COLORKEY(key);
+			regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
+		} else {
+			regs->DCLRKV = RGB16_TO_COLORKEY(key);
+			regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
+		}
+		break;
+
+	case 24:
+	case 32:
+		regs->DCLRKV = key;
+		regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+		break;
 	}
 }
 
@@ -689,48 +696,48 @@
 
 	if (params->format & I915_OVERLAY_YUV_PLANAR) {
 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
-			case I915_OVERLAY_YUV422:
-				cmd |= OCMD_YUV_422_PLANAR;
-				break;
-			case I915_OVERLAY_YUV420:
-				cmd |= OCMD_YUV_420_PLANAR;
-				break;
-			case I915_OVERLAY_YUV411:
-			case I915_OVERLAY_YUV410:
-				cmd |= OCMD_YUV_410_PLANAR;
-				break;
+		case I915_OVERLAY_YUV422:
+			cmd |= OCMD_YUV_422_PLANAR;
+			break;
+		case I915_OVERLAY_YUV420:
+			cmd |= OCMD_YUV_420_PLANAR;
+			break;
+		case I915_OVERLAY_YUV411:
+		case I915_OVERLAY_YUV410:
+			cmd |= OCMD_YUV_410_PLANAR;
+			break;
 		}
 	} else { /* YUV packed */
 		switch (params->format & I915_OVERLAY_DEPTH_MASK) {
-			case I915_OVERLAY_YUV422:
-				cmd |= OCMD_YUV_422_PACKED;
-				break;
-			case I915_OVERLAY_YUV411:
-				cmd |= OCMD_YUV_411_PACKED;
-				break;
+		case I915_OVERLAY_YUV422:
+			cmd |= OCMD_YUV_422_PACKED;
+			break;
+		case I915_OVERLAY_YUV411:
+			cmd |= OCMD_YUV_411_PACKED;
+			break;
 		}
 
 		switch (params->format & I915_OVERLAY_SWAP_MASK) {
-			case I915_OVERLAY_NO_SWAP:
-				break;
-			case I915_OVERLAY_UV_SWAP:
-				cmd |= OCMD_UV_SWAP;
-				break;
-			case I915_OVERLAY_Y_SWAP:
-				cmd |= OCMD_Y_SWAP;
-				break;
-			case I915_OVERLAY_Y_AND_UV_SWAP:
-				cmd |= OCMD_Y_AND_UV_SWAP;
-				break;
+		case I915_OVERLAY_NO_SWAP:
+			break;
+		case I915_OVERLAY_UV_SWAP:
+			cmd |= OCMD_UV_SWAP;
+			break;
+		case I915_OVERLAY_Y_SWAP:
+			cmd |= OCMD_Y_SWAP;
+			break;
+		case I915_OVERLAY_Y_AND_UV_SWAP:
+			cmd |= OCMD_Y_AND_UV_SWAP;
+			break;
 		}
 	}
 
 	return cmd;
 }
 
-int intel_overlay_do_put_image(struct intel_overlay *overlay,
-			       struct drm_gem_object *new_bo,
-			       struct put_image_params *params)
+static int intel_overlay_do_put_image(struct intel_overlay *overlay,
+				      struct drm_gem_object *new_bo,
+				      struct put_image_params *params)
 {
 	int ret, tmp_width;
 	struct overlay_registers *regs;
@@ -755,24 +762,24 @@
 		goto out_unpin;
 
 	if (!overlay->active) {
-		regs = intel_overlay_map_regs_atomic(overlay);
+		regs = intel_overlay_map_regs(overlay);
 		if (!regs) {
 			ret = -ENOMEM;
 			goto out_unpin;
 		}
 		regs->OCONFIG = OCONF_CC_OUT_8BIT;
-		if (IS_I965GM(overlay->dev))
+		if (IS_GEN4(overlay->dev))
 			regs->OCONFIG |= OCONF_CSC_MODE_BT709;
 		regs->OCONFIG |= overlay->crtc->pipe == 0 ?
 			OCONF_PIPE_A : OCONF_PIPE_B;
-		intel_overlay_unmap_regs_atomic(overlay);
+		intel_overlay_unmap_regs(overlay, regs);
 
 		ret = intel_overlay_on(overlay);
 		if (ret != 0)
 			goto out_unpin;
 	}
 
-	regs = intel_overlay_map_regs_atomic(overlay);
+	regs = intel_overlay_map_regs(overlay);
 	if (!regs) {
 		ret = -ENOMEM;
 		goto out_unpin;
@@ -788,7 +795,7 @@
 
 	regs->SWIDTH = params->src_w;
 	regs->SWIDTHSW = calc_swidthsw(overlay->dev,
-			params->offset_Y, tmp_width);
+				       params->offset_Y, tmp_width);
 	regs->SHEIGHT = params->src_h;
 	regs->OBUF_0Y = bo_priv->gtt_offset + params-> offset_Y;
 	regs->OSTRIDE = params->stride_Y;
@@ -799,9 +806,9 @@
 		u32 tmp_U, tmp_V;
 		regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
 		tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
-				params->src_w/uv_hscale);
+				      params->src_w/uv_hscale);
 		tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
-				params->src_w/uv_hscale);
+				      params->src_w/uv_hscale);
 		regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
 		regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
 		regs->OBUF_0U = bo_priv->gtt_offset + params->offset_U;
@@ -815,9 +822,11 @@
 
 	regs->OCMD = overlay_cmd_reg(params);
 
-	intel_overlay_unmap_regs_atomic(overlay);
+	intel_overlay_unmap_regs(overlay, regs);
 
-	intel_overlay_continue(overlay, scale_changed);
+	ret = intel_overlay_continue(overlay, scale_changed);
+	if (ret)
+		goto out_unpin;
 
 	overlay->old_vid_bo = overlay->vid_bo;
 	overlay->vid_bo = to_intel_bo(new_bo);
@@ -829,20 +838,19 @@
 	return ret;
 }
 
-int intel_overlay_switch_off(struct intel_overlay *overlay)
+int intel_overlay_switch_off(struct intel_overlay *overlay,
+			     bool interruptible)
 {
-	int ret;
 	struct overlay_registers *regs;
 	struct drm_device *dev = overlay->dev;
+	int ret;
 
 	BUG_ON(!mutex_is_locked(&dev->struct_mutex));
 	BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
-	if (overlay->hw_wedged) {
-		ret = intel_overlay_recover_from_interrupt(overlay, 1);
-		if (ret != 0)
-			return ret;
-	}
+	ret = intel_overlay_recover_from_interrupt(overlay, interruptible);
+	if (ret != 0)
+		return ret;
 
 	if (!overlay->active)
 		return 0;
@@ -851,33 +859,29 @@
 	if (ret != 0)
 		return ret;
 
-	regs = intel_overlay_map_regs_atomic(overlay);
+	regs = intel_overlay_map_regs(overlay);
 	regs->OCMD = 0;
-	intel_overlay_unmap_regs_atomic(overlay);
+	intel_overlay_unmap_regs(overlay, regs);
 
-	ret = intel_overlay_off(overlay);
+	ret = intel_overlay_off(overlay, interruptible);
 	if (ret != 0)
 		return ret;
 
 	intel_overlay_off_tail(overlay);
-
 	return 0;
 }
 
 static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
 					  struct intel_crtc *crtc)
 {
-        drm_i915_private_t *dev_priv = overlay->dev->dev_private;
-	u32 pipeconf;
-	int pipeconf_reg = (crtc->pipe == 0) ? PIPEACONF : PIPEBCONF;
+	drm_i915_private_t *dev_priv = overlay->dev->dev_private;
 
-	if (!crtc->base.enabled || crtc->dpms_mode != DRM_MODE_DPMS_ON)
+	if (!crtc->active)
 		return -EINVAL;
 
-	pipeconf = I915_READ(pipeconf_reg);
-
 	/* can't use the overlay with double wide pipe */
-	if (!IS_I965G(overlay->dev) && pipeconf & PIPEACONF_DOUBLE_WIDE)
+	if (INTEL_INFO(overlay->dev)->gen < 4 &&
+	    (I915_READ(PIPECONF(crtc->pipe)) & (PIPECONF_DOUBLE_WIDE | PIPECONF_ENABLE)) != PIPECONF_ENABLE)
 		return -EINVAL;
 
 	return 0;
@@ -886,20 +890,22 @@
 static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
 {
 	struct drm_device *dev = overlay->dev;
-        drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 ratio;
+	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 pfit_control = I915_READ(PFIT_CONTROL);
+	u32 ratio;
 
 	/* XXX: This is not the same logic as in the xorg driver, but more in
-	 * line with the intel documentation for the i965 */
-	if (!IS_I965G(dev) && (pfit_control & VERT_AUTO_SCALE)) {
-		ratio = I915_READ(PFIT_AUTO_RATIOS) >> PFIT_VERT_SCALE_SHIFT;
-	} else { /* on i965 use the PGM reg to read out the autoscaler values */
-		ratio = I915_READ(PFIT_PGM_RATIOS);
-		if (IS_I965G(dev))
-			ratio >>= PFIT_VERT_SCALE_SHIFT_965;
+	 * line with the intel documentation for the i965
+	 */
+	if (INTEL_INFO(dev)->gen >= 4) {
+	       	/* on i965 use the PGM reg to read out the autoscaler values */
+		ratio = I915_READ(PFIT_PGM_RATIOS) >> PFIT_VERT_SCALE_SHIFT_965;
+	} else {
+		if (pfit_control & VERT_AUTO_SCALE)
+			ratio = I915_READ(PFIT_AUTO_RATIOS);
 		else
-			ratio >>= PFIT_VERT_SCALE_SHIFT;
+			ratio = I915_READ(PFIT_PGM_RATIOS);
+		ratio >>= PFIT_VERT_SCALE_SHIFT;
 	}
 
 	overlay->pfit_vscale_ratio = ratio;
@@ -910,12 +916,10 @@
 {
 	struct drm_display_mode *mode = &overlay->crtc->base.mode;
 
-	if ((rec->dst_x < mode->crtc_hdisplay)
-	    && (rec->dst_x + rec->dst_width
-		    <= mode->crtc_hdisplay)
-	    && (rec->dst_y < mode->crtc_vdisplay)
-	    && (rec->dst_y + rec->dst_height
-		    <= mode->crtc_vdisplay))
+	if (rec->dst_x < mode->crtc_hdisplay &&
+	    rec->dst_x + rec->dst_width <= mode->crtc_hdisplay &&
+	    rec->dst_y < mode->crtc_vdisplay &&
+	    rec->dst_y + rec->dst_height <= mode->crtc_vdisplay)
 		return 0;
 	else
 		return -EINVAL;
@@ -940,53 +944,57 @@
 			     struct drm_intel_overlay_put_image *rec,
 			     struct drm_gem_object *new_bo)
 {
-	u32 stride_mask;
-	int depth;
 	int uv_hscale = uv_hsubsampling(rec->flags);
 	int uv_vscale = uv_vsubsampling(rec->flags);
-	size_t tmp;
+	u32 stride_mask, depth, tmp;
 
 	/* check src dimensions */
 	if (IS_845G(dev) || IS_I830(dev)) {
-		if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY
-		    || rec->src_width > IMAGE_MAX_WIDTH_LEGACY)
+		if (rec->src_height > IMAGE_MAX_HEIGHT_LEGACY ||
+		    rec->src_width  > IMAGE_MAX_WIDTH_LEGACY)
 			return -EINVAL;
 	} else {
-		if (rec->src_height > IMAGE_MAX_HEIGHT
-		    || rec->src_width > IMAGE_MAX_WIDTH)
+		if (rec->src_height > IMAGE_MAX_HEIGHT ||
+		    rec->src_width  > IMAGE_MAX_WIDTH)
 			return -EINVAL;
 	}
+
 	/* better safe than sorry, use 4 as the maximal subsampling ratio */
-	if (rec->src_height < N_VERT_Y_TAPS*4
-	    || rec->src_width < N_HORIZ_Y_TAPS*4)
+	if (rec->src_height < N_VERT_Y_TAPS*4 ||
+	    rec->src_width  < N_HORIZ_Y_TAPS*4)
 		return -EINVAL;
 
 	/* check alignment constraints */
 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
-		case I915_OVERLAY_RGB:
-			/* not implemented */
+	case I915_OVERLAY_RGB:
+		/* not implemented */
+		return -EINVAL;
+
+	case I915_OVERLAY_YUV_PACKED:
+		if (uv_vscale != 1)
 			return -EINVAL;
-		case I915_OVERLAY_YUV_PACKED:
-			depth = packed_depth_bytes(rec->flags);
-			if (uv_vscale != 1)
-				return -EINVAL;
-			if (depth < 0)
-				return depth;
-			/* ignore UV planes */
-			rec->stride_UV = 0;
-			rec->offset_U = 0;
-			rec->offset_V = 0;
-			/* check pixel alignment */
-			if (rec->offset_Y % depth)
-				return -EINVAL;
-			break;
-		case I915_OVERLAY_YUV_PLANAR:
-			if (uv_vscale < 0 || uv_hscale < 0)
-				return -EINVAL;
-			/* no offset restrictions for planar formats */
-			break;
-		default:
+
+		depth = packed_depth_bytes(rec->flags);
+		if (depth < 0)
+			return depth;
+
+		/* ignore UV planes */
+		rec->stride_UV = 0;
+		rec->offset_U = 0;
+		rec->offset_V = 0;
+		/* check pixel alignment */
+		if (rec->offset_Y % depth)
 			return -EINVAL;
+		break;
+
+	case I915_OVERLAY_YUV_PLANAR:
+		if (uv_vscale < 0 || uv_hscale < 0)
+			return -EINVAL;
+		/* no offset restrictions for planar formats */
+		break;
+
+	default:
+		return -EINVAL;
 	}
 
 	if (rec->src_width % uv_hscale)
@@ -1000,47 +1008,74 @@
 
 	if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask)
 		return -EINVAL;
-	if (IS_I965G(dev) && rec->stride_Y < 512)
+	if (IS_GEN4(dev) && rec->stride_Y < 512)
 		return -EINVAL;
 
 	tmp = (rec->flags & I915_OVERLAY_TYPE_MASK) == I915_OVERLAY_YUV_PLANAR ?
-		4 : 8;
-	if (rec->stride_Y > tmp*1024 || rec->stride_UV > 2*1024)
+		4096 : 8192;
+	if (rec->stride_Y > tmp || rec->stride_UV > 2*1024)
 		return -EINVAL;
 
 	/* check buffer dimensions */
 	switch (rec->flags & I915_OVERLAY_TYPE_MASK) {
-		case I915_OVERLAY_RGB:
-		case I915_OVERLAY_YUV_PACKED:
-			/* always 4 Y values per depth pixels */
-			if (packed_width_bytes(rec->flags, rec->src_width)
-					> rec->stride_Y)
-				return -EINVAL;
+	case I915_OVERLAY_RGB:
+	case I915_OVERLAY_YUV_PACKED:
+		/* always 4 Y values per depth pixels */
+		if (packed_width_bytes(rec->flags, rec->src_width) > rec->stride_Y)
+			return -EINVAL;
 
-			tmp = rec->stride_Y*rec->src_height;
-			if (rec->offset_Y + tmp > new_bo->size)
-				return -EINVAL;
-			break;
-		case I915_OVERLAY_YUV_PLANAR:
-			if (rec->src_width > rec->stride_Y)
-				return -EINVAL;
-			if (rec->src_width/uv_hscale > rec->stride_UV)
-				return -EINVAL;
+		tmp = rec->stride_Y*rec->src_height;
+		if (rec->offset_Y + tmp > new_bo->size)
+			return -EINVAL;
+		break;
 
-			tmp = rec->stride_Y*rec->src_height;
-			if (rec->offset_Y + tmp > new_bo->size)
-				return -EINVAL;
-			tmp = rec->stride_UV*rec->src_height;
-			tmp /= uv_vscale;
-			if (rec->offset_U + tmp > new_bo->size
-			    || rec->offset_V + tmp > new_bo->size)
-				return -EINVAL;
-			break;
+	case I915_OVERLAY_YUV_PLANAR:
+		if (rec->src_width > rec->stride_Y)
+			return -EINVAL;
+		if (rec->src_width/uv_hscale > rec->stride_UV)
+			return -EINVAL;
+
+		tmp = rec->stride_Y * rec->src_height;
+		if (rec->offset_Y + tmp > new_bo->size)
+			return -EINVAL;
+
+		tmp = rec->stride_UV * (rec->src_height / uv_vscale);
+		if (rec->offset_U + tmp > new_bo->size ||
+		    rec->offset_V + tmp > new_bo->size)
+			return -EINVAL;
+		break;
 	}
 
 	return 0;
 }
 
+/**
+ * Return the pipe currently connected to the panel fitter,
+ * or -1 if the panel fitter is not present or not in use
+ */
+static int intel_panel_fitter_pipe(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32  pfit_control;
+
+	/* i830 doesn't have a panel fitter */
+	if (IS_I830(dev))
+		return -1;
+
+	pfit_control = I915_READ(PFIT_CONTROL);
+
+	/* See if the panel fitter is in use */
+	if ((pfit_control & PFIT_ENABLE) == 0)
+		return -1;
+
+	/* 965 can place panel fitter on either pipe */
+	if (IS_GEN4(dev))
+		return (pfit_control >> 29) & 0x3;
+
+	/* older chips can only use pipe 1 */
+	return 1;
+}
+
 int intel_overlay_put_image(struct drm_device *dev, void *data,
                             struct drm_file *file_priv)
 {
@@ -1068,7 +1103,7 @@
 		mutex_lock(&dev->mode_config.mutex);
 		mutex_lock(&dev->struct_mutex);
 
-		ret = intel_overlay_switch_off(overlay);
+		ret = intel_overlay_switch_off(overlay, true);
 
 		mutex_unlock(&dev->struct_mutex);
 		mutex_unlock(&dev->mode_config.mutex);
@@ -1081,7 +1116,7 @@
 		return -ENOMEM;
 
 	drmmode_obj = drm_mode_object_find(dev, put_image_rec->crtc_id,
-                        DRM_MODE_OBJECT_CRTC);
+					   DRM_MODE_OBJECT_CRTC);
 	if (!drmmode_obj) {
 		ret = -ENOENT;
 		goto out_free;
@@ -1089,7 +1124,7 @@
 	crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
 
 	new_bo = drm_gem_object_lookup(dev, file_priv,
-			put_image_rec->bo_handle);
+				       put_image_rec->bo_handle);
 	if (!new_bo) {
 		ret = -ENOENT;
 		goto out_free;
@@ -1098,15 +1133,13 @@
 	mutex_lock(&dev->mode_config.mutex);
 	mutex_lock(&dev->struct_mutex);
 
-	if (overlay->hw_wedged) {
-		ret = intel_overlay_recover_from_interrupt(overlay, 1);
-		if (ret != 0)
-			goto out_unlock;
-	}
+	ret = intel_overlay_recover_from_interrupt(overlay, true);
+	if (ret != 0)
+		goto out_unlock;
 
 	if (overlay->crtc != crtc) {
 		struct drm_display_mode *mode = &crtc->base.mode;
-		ret = intel_overlay_switch_off(overlay);
+		ret = intel_overlay_switch_off(overlay, true);
 		if (ret != 0)
 			goto out_unlock;
 
@@ -1117,9 +1150,9 @@
 		overlay->crtc = crtc;
 		crtc->overlay = overlay;
 
-		if (intel_panel_fitter_pipe(dev) == crtc->pipe
-		    /* and line to wide, i.e. one-line-mode */
-		    && mode->hdisplay > 1024) {
+		/* line too wide, i.e. one-line-mode */
+		if (mode->hdisplay > 1024 &&
+		    intel_panel_fitter_pipe(dev) == crtc->pipe) {
 			overlay->pfit_active = 1;
 			update_pfit_vscale_ratio(overlay);
 		} else
@@ -1132,10 +1165,10 @@
 
 	if (overlay->pfit_active) {
 		params->dst_y = ((((u32)put_image_rec->dst_y) << 12) /
-			overlay->pfit_vscale_ratio);
+				 overlay->pfit_vscale_ratio);
 		/* shifting right rounds downwards, so add 1 */
 		params->dst_h = ((((u32)put_image_rec->dst_height) << 12) /
-			overlay->pfit_vscale_ratio) + 1;
+				 overlay->pfit_vscale_ratio) + 1;
 	} else {
 		params->dst_y = put_image_rec->dst_y;
 		params->dst_h = put_image_rec->dst_height;
@@ -1147,8 +1180,8 @@
 	params->src_h = put_image_rec->src_height;
 	params->src_scan_w = put_image_rec->src_scan_width;
 	params->src_scan_h = put_image_rec->src_scan_height;
-	if (params->src_scan_h > params->src_h
-	    || params->src_scan_w > params->src_w) {
+	if (params->src_scan_h > params->src_h ||
+	    params->src_scan_w > params->src_w) {
 		ret = -EINVAL;
 		goto out_unlock;
 	}
@@ -1204,7 +1237,7 @@
 		return false;
 
 	for (i = 0; i < 3; i++) {
-		if (((gamma1 >> i * 8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
+		if (((gamma1 >> i*8) & 0xff) >= ((gamma2 >> i*8) & 0xff))
 			return false;
 	}
 
@@ -1225,16 +1258,18 @@
 
 static int check_gamma(struct drm_intel_overlay_attrs *attrs)
 {
-	if (!check_gamma_bounds(0, attrs->gamma0)
-	    || !check_gamma_bounds(attrs->gamma0, attrs->gamma1)
-	    || !check_gamma_bounds(attrs->gamma1, attrs->gamma2)
-	    || !check_gamma_bounds(attrs->gamma2, attrs->gamma3)
-	    || !check_gamma_bounds(attrs->gamma3, attrs->gamma4)
-	    || !check_gamma_bounds(attrs->gamma4, attrs->gamma5)
-	    || !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
+	if (!check_gamma_bounds(0, attrs->gamma0) ||
+	    !check_gamma_bounds(attrs->gamma0, attrs->gamma1) ||
+	    !check_gamma_bounds(attrs->gamma1, attrs->gamma2) ||
+	    !check_gamma_bounds(attrs->gamma2, attrs->gamma3) ||
+	    !check_gamma_bounds(attrs->gamma3, attrs->gamma4) ||
+	    !check_gamma_bounds(attrs->gamma4, attrs->gamma5) ||
+	    !check_gamma_bounds(attrs->gamma5, 0x00ffffff))
 		return -EINVAL;
+
 	if (!check_gamma5_errata(attrs->gamma5))
 		return -EINVAL;
+
 	return 0;
 }
 
@@ -1261,13 +1296,14 @@
 	mutex_lock(&dev->mode_config.mutex);
 	mutex_lock(&dev->struct_mutex);
 
+	ret = -EINVAL;
 	if (!(attrs->flags & I915_OVERLAY_UPDATE_ATTRS)) {
-		attrs->color_key = overlay->color_key;
+		attrs->color_key  = overlay->color_key;
 		attrs->brightness = overlay->brightness;
-		attrs->contrast = overlay->contrast;
+		attrs->contrast   = overlay->contrast;
 		attrs->saturation = overlay->saturation;
 
-		if (IS_I9XX(dev)) {
+		if (!IS_GEN2(dev)) {
 			attrs->gamma0 = I915_READ(OGAMC0);
 			attrs->gamma1 = I915_READ(OGAMC1);
 			attrs->gamma2 = I915_READ(OGAMC2);
@@ -1275,29 +1311,20 @@
 			attrs->gamma4 = I915_READ(OGAMC4);
 			attrs->gamma5 = I915_READ(OGAMC5);
 		}
-		ret = 0;
 	} else {
-		overlay->color_key = attrs->color_key;
-		if (attrs->brightness >= -128 && attrs->brightness <= 127) {
-			overlay->brightness = attrs->brightness;
-		} else {
-			ret = -EINVAL;
+		if (attrs->brightness < -128 || attrs->brightness > 127)
 			goto out_unlock;
-		}
-		if (attrs->contrast <= 255) {
-			overlay->contrast = attrs->contrast;
-		} else {
-			ret = -EINVAL;
+		if (attrs->contrast > 255)
 			goto out_unlock;
-		}
-		if (attrs->saturation <= 1023) {
-			overlay->saturation = attrs->saturation;
-		} else {
-			ret = -EINVAL;
+		if (attrs->saturation > 1023)
 			goto out_unlock;
-		}
 
-		regs = intel_overlay_map_regs_atomic(overlay);
+		overlay->color_key  = attrs->color_key;
+		overlay->brightness = attrs->brightness;
+		overlay->contrast   = attrs->contrast;
+		overlay->saturation = attrs->saturation;
+
+		regs = intel_overlay_map_regs(overlay);
 		if (!regs) {
 			ret = -ENOMEM;
 			goto out_unlock;
@@ -1305,13 +1332,11 @@
 
 		update_reg_attrs(overlay, regs);
 
-		intel_overlay_unmap_regs_atomic(overlay);
+		intel_overlay_unmap_regs(overlay, regs);
 
 		if (attrs->flags & I915_OVERLAY_UPDATE_GAMMA) {
-			if (!IS_I9XX(dev)) {
-				ret = -EINVAL;
+			if (IS_GEN2(dev))
 				goto out_unlock;
-			}
 
 			if (overlay->active) {
 				ret = -EBUSY;
@@ -1319,7 +1344,7 @@
 			}
 
 			ret = check_gamma(attrs);
-			if (ret != 0)
+			if (ret)
 				goto out_unlock;
 
 			I915_WRITE(OGAMC0, attrs->gamma0);
@@ -1329,9 +1354,9 @@
 			I915_WRITE(OGAMC4, attrs->gamma4);
 			I915_WRITE(OGAMC5, attrs->gamma5);
 		}
-		ret = 0;
 	}
 
+	ret = 0;
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
 	mutex_unlock(&dev->mode_config.mutex);
@@ -1347,7 +1372,7 @@
 	struct overlay_registers *regs;
 	int ret;
 
-	if (!OVERLAY_EXISTS(dev))
+	if (!HAS_OVERLAY(dev))
 		return;
 
 	overlay = kzalloc(sizeof(struct intel_overlay), GFP_KERNEL);
@@ -1360,22 +1385,28 @@
 		goto out_free;
 	overlay->reg_bo = to_intel_bo(reg_bo);
 
-	if (OVERLAY_NONPHYSICAL(dev)) {
+	if (OVERLAY_NEEDS_PHYSICAL(dev)) {
+		ret = i915_gem_attach_phys_object(dev, reg_bo,
+						  I915_GEM_PHYS_OVERLAY_REGS,
+						  PAGE_SIZE);
+                if (ret) {
+                        DRM_ERROR("failed to attach phys overlay regs\n");
+                        goto out_free_bo;
+                }
+		overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
+	} else {
 		ret = i915_gem_object_pin(reg_bo, PAGE_SIZE);
 		if (ret) {
                         DRM_ERROR("failed to pin overlay register bo\n");
                         goto out_free_bo;
                 }
 		overlay->flip_addr = overlay->reg_bo->gtt_offset;
-	} else {
-		ret = i915_gem_attach_phys_object(dev, reg_bo,
-						  I915_GEM_PHYS_OVERLAY_REGS,
-						  0);
-                if (ret) {
-                        DRM_ERROR("failed to attach phys overlay regs\n");
-                        goto out_free_bo;
+
+		ret = i915_gem_object_set_to_gtt_domain(reg_bo, true);
+		if (ret) {
+                        DRM_ERROR("failed to move overlay register bo into the GTT\n");
+                        goto out_unpin_bo;
                 }
-		overlay->flip_addr = overlay->reg_bo->phys_obj->handle->busaddr;
 	}
 
 	/* init all values */
@@ -1384,21 +1415,22 @@
 	overlay->contrast = 75;
 	overlay->saturation = 146;
 
-	regs = intel_overlay_map_regs_atomic(overlay);
+	regs = intel_overlay_map_regs(overlay);
 	if (!regs)
 		goto out_free_bo;
 
 	memset(regs, 0, sizeof(struct overlay_registers));
 	update_polyphase_filter(regs);
-
 	update_reg_attrs(overlay, regs);
 
-	intel_overlay_unmap_regs_atomic(overlay);
+	intel_overlay_unmap_regs(overlay, regs);
 
 	dev_priv->overlay = overlay;
 	DRM_INFO("initialized overlay support\n");
 	return;
 
+out_unpin_bo:
+	i915_gem_object_unpin(reg_bo);
 out_free_bo:
 	drm_gem_object_unreference(reg_bo);
 out_free:
@@ -1408,18 +1440,23 @@
 
 void intel_cleanup_overlay(struct drm_device *dev)
 {
-        drm_i915_private_t *dev_priv = dev->dev_private;
+	drm_i915_private_t *dev_priv = dev->dev_private;
 
-	if (dev_priv->overlay) {
-		/* The bo's should be free'd by the generic code already.
-		 * Furthermore modesetting teardown happens beforehand so the
-		 * hardware should be off already */
-		BUG_ON(dev_priv->overlay->active);
+	if (!dev_priv->overlay)
+		return;
 
-		kfree(dev_priv->overlay);
-	}
+	/* The bo's should be free'd by the generic code already.
+	 * Furthermore modesetting teardown happens beforehand so the
+	 * hardware should be off already */
+	BUG_ON(dev_priv->overlay->active);
+
+	drm_gem_object_unreference_unlocked(&dev_priv->overlay->reg_bo->base);
+	kfree(dev_priv->overlay);
 }
 
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
 struct intel_overlay_error_state {
 	struct overlay_registers regs;
 	unsigned long base;
@@ -1427,6 +1464,32 @@
 	u32 isr;
 };
 
+static struct overlay_registers *
+intel_overlay_map_regs_atomic(struct intel_overlay *overlay,
+			      int slot)
+{
+        drm_i915_private_t *dev_priv = overlay->dev->dev_private;
+	struct overlay_registers *regs;
+
+	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+		regs = overlay->reg_bo->phys_obj->handle->vaddr;
+	else
+		regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
+						overlay->reg_bo->gtt_offset,
+						slot);
+
+	return regs;
+}
+
+static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
+					    int slot,
+					    struct overlay_registers *regs)
+{
+	if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
+		io_mapping_unmap_atomic(regs, slot);
+}
+
+
 struct intel_overlay_error_state *
 intel_overlay_capture_error_state(struct drm_device *dev)
 {
@@ -1444,17 +1507,17 @@
 
 	error->dovsta = I915_READ(DOVSTA);
 	error->isr = I915_READ(ISR);
-	if (OVERLAY_NONPHYSICAL(overlay->dev))
-		error->base = (long) overlay->reg_bo->gtt_offset;
-	else
+	if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
 		error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
+	else
+		error->base = (long) overlay->reg_bo->gtt_offset;
 
-	regs = intel_overlay_map_regs_atomic(overlay);
+	regs = intel_overlay_map_regs_atomic(overlay, KM_IRQ0);
 	if (!regs)
 		goto err;
 
 	memcpy_fromio(&error->regs, regs, sizeof(struct overlay_registers));
-	intel_overlay_unmap_regs_atomic(overlay);
+	intel_overlay_unmap_regs_atomic(overlay, KM_IRQ0, regs);
 
 	return error;
 
@@ -1515,3 +1578,4 @@
 	P(UVSCALEV);
 #undef P
 }
+#endif
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index e7f5299..92ff8f3 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -30,6 +30,8 @@
 
 #include "intel_drv.h"
 
+#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
+
 void
 intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 		       struct drm_display_mode *adjusted_mode)
@@ -109,3 +111,110 @@
 	dev_priv->pch_pf_pos = (x << 16) | y;
 	dev_priv->pch_pf_size = (width << 16) | height;
 }
+
+static int is_backlight_combination_mode(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+
+	if (INTEL_INFO(dev)->gen >= 4)
+		return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+
+	if (IS_GEN2(dev))
+		return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+
+	return 0;
+}
+
+u32 intel_panel_get_max_backlight(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 max;
+
+	if (HAS_PCH_SPLIT(dev)) {
+		max = I915_READ(BLC_PWM_PCH_CTL2) >> 16;
+	} else {
+		max = I915_READ(BLC_PWM_CTL);
+		if (IS_PINEVIEW(dev)) {
+			max >>= 17;
+		} else {
+			max >>= 16;
+			if (INTEL_INFO(dev)->gen < 4)
+				max &= ~1;
+		}
+
+		if (is_backlight_combination_mode(dev))
+			max *= 0xff;
+	}
+
+	if (max == 0) {
+		/* XXX add code here to query mode clock or hardware clock
+		 * and program max PWM appropriately.
+		 */
+		DRM_ERROR("fixme: max PWM is zero.\n");
+		max = 1;
+	}
+
+	DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
+	return max;
+}
+
+u32 intel_panel_get_backlight(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 val;
+
+	if (HAS_PCH_SPLIT(dev)) {
+		val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+	} else {
+		val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+		if (IS_PINEVIEW(dev))
+			val >>= 1;
+
+		if (is_backlight_combination_mode(dev)){
+			u8 lbpc;
+
+			val &= ~1;
+			pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
+			val *= lbpc;
+			val >>= 1;
+		}
+	}
+
+	DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
+	return val;
+}
+
+static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+	I915_WRITE(BLC_PWM_CPU_CTL, val | level);
+}
+
+void intel_panel_set_backlight(struct drm_device *dev, u32 level)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 tmp;
+
+	DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
+
+	if (HAS_PCH_SPLIT(dev))
+		return intel_pch_panel_set_backlight(dev, level);
+
+	if (is_backlight_combination_mode(dev)){
+		u32 max = intel_panel_get_max_backlight(dev);
+		u8 lpbc;
+
+		lpbc = level * 0xfe / max + 1;
+		level /= lpbc;
+		pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc);
+	}
+
+	tmp = I915_READ(BLC_PWM_CTL);
+	if (IS_PINEVIEW(dev)) {
+		tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1);
+		level <<= 1;
+	} else
+		tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
+	I915_WRITE(BLC_PWM_CTL, tmp | level);
+}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index cb3508f..d89b887 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -32,6 +32,7 @@
 #include "i915_drv.h"
 #include "i915_drm.h"
 #include "i915_trace.h"
+#include "intel_drv.h"
 
 static u32 i915_gem_get_seqno(struct drm_device *dev)
 {
@@ -49,9 +50,9 @@
 
 static void
 render_ring_flush(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		u32	invalidate_domains,
-		u32	flush_domains)
+		  struct intel_ring_buffer *ring,
+		  u32	invalidate_domains,
+		  u32	flush_domains)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 cmd;
@@ -97,7 +98,7 @@
 		if ((invalidate_domains|flush_domains) &
 		    I915_GEM_DOMAIN_RENDER)
 			cmd &= ~MI_NO_WRITE_FLUSH;
-		if (!IS_I965G(dev)) {
+		if (INTEL_INFO(dev)->gen < 4) {
 			/*
 			 * On the 965, the sampler cache always gets flushed
 			 * and this bit is reserved.
@@ -118,38 +119,26 @@
 	}
 }
 
-static unsigned int render_ring_get_head(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+static void ring_set_tail(struct drm_device *dev,
+			  struct intel_ring_buffer *ring,
+			  u32 value)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(PRB0_HEAD) & HEAD_ADDR;
+	I915_WRITE_TAIL(ring, ring->tail);
 }
 
-static unsigned int render_ring_get_tail(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+u32 intel_ring_get_active_head(struct drm_device *dev,
+			       struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(PRB0_TAIL) & TAIL_ADDR;
-}
-
-static unsigned int render_ring_get_active_head(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+	u32 acthd_reg = INTEL_INFO(dev)->gen >= 4 ?
+			RING_ACTHD(ring->mmio_base) : ACTHD;
 
 	return I915_READ(acthd_reg);
 }
 
-static void render_ring_advance_ring(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	I915_WRITE(PRB0_TAIL, ring->tail);
-}
-
 static int init_ring_common(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			    struct intel_ring_buffer *ring)
 {
 	u32 head;
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -157,57 +146,57 @@
 	obj_priv = to_intel_bo(ring->gem_object);
 
 	/* Stop the ring if it's running. */
-	I915_WRITE(ring->regs.ctl, 0);
-	I915_WRITE(ring->regs.head, 0);
-	I915_WRITE(ring->regs.tail, 0);
+	I915_WRITE_CTL(ring, 0);
+	I915_WRITE_HEAD(ring, 0);
+	ring->set_tail(dev, ring, 0);
 
 	/* Initialize the ring. */
-	I915_WRITE(ring->regs.start, obj_priv->gtt_offset);
-	head = ring->get_head(dev, ring);
+	I915_WRITE_START(ring, obj_priv->gtt_offset);
+	head = I915_READ_HEAD(ring) & HEAD_ADDR;
 
 	/* G45 ring initialization fails to reset head to zero */
 	if (head != 0) {
 		DRM_ERROR("%s head not reset to zero "
 				"ctl %08x head %08x tail %08x start %08x\n",
 				ring->name,
-				I915_READ(ring->regs.ctl),
-				I915_READ(ring->regs.head),
-				I915_READ(ring->regs.tail),
-				I915_READ(ring->regs.start));
+				I915_READ_CTL(ring),
+				I915_READ_HEAD(ring),
+				I915_READ_TAIL(ring),
+				I915_READ_START(ring));
 
-		I915_WRITE(ring->regs.head, 0);
+		I915_WRITE_HEAD(ring, 0);
 
 		DRM_ERROR("%s head forced to zero "
 				"ctl %08x head %08x tail %08x start %08x\n",
 				ring->name,
-				I915_READ(ring->regs.ctl),
-				I915_READ(ring->regs.head),
-				I915_READ(ring->regs.tail),
-				I915_READ(ring->regs.start));
+				I915_READ_CTL(ring),
+				I915_READ_HEAD(ring),
+				I915_READ_TAIL(ring),
+				I915_READ_START(ring));
 	}
 
-	I915_WRITE(ring->regs.ctl,
+	I915_WRITE_CTL(ring,
 			((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
 			| RING_NO_REPORT | RING_VALID);
 
-	head = I915_READ(ring->regs.head) & HEAD_ADDR;
+	head = I915_READ_HEAD(ring) & HEAD_ADDR;
 	/* If the head is still not zero, the ring is dead */
 	if (head != 0) {
 		DRM_ERROR("%s initialization failed "
 				"ctl %08x head %08x tail %08x start %08x\n",
 				ring->name,
-				I915_READ(ring->regs.ctl),
-				I915_READ(ring->regs.head),
-				I915_READ(ring->regs.tail),
-				I915_READ(ring->regs.start));
+				I915_READ_CTL(ring),
+				I915_READ_HEAD(ring),
+				I915_READ_TAIL(ring),
+				I915_READ_START(ring));
 		return -EIO;
 	}
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		i915_kernel_lost_context(dev);
 	else {
-		ring->head = ring->get_head(dev, ring);
-		ring->tail = ring->get_tail(dev, ring);
+		ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+		ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
 		ring->space = ring->head - (ring->tail + 8);
 		if (ring->space < 0)
 			ring->space += ring->size;
@@ -216,13 +205,13 @@
 }
 
 static int init_render_ring(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			    struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int ret = init_ring_common(dev, ring);
 	int mode;
 
-	if (IS_I9XX(dev) && !IS_GEN3(dev)) {
+	if (INTEL_INFO(dev)->gen > 3) {
 		mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
 		if (IS_GEN6(dev))
 			mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
@@ -250,9 +239,8 @@
  */
 static u32
 render_ring_add_request(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		struct drm_file *file_priv,
-		u32 flush_domains)
+			struct intel_ring_buffer *ring,
+			u32 flush_domains)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	u32 seqno;
@@ -315,8 +303,8 @@
 }
 
 static u32
-render_ring_get_gem_seqno(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+render_ring_get_seqno(struct drm_device *dev,
+		      struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	if (HAS_PIPE_CONTROL(dev))
@@ -327,7 +315,7 @@
 
 static void
 render_ring_get_user_irq(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			 struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long irqflags;
@@ -344,7 +332,7 @@
 
 static void
 render_ring_put_user_irq(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			 struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	unsigned long irqflags;
@@ -360,21 +348,23 @@
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 }
 
-static void render_setup_status_page(struct drm_device *dev,
-	struct	intel_ring_buffer *ring)
+void intel_ring_setup_status_page(struct drm_device *dev,
+				  struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	if (IS_GEN6(dev)) {
-		I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr);
-		I915_READ(HWS_PGA_GEN6); /* posting read */
+		I915_WRITE(RING_HWS_PGA_GEN6(ring->mmio_base),
+			   ring->status_page.gfx_addr);
+		I915_READ(RING_HWS_PGA_GEN6(ring->mmio_base)); /* posting read */
 	} else {
-		I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
-		I915_READ(HWS_PGA); /* posting read */
+		I915_WRITE(RING_HWS_PGA(ring->mmio_base),
+			   ring->status_page.gfx_addr);
+		I915_READ(RING_HWS_PGA(ring->mmio_base)); /* posting read */
 	}
 
 }
 
-void
+static void
 bsd_ring_flush(struct drm_device *dev,
 		struct intel_ring_buffer *ring,
 		u32     invalidate_domains,
@@ -386,45 +376,16 @@
 	intel_ring_advance(dev, ring);
 }
 
-static inline unsigned int bsd_ring_get_head(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(BSD_RING_HEAD) & HEAD_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_tail(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(BSD_RING_TAIL) & TAIL_ADDR;
-}
-
-static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	return I915_READ(BSD_RING_ACTHD);
-}
-
-static inline void bsd_ring_advance_ring(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	I915_WRITE(BSD_RING_TAIL, ring->tail);
-}
-
 static int init_bsd_ring(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			 struct intel_ring_buffer *ring)
 {
 	return init_ring_common(dev, ring);
 }
 
 static u32
 bsd_ring_add_request(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		struct drm_file *file_priv,
-		u32 flush_domains)
+		     struct intel_ring_buffer *ring,
+		     u32 flush_domains)
 {
 	u32 seqno;
 
@@ -443,40 +404,32 @@
 	return seqno;
 }
 
-static void bsd_setup_status_page(struct drm_device *dev,
-		struct  intel_ring_buffer *ring)
-{
-	drm_i915_private_t *dev_priv = dev->dev_private;
-	I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr);
-	I915_READ(BSD_HWS_PGA);
-}
-
 static void
 bsd_ring_get_user_irq(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+		      struct intel_ring_buffer *ring)
 {
 	/* do nothing */
 }
 static void
 bsd_ring_put_user_irq(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+		      struct intel_ring_buffer *ring)
 {
 	/* do nothing */
 }
 
 static u32
-bsd_ring_get_gem_seqno(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+bsd_ring_get_seqno(struct drm_device *dev,
+		   struct intel_ring_buffer *ring)
 {
 	return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
 }
 
 static int
 bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		struct drm_i915_gem_execbuffer2 *exec,
-		struct drm_clip_rect *cliprects,
-		uint64_t exec_offset)
+				 struct intel_ring_buffer *ring,
+				 struct drm_i915_gem_execbuffer2 *exec,
+				 struct drm_clip_rect *cliprects,
+				 uint64_t exec_offset)
 {
 	uint32_t exec_start;
 	exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
@@ -491,10 +444,10 @@
 
 static int
 render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		struct drm_i915_gem_execbuffer2 *exec,
-		struct drm_clip_rect *cliprects,
-		uint64_t exec_offset)
+				    struct intel_ring_buffer *ring,
+				    struct drm_i915_gem_execbuffer2 *exec,
+				    struct drm_clip_rect *cliprects,
+				    uint64_t exec_offset)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int nbox = exec->num_cliprects;
@@ -524,7 +477,7 @@
 			intel_ring_emit(dev, ring, 0);
 		} else {
 			intel_ring_begin(dev, ring, 4);
-			if (IS_I965G(dev)) {
+			if (INTEL_INFO(dev)->gen >= 4) {
 				intel_ring_emit(dev, ring,
 						MI_BATCH_BUFFER_START | (2 << 6)
 						| MI_BATCH_NON_SECURE_I965);
@@ -553,7 +506,7 @@
 }
 
 static void cleanup_status_page(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+				struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_gem_object *obj;
@@ -573,7 +526,7 @@
 }
 
 static int init_status_page(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			    struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_gem_object *obj;
@@ -603,7 +556,7 @@
 	ring->status_page.obj = obj;
 	memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
-	ring->setup_status_page(dev, ring);
+	intel_ring_setup_status_page(dev, ring);
 	DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
 			ring->name, ring->status_page.gfx_addr);
 
@@ -617,15 +570,17 @@
 	return ret;
 }
 
-
 int intel_init_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			   struct intel_ring_buffer *ring)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_gem_object *obj_priv;
 	struct drm_gem_object *obj;
 	int ret;
 
 	ring->dev = dev;
+	INIT_LIST_HEAD(&ring->active_list);
+	INIT_LIST_HEAD(&ring->request_list);
 
 	if (I915_NEED_GFX_HWS(dev)) {
 		ret = init_status_page(dev, ring);
@@ -642,7 +597,7 @@
 
 	ring->gem_object = obj;
 
-	ret = i915_gem_object_pin(obj, ring->alignment);
+	ret = i915_gem_object_pin(obj, PAGE_SIZE);
 	if (ret)
 		goto err_unref;
 
@@ -668,14 +623,12 @@
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		i915_kernel_lost_context(dev);
 	else {
-		ring->head = ring->get_head(dev, ring);
-		ring->tail = ring->get_tail(dev, ring);
+		ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
+		ring->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
 		ring->space = ring->head - (ring->tail + 8);
 		if (ring->space < 0)
 			ring->space += ring->size;
 	}
-	INIT_LIST_HEAD(&ring->active_list);
-	INIT_LIST_HEAD(&ring->request_list);
 	return ret;
 
 err_unmap:
@@ -691,7 +644,7 @@
 }
 
 void intel_cleanup_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			       struct intel_ring_buffer *ring)
 {
 	if (ring->gem_object == NULL)
 		return;
@@ -704,8 +657,8 @@
 	cleanup_status_page(dev, ring);
 }
 
-int intel_wrap_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+static int intel_wrap_ring_buffer(struct drm_device *dev,
+				  struct intel_ring_buffer *ring)
 {
 	unsigned int *virt;
 	int rem;
@@ -731,14 +684,15 @@
 }
 
 int intel_wait_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring, int n)
+			   struct intel_ring_buffer *ring, int n)
 {
 	unsigned long end;
+	drm_i915_private_t *dev_priv = dev->dev_private;
 
 	trace_i915_ring_wait_begin (dev);
 	end = jiffies + 3 * HZ;
 	do {
-		ring->head = ring->get_head(dev, ring);
+		ring->head = I915_READ_HEAD(ring) & HEAD_ADDR;
 		ring->space = ring->head - (ring->tail + 8);
 		if (ring->space < 0)
 			ring->space += ring->size;
@@ -760,7 +714,8 @@
 }
 
 void intel_ring_begin(struct drm_device *dev,
-		struct intel_ring_buffer *ring, int num_dwords)
+		      struct intel_ring_buffer *ring,
+		      int num_dwords)
 {
 	int n = 4*num_dwords;
 	if (unlikely(ring->tail + n > ring->size))
@@ -772,16 +727,16 @@
 }
 
 void intel_ring_advance(struct drm_device *dev,
-		struct intel_ring_buffer *ring)
+			struct intel_ring_buffer *ring)
 {
 	ring->tail &= ring->size - 1;
-	ring->advance_ring(dev, ring);
+	ring->set_tail(dev, ring, ring->tail);
 }
 
 void intel_fill_struct(struct drm_device *dev,
-		struct intel_ring_buffer *ring,
-		void *data,
-		unsigned int len)
+		       struct intel_ring_buffer *ring,
+		       void *data,
+		       unsigned int len)
 {
 	unsigned int *virt = ring->virtual_start + ring->tail;
 	BUG_ON((len&~(4-1)) != 0);
@@ -793,76 +748,136 @@
 	intel_ring_advance(dev, ring);
 }
 
-struct intel_ring_buffer render_ring = {
+static const struct intel_ring_buffer render_ring = {
 	.name			= "render ring",
-	.regs                   = {
-		.ctl = PRB0_CTL,
-		.head = PRB0_HEAD,
-		.tail = PRB0_TAIL,
-		.start = PRB0_START
-	},
-	.ring_flag		= I915_EXEC_RENDER,
+	.id			= RING_RENDER,
+	.mmio_base		= RENDER_RING_BASE,
 	.size			= 32 * PAGE_SIZE,
-	.alignment		= PAGE_SIZE,
-	.virtual_start		= NULL,
-	.dev			= NULL,
-	.gem_object		= NULL,
-	.head			= 0,
-	.tail			= 0,
-	.space			= 0,
-	.user_irq_refcount	= 0,
-	.irq_gem_seqno		= 0,
-	.waiting_gem_seqno	= 0,
-	.setup_status_page	= render_setup_status_page,
 	.init			= init_render_ring,
-	.get_head		= render_ring_get_head,
-	.get_tail		= render_ring_get_tail,
-	.get_active_head	= render_ring_get_active_head,
-	.advance_ring		= render_ring_advance_ring,
+	.set_tail		= ring_set_tail,
 	.flush			= render_ring_flush,
 	.add_request		= render_ring_add_request,
-	.get_gem_seqno		= render_ring_get_gem_seqno,
+	.get_seqno		= render_ring_get_seqno,
 	.user_irq_get		= render_ring_get_user_irq,
 	.user_irq_put		= render_ring_put_user_irq,
 	.dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer,
-	.status_page		= {NULL, 0, NULL},
-	.map			= {0,}
 };
 
 /* ring buffer for bit-stream decoder */
 
-struct intel_ring_buffer bsd_ring = {
+static const struct intel_ring_buffer bsd_ring = {
 	.name                   = "bsd ring",
-	.regs			= {
-		.ctl = BSD_RING_CTL,
-		.head = BSD_RING_HEAD,
-		.tail = BSD_RING_TAIL,
-		.start = BSD_RING_START
-	},
-	.ring_flag		= I915_EXEC_BSD,
+	.id			= RING_BSD,
+	.mmio_base		= BSD_RING_BASE,
 	.size			= 32 * PAGE_SIZE,
-	.alignment		= PAGE_SIZE,
-	.virtual_start		= NULL,
-	.dev			= NULL,
-	.gem_object		= NULL,
-	.head			= 0,
-	.tail			= 0,
-	.space			= 0,
-	.user_irq_refcount	= 0,
-	.irq_gem_seqno		= 0,
-	.waiting_gem_seqno	= 0,
-	.setup_status_page	= bsd_setup_status_page,
 	.init			= init_bsd_ring,
-	.get_head		= bsd_ring_get_head,
-	.get_tail		= bsd_ring_get_tail,
-	.get_active_head	= bsd_ring_get_active_head,
-	.advance_ring		= bsd_ring_advance_ring,
+	.set_tail		= ring_set_tail,
 	.flush			= bsd_ring_flush,
 	.add_request		= bsd_ring_add_request,
-	.get_gem_seqno		= bsd_ring_get_gem_seqno,
+	.get_seqno		= bsd_ring_get_seqno,
 	.user_irq_get		= bsd_ring_get_user_irq,
 	.user_irq_put		= bsd_ring_put_user_irq,
 	.dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer,
-	.status_page		= {NULL, 0, NULL},
-	.map			= {0,}
 };
+
+
+static void gen6_bsd_ring_set_tail(struct drm_device *dev,
+				   struct intel_ring_buffer *ring,
+				   u32 value)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+
+       /* Every tail move must follow the sequence below */
+       I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+	       GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+	       GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_DISABLE);
+       I915_WRITE(GEN6_BSD_RNCID, 0x0);
+
+       if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
+                               GEN6_BSD_SLEEP_PSMI_CONTROL_IDLE_INDICATOR) == 0,
+                       50))
+               DRM_ERROR("timed out waiting for IDLE Indicator\n");
+
+       I915_WRITE_TAIL(ring, value);
+       I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
+	       GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_MODIFY_MASK |
+	       GEN6_BSD_SLEEP_PSMI_CONTROL_RC_ILDL_MESSAGE_ENABLE);
+}
+
+static void gen6_bsd_ring_flush(struct drm_device *dev,
+				struct intel_ring_buffer *ring,
+				u32 invalidate_domains,
+				u32 flush_domains)
+{
+       intel_ring_begin(dev, ring, 4);
+       intel_ring_emit(dev, ring, MI_FLUSH_DW);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_emit(dev, ring, 0);
+       intel_ring_advance(dev, ring);
+}
+
+static int
+gen6_bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
+				      struct intel_ring_buffer *ring,
+				      struct drm_i915_gem_execbuffer2 *exec,
+				      struct drm_clip_rect *cliprects,
+				      uint64_t exec_offset)
+{
+       uint32_t exec_start;
+
+       exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+
+       intel_ring_begin(dev, ring, 2);
+       intel_ring_emit(dev, ring,
+		       MI_BATCH_BUFFER_START | MI_BATCH_NON_SECURE_I965);
+       /* bit0-7 is the length on GEN6+ */
+       intel_ring_emit(dev, ring, exec_start);
+       intel_ring_advance(dev, ring);
+
+       return 0;
+}
+
+/* ring buffer for Video Codec for Gen6+ */
+static const struct intel_ring_buffer gen6_bsd_ring = {
+       .name			= "gen6 bsd ring",
+       .id			= RING_BSD,
+       .mmio_base		= GEN6_BSD_RING_BASE,
+       .size			= 32 * PAGE_SIZE,
+       .init			= init_bsd_ring,
+       .set_tail		= gen6_bsd_ring_set_tail,
+       .flush			= gen6_bsd_ring_flush,
+       .add_request		= bsd_ring_add_request,
+       .get_seqno		= bsd_ring_get_seqno,
+       .user_irq_get		= bsd_ring_get_user_irq,
+       .user_irq_put		= bsd_ring_put_user_irq,
+       .dispatch_gem_execbuffer	= gen6_bsd_ring_dispatch_gem_execbuffer,
+};
+
+int intel_init_render_ring_buffer(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	dev_priv->render_ring = render_ring;
+
+	if (!I915_NEED_GFX_HWS(dev)) {
+		dev_priv->render_ring.status_page.page_addr
+			= dev_priv->status_page_dmah->vaddr;
+		memset(dev_priv->render_ring.status_page.page_addr,
+				0, PAGE_SIZE);
+	}
+
+	return intel_init_ring_buffer(dev, &dev_priv->render_ring);
+}
+
+int intel_init_bsd_ring_buffer(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	if (IS_GEN6(dev))
+		dev_priv->bsd_ring = gen6_bsd_ring;
+	else
+		dev_priv->bsd_ring = bsd_ring;
+
+	return intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 525e7d3..9725f78 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -7,25 +7,31 @@
 	struct		drm_gem_object *obj;
 };
 
+#define I915_READ_TAIL(ring) I915_READ(RING_TAIL(ring->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL(ring->mmio_base), val)
+#define I915_READ_START(ring) I915_READ(RING_START(ring->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START(ring->mmio_base), val)
+#define I915_READ_HEAD(ring) I915_READ(RING_HEAD(ring->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD(ring->mmio_base), val)
+#define I915_READ_CTL(ring) I915_READ(RING_CTL(ring->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL(ring->mmio_base), val)
+
 struct drm_i915_gem_execbuffer2;
 struct  intel_ring_buffer {
 	const char	*name;
-	struct		ring_regs {
-			u32 ctl;
-			u32 head;
-			u32 tail;
-			u32 start;
-	} regs;
-	unsigned int	ring_flag;
+	enum intel_ring_id {
+		RING_RENDER = 0x1,
+		RING_BSD = 0x2,
+	} id;
+	u32		mmio_base;
 	unsigned long	size;
-	unsigned int	alignment;
 	void		*virtual_start;
 	struct		drm_device *dev;
 	struct		drm_gem_object *gem_object;
 
 	unsigned int	head;
 	unsigned int	tail;
-	unsigned int	space;
+	int		space;
 	struct intel_hw_status_page status_page;
 
 	u32		irq_gem_seqno;		/* last seq seem at irq time */
@@ -35,30 +41,22 @@
 			struct intel_ring_buffer *ring);
 	void		(*user_irq_put)(struct drm_device *dev,
 			struct intel_ring_buffer *ring);
-	void		(*setup_status_page)(struct drm_device *dev,
-			struct	intel_ring_buffer *ring);
 
 	int		(*init)(struct drm_device *dev,
 			struct intel_ring_buffer *ring);
 
-	unsigned int	(*get_head)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
-	unsigned int	(*get_tail)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
-	unsigned int	(*get_active_head)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
-	void		(*advance_ring)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
+	void		(*set_tail)(struct drm_device *dev,
+				    struct intel_ring_buffer *ring,
+				    u32 value);
 	void		(*flush)(struct drm_device *dev,
 			struct intel_ring_buffer *ring,
 			u32	invalidate_domains,
 			u32	flush_domains);
 	u32		(*add_request)(struct drm_device *dev,
 			struct intel_ring_buffer *ring,
-			struct drm_file *file_priv,
 			u32 flush_domains);
-	u32		(*get_gem_seqno)(struct drm_device *dev,
-			struct intel_ring_buffer *ring);
+	u32		(*get_seqno)(struct drm_device *dev,
+				     struct intel_ring_buffer *ring);
 	int		(*dispatch_gem_execbuffer)(struct drm_device *dev,
 			struct intel_ring_buffer *ring,
 			struct drm_i915_gem_execbuffer2 *exec,
@@ -83,6 +81,11 @@
 	 */
 	struct list_head request_list;
 
+	/**
+	 * Do we have some not yet emitted requests outstanding?
+	 */
+	bool outstanding_lazy_request;
+
 	wait_queue_head_t irq_queue;
 	drm_local_map_t map;
 };
@@ -96,15 +99,13 @@
 }
 
 int intel_init_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring);
+			   struct intel_ring_buffer *ring);
 void intel_cleanup_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring);
+			       struct intel_ring_buffer *ring);
 int intel_wait_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring, int n);
-int intel_wrap_ring_buffer(struct drm_device *dev,
-		struct intel_ring_buffer *ring);
+			   struct intel_ring_buffer *ring, int n);
 void intel_ring_begin(struct drm_device *dev,
-		struct intel_ring_buffer *ring, int n);
+		      struct intel_ring_buffer *ring, int n);
 
 static inline void intel_ring_emit(struct drm_device *dev,
 				   struct intel_ring_buffer *ring,
@@ -125,7 +126,12 @@
 u32 intel_ring_get_seqno(struct drm_device *dev,
 		struct intel_ring_buffer *ring);
 
-extern struct intel_ring_buffer render_ring;
-extern struct intel_ring_buffer bsd_ring;
+int intel_init_render_ring_buffer(struct drm_device *dev);
+int intel_init_bsd_ring_buffer(struct drm_device *dev);
+
+u32 intel_ring_get_active_head(struct drm_device *dev,
+			       struct intel_ring_buffer *ring);
+void intel_ring_setup_status_page(struct drm_device *dev,
+				  struct intel_ring_buffer *ring);
 
 #endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index e8e902d..a84224f 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -65,8 +65,11 @@
 struct intel_sdvo {
 	struct intel_encoder base;
 
+	struct i2c_adapter *i2c;
 	u8 slave_addr;
 
+	struct i2c_adapter ddc;
+
 	/* Register for the SDVO device: SDVOB or SDVOC */
 	int sdvo_reg;
 
@@ -106,16 +109,12 @@
 	bool is_hdmi;
 
 	/**
-	 * This is set if we detect output of sdvo device as LVDS.
+	 * This is set if we detect output of sdvo device as LVDS and
+	 * have a valid fixed mode to use with the panel.
 	 */
 	bool is_lvds;
 
 	/**
-	 * This is sdvo flags for input timing.
-	 */
-	uint8_t sdvo_flags;
-
-	/**
 	 * This is sdvo fixed pannel mode pointer
 	 */
 	struct drm_display_mode *sdvo_lvds_fixed_mode;
@@ -129,9 +128,8 @@
 	/* DDC bus used by this SDVO encoder */
 	uint8_t ddc_bus;
 
-	/* Mac mini hack -- use the same DDC as the analog connector */
-	struct i2c_adapter *analog_ddc_bus;
-
+	/* Input timings for adjusted_mode */
+	struct intel_sdvo_dtd input_dtd;
 };
 
 struct intel_sdvo_connector {
@@ -186,9 +184,15 @@
 	u32	cur_dot_crawl,	max_dot_crawl;
 };
 
-static struct intel_sdvo *enc_to_intel_sdvo(struct drm_encoder *encoder)
+static struct intel_sdvo *to_intel_sdvo(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_sdvo, base);
+	return container_of(encoder, struct intel_sdvo, base.base);
+}
+
+static struct intel_sdvo *intel_attached_sdvo(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_sdvo, base);
 }
 
 static struct intel_sdvo_connector *to_intel_sdvo_connector(struct drm_connector *connector)
@@ -213,7 +217,7 @@
  */
 static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val)
 {
-	struct drm_device *dev = intel_sdvo->base.enc.dev;
+	struct drm_device *dev = intel_sdvo->base.base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 bval = val, cval = val;
 	int i;
@@ -245,49 +249,29 @@
 
 static bool intel_sdvo_read_byte(struct intel_sdvo *intel_sdvo, u8 addr, u8 *ch)
 {
-	u8 out_buf[2] = { addr, 0 };
-	u8 buf[2];
 	struct i2c_msg msgs[] = {
 		{
-			.addr = intel_sdvo->slave_addr >> 1,
+			.addr = intel_sdvo->slave_addr,
 			.flags = 0,
 			.len = 1,
-			.buf = out_buf,
+			.buf = &addr,
 		},
 		{
-			.addr = intel_sdvo->slave_addr >> 1,
+			.addr = intel_sdvo->slave_addr,
 			.flags = I2C_M_RD,
 			.len = 1,
-			.buf = buf,
+			.buf = ch,
 		}
 	};
 	int ret;
 
-	if ((ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 2)) == 2)
-	{
-		*ch = buf[0];
+	if ((ret = i2c_transfer(intel_sdvo->i2c, msgs, 2)) == 2)
 		return true;
-	}
 
 	DRM_DEBUG_KMS("i2c transfer returned %d\n", ret);
 	return false;
 }
 
-static bool intel_sdvo_write_byte(struct intel_sdvo *intel_sdvo, int addr, u8 ch)
-{
-	u8 out_buf[2] = { addr, ch };
-	struct i2c_msg msgs[] = {
-		{
-			.addr = intel_sdvo->slave_addr >> 1,
-			.flags = 0,
-			.len = 2,
-			.buf = out_buf,
-		}
-	};
-
-	return i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 1) == 1;
-}
-
 #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
 /** Mapping of command numbers to names, for debug output */
 static const struct _sdvo_cmd_name {
@@ -432,22 +416,6 @@
 	DRM_LOG_KMS("\n");
 }
 
-static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
-				 const void *args, int args_len)
-{
-	int i;
-
-	intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
-
-	for (i = 0; i < args_len; i++) {
-		if (!intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0 - i,
-					   ((u8*)args)[i]))
-			return false;
-	}
-
-	return intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_OPCODE, cmd);
-}
-
 static const char *cmd_status_names[] = {
 	"Power on",
 	"Success",
@@ -458,54 +426,115 @@
 	"Scaling not supported"
 };
 
-static void intel_sdvo_debug_response(struct intel_sdvo *intel_sdvo,
-				      void *response, int response_len,
-				      u8 status)
+static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
+				 const void *args, int args_len)
 {
-	int i;
+	u8 buf[args_len*2 + 2], status;
+	struct i2c_msg msgs[args_len + 3];
+	int i, ret;
 
-	DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
-	for (i = 0; i < response_len; i++)
-		DRM_LOG_KMS("%02X ", ((u8 *)response)[i]);
-	for (; i < 8; i++)
-		DRM_LOG_KMS("   ");
-	if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-		DRM_LOG_KMS("(%s)", cmd_status_names[status]);
-	else
-		DRM_LOG_KMS("(??? %d)", status);
-	DRM_LOG_KMS("\n");
+	intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
+
+	for (i = 0; i < args_len; i++) {
+		msgs[i].addr = intel_sdvo->slave_addr;
+		msgs[i].flags = 0;
+		msgs[i].len = 2;
+		msgs[i].buf = buf + 2 *i;
+		buf[2*i + 0] = SDVO_I2C_ARG_0 - i;
+		buf[2*i + 1] = ((u8*)args)[i];
+	}
+	msgs[i].addr = intel_sdvo->slave_addr;
+	msgs[i].flags = 0;
+	msgs[i].len = 2;
+	msgs[i].buf = buf + 2*i;
+	buf[2*i + 0] = SDVO_I2C_OPCODE;
+	buf[2*i + 1] = cmd;
+
+	/* the following two are to read the response */
+	status = SDVO_I2C_CMD_STATUS;
+	msgs[i+1].addr = intel_sdvo->slave_addr;
+	msgs[i+1].flags = 0;
+	msgs[i+1].len = 1;
+	msgs[i+1].buf = &status;
+
+	msgs[i+2].addr = intel_sdvo->slave_addr;
+	msgs[i+2].flags = I2C_M_RD;
+	msgs[i+2].len = 1;
+	msgs[i+2].buf = &status;
+
+	ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
+		return false;
+	}
+	if (ret != i+3) {
+		/* failure in I2C transfer */
+		DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
+		return false;
+	}
+
+	i = 3;
+	while (status == SDVO_CMD_STATUS_PENDING && i--) {
+		if (!intel_sdvo_read_byte(intel_sdvo,
+					  SDVO_I2C_CMD_STATUS,
+					  &status))
+			return false;
+	}
+	if (status != SDVO_CMD_STATUS_SUCCESS) {
+		DRM_DEBUG_KMS("command returns response %s [%d]\n",
+			      status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP ? cmd_status_names[status] : "???",
+			      status);
+		return false;
+	}
+
+	return true;
 }
 
 static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
 				     void *response, int response_len)
 {
-	int i;
+	u8 retry = 5;
 	u8 status;
-	u8 retry = 50;
+	int i;
 
-	while (retry--) {
-		/* Read the command response */
-		for (i = 0; i < response_len; i++) {
-			if (!intel_sdvo_read_byte(intel_sdvo,
-						  SDVO_I2C_RETURN_0 + i,
-						  &((u8 *)response)[i]))
-				return false;
-		}
-
-		/* read the return status */
-		if (!intel_sdvo_read_byte(intel_sdvo, SDVO_I2C_CMD_STATUS,
+	/*
+	 * The documentation states that all commands will be
+	 * processed within 15µs, and that we need only poll
+	 * the status byte a maximum of 3 times in order for the
+	 * command to be complete.
+	 *
+	 * Check 5 times in case the hardware failed to read the docs.
+	 */
+	do {
+		if (!intel_sdvo_read_byte(intel_sdvo,
+					  SDVO_I2C_CMD_STATUS,
 					  &status))
 			return false;
+	} while (status == SDVO_CMD_STATUS_PENDING && --retry);
 
-		intel_sdvo_debug_response(intel_sdvo, response, response_len,
-					  status);
-		if (status != SDVO_CMD_STATUS_PENDING)
-			break;
+	DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
+	if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
+		DRM_LOG_KMS("(%s)", cmd_status_names[status]);
+	else
+		DRM_LOG_KMS("(??? %d)", status);
 
-		mdelay(50);
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		goto log_fail;
+
+	/* Read the command response */
+	for (i = 0; i < response_len; i++) {
+		if (!intel_sdvo_read_byte(intel_sdvo,
+					  SDVO_I2C_RETURN_0 + i,
+					  &((u8 *)response)[i]))
+			goto log_fail;
+		DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);
 	}
+	DRM_LOG_KMS("\n");
+	return true;
 
-	return status == SDVO_CMD_STATUS_SUCCESS;
+log_fail:
+	DRM_LOG_KMS("\n");
+	return false;
 }
 
 static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
@@ -518,71 +547,17 @@
 		return 4;
 }
 
-/**
- * Try to read the response after issuie the DDC switch command. But it
- * is noted that we must do the action of reading response and issuing DDC
- * switch command in one I2C transaction. Otherwise when we try to start
- * another I2C transaction after issuing the DDC bus switch, it will be
- * switched to the internal SDVO register.
- */
-static void intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
-					      u8 target)
+static bool intel_sdvo_set_control_bus_switch(struct intel_sdvo *intel_sdvo,
+					      u8 ddc_bus)
 {
-	u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
-	struct i2c_msg msgs[] = {
-		{
-			.addr = intel_sdvo->slave_addr >> 1,
-			.flags = 0,
-			.len = 2,
-			.buf = out_buf,
-		},
-		/* the following two are to read the response */
-		{
-			.addr = intel_sdvo->slave_addr >> 1,
-			.flags = 0,
-			.len = 1,
-			.buf = cmd_buf,
-		},
-		{
-			.addr = intel_sdvo->slave_addr >> 1,
-			.flags = I2C_M_RD,
-			.len = 1,
-			.buf = ret_value,
-		},
-	};
-
-	intel_sdvo_debug_write(intel_sdvo, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
-					&target, 1);
-	/* write the DDC switch command argument */
-	intel_sdvo_write_byte(intel_sdvo, SDVO_I2C_ARG_0, target);
-
-	out_buf[0] = SDVO_I2C_OPCODE;
-	out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
-	cmd_buf[0] = SDVO_I2C_CMD_STATUS;
-	cmd_buf[1] = 0;
-	ret_value[0] = 0;
-	ret_value[1] = 0;
-
-	ret = i2c_transfer(intel_sdvo->base.i2c_bus, msgs, 3);
-	if (ret != 3) {
-		/* failure in I2C transfer */
-		DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
-		return;
-	}
-	if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
-		DRM_DEBUG_KMS("DDC switch command returns response %d\n",
-					ret_value[0]);
-		return;
-	}
-	return;
+	return intel_sdvo_write_cmd(intel_sdvo,
+				    SDVO_CMD_SET_CONTROL_BUS_SWITCH,
+				    &ddc_bus, 1);
 }
 
 static bool intel_sdvo_set_value(struct intel_sdvo *intel_sdvo, u8 cmd, const void *data, int len)
 {
-	if (!intel_sdvo_write_cmd(intel_sdvo, cmd, data, len))
-		return false;
-
-	return intel_sdvo_read_response(intel_sdvo, NULL, 0);
+	return intel_sdvo_write_cmd(intel_sdvo, cmd, data, len);
 }
 
 static bool
@@ -1022,8 +997,6 @@
 					struct drm_display_mode *mode,
 					struct drm_display_mode *adjusted_mode)
 {
-	struct intel_sdvo_dtd input_dtd;
-
 	/* Reset the input timing to the screen. Assume always input 0. */
 	if (!intel_sdvo_set_target_input(intel_sdvo))
 		return false;
@@ -1035,14 +1008,12 @@
 		return false;
 
 	if (!intel_sdvo_get_preferred_input_timing(intel_sdvo,
-						   &input_dtd))
+						   &intel_sdvo->input_dtd))
 		return false;
 
-	intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
-	intel_sdvo->sdvo_flags = input_dtd.part2.sdvo_flags;
+	intel_sdvo_get_mode_from_dtd(adjusted_mode, &intel_sdvo->input_dtd);
 
 	drm_mode_set_crtcinfo(adjusted_mode, 0);
-	mode->clock = adjusted_mode->clock;
 	return true;
 }
 
@@ -1050,7 +1021,8 @@
 				  struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
 {
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+	int multiplier;
 
 	/* We need to construct preferred input timings based on our
 	 * output timings.  To do that, we have to set the output
@@ -1065,10 +1037,8 @@
 							     mode,
 							     adjusted_mode);
 	} else if (intel_sdvo->is_lvds) {
-		drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode, 0);
-
 		if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
-							    intel_sdvo->sdvo_lvds_fixed_mode))
+							     intel_sdvo->sdvo_lvds_fixed_mode))
 			return false;
 
 		(void) intel_sdvo_set_input_timings_for_mode(intel_sdvo,
@@ -1077,9 +1047,10 @@
 	}
 
 	/* Make the CRTC code factor in the SDVO pixel multiplier.  The
-	 * SDVO device will be told of the multiplier during mode_set.
+	 * SDVO device will factor out the multiplier during mode_set.
 	 */
-	adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+	multiplier = intel_sdvo_get_pixel_multiplier(adjusted_mode);
+	intel_mode_set_pixel_multiplier(adjusted_mode, multiplier);
 
 	return true;
 }
@@ -1092,11 +1063,12 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_crtc *crtc = encoder->crtc;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-	u32 sdvox = 0;
-	int sdvo_pixel_multiply, rate;
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
+	u32 sdvox;
 	struct intel_sdvo_in_out_map in_out;
 	struct intel_sdvo_dtd input_dtd;
+	int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+	int rate;
 
 	if (!mode)
 		return;
@@ -1114,28 +1086,23 @@
 			     SDVO_CMD_SET_IN_OUT_MAP,
 			     &in_out, sizeof(in_out));
 
-	if (intel_sdvo->is_hdmi) {
-		if (!intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
-			return;
-
-		sdvox |= SDVO_AUDIO_ENABLE;
-	}
+	/* Set the output timings to the screen */
+	if (!intel_sdvo_set_target_output(intel_sdvo,
+					  intel_sdvo->attached_output))
+		return;
 
 	/* We have tried to get input timing in mode_fixup, and filled into
-	   adjusted_mode */
-	intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-	if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
-		input_dtd.part2.sdvo_flags = intel_sdvo->sdvo_flags;
-
-	/* If it's a TV, we already set the output timing in mode_fixup.
-	 * Otherwise, the output timing is equal to the input timing.
+	 * adjusted_mode.
 	 */
-	if (!intel_sdvo->is_tv && !intel_sdvo->is_lvds) {
+	if (intel_sdvo->is_tv || intel_sdvo->is_lvds) {
+		input_dtd = intel_sdvo->input_dtd;
+	} else {
 		/* Set the output timing to the screen */
 		if (!intel_sdvo_set_target_output(intel_sdvo,
 						  intel_sdvo->attached_output))
 			return;
 
+		intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
 		(void) intel_sdvo_set_output_timing(intel_sdvo, &input_dtd);
 	}
 
@@ -1143,31 +1110,18 @@
 	if (!intel_sdvo_set_target_input(intel_sdvo))
 		return;
 
-	if (intel_sdvo->is_tv) {
-		if (!intel_sdvo_set_tv_format(intel_sdvo))
-			return;
-	}
+	if (intel_sdvo->is_hdmi &&
+	    !intel_sdvo_set_avi_infoframe(intel_sdvo, mode))
+		return;
 
-	/* We would like to use intel_sdvo_create_preferred_input_timing() to
-	 * provide the device with a timing it can support, if it supports that
-	 * feature.  However, presumably we would need to adjust the CRTC to
-	 * output the preferred timing, and we don't support that currently.
-	 */
-#if 0
-	success = intel_sdvo_create_preferred_input_timing(encoder, clock,
-							   width, height);
-	if (success) {
-		struct intel_sdvo_dtd *input_dtd;
+	if (intel_sdvo->is_tv &&
+	    !intel_sdvo_set_tv_format(intel_sdvo))
+		return;
 
-		intel_sdvo_get_preferred_input_timing(encoder, &input_dtd);
-		intel_sdvo_set_input_timing(encoder, &input_dtd);
-	}
-#else
 	(void) intel_sdvo_set_input_timing(intel_sdvo, &input_dtd);
-#endif
 
-	sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
-	switch (sdvo_pixel_multiply) {
+	switch (pixel_multiplier) {
+	default:
 	case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
 	case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
 	case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1176,14 +1130,14 @@
 		return;
 
 	/* Set the SDVO control regs. */
-	if (IS_I965G(dev)) {
-		sdvox |= SDVO_BORDER_ENABLE;
+	if (INTEL_INFO(dev)->gen >= 4) {
+		sdvox = SDVO_BORDER_ENABLE;
 		if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
 			sdvox |= SDVO_VSYNC_ACTIVE_HIGH;
 		if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
 			sdvox |= SDVO_HSYNC_ACTIVE_HIGH;
 	} else {
-		sdvox |= I915_READ(intel_sdvo->sdvo_reg);
+		sdvox = I915_READ(intel_sdvo->sdvo_reg);
 		switch (intel_sdvo->sdvo_reg) {
 		case SDVOB:
 			sdvox &= SDVOB_PRESERVE_MASK;
@@ -1196,16 +1150,18 @@
 	}
 	if (intel_crtc->pipe == 1)
 		sdvox |= SDVO_PIPE_B_SELECT;
+	if (intel_sdvo->is_hdmi)
+		sdvox |= SDVO_AUDIO_ENABLE;
 
-	if (IS_I965G(dev)) {
+	if (INTEL_INFO(dev)->gen >= 4) {
 		/* done in crtc_mode_set as the dpll_md reg must be written early */
 	} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
 		/* done in crtc_mode_set as it lives inside the dpll register */
 	} else {
-		sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
+		sdvox |= (pixel_multiplier - 1) << SDVO_PORT_MULTIPLY_SHIFT;
 	}
 
-	if (intel_sdvo->sdvo_flags & SDVO_NEED_TO_STALL)
+	if (input_dtd.part2.sdvo_flags & SDVO_NEED_TO_STALL)
 		sdvox |= SDVO_STALL_SELECT;
 	intel_sdvo_write_sdvox(intel_sdvo, sdvox);
 }
@@ -1214,7 +1170,7 @@
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
 	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
 	u32 temp;
 
@@ -1260,8 +1216,7 @@
 static int intel_sdvo_mode_valid(struct drm_connector *connector,
 				 struct drm_display_mode *mode)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 
 	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
 		return MODE_NO_DBLESCAN;
@@ -1285,7 +1240,38 @@
 
 static bool intel_sdvo_get_capabilities(struct intel_sdvo *intel_sdvo, struct intel_sdvo_caps *caps)
 {
-	return intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_DEVICE_CAPS, caps, sizeof(*caps));
+	if (!intel_sdvo_get_value(intel_sdvo,
+				  SDVO_CMD_GET_DEVICE_CAPS,
+				  caps, sizeof(*caps)))
+		return false;
+
+	DRM_DEBUG_KMS("SDVO capabilities:\n"
+		      "  vendor_id: %d\n"
+		      "  device_id: %d\n"
+		      "  device_rev_id: %d\n"
+		      "  sdvo_version_major: %d\n"
+		      "  sdvo_version_minor: %d\n"
+		      "  sdvo_inputs_mask: %d\n"
+		      "  smooth_scaling: %d\n"
+		      "  sharp_scaling: %d\n"
+		      "  up_scaling: %d\n"
+		      "  down_scaling: %d\n"
+		      "  stall_support: %d\n"
+		      "  output_flags: %d\n",
+		      caps->vendor_id,
+		      caps->device_id,
+		      caps->device_rev_id,
+		      caps->sdvo_version_major,
+		      caps->sdvo_version_minor,
+		      caps->sdvo_inputs_mask,
+		      caps->smooth_scaling,
+		      caps->sharp_scaling,
+		      caps->up_scaling,
+		      caps->down_scaling,
+		      caps->stall_support,
+		      caps->output_flags);
+
+	return true;
 }
 
 /* No use! */
@@ -1389,22 +1375,33 @@
 	return (caps > 1);
 }
 
+static struct edid *
+intel_sdvo_get_edid(struct drm_connector *connector)
+{
+	struct intel_sdvo *sdvo = intel_attached_sdvo(connector);
+	return drm_get_edid(connector, &sdvo->ddc);
+}
+
 static struct drm_connector *
 intel_find_analog_connector(struct drm_device *dev)
 {
 	struct drm_connector *connector;
-	struct drm_encoder *encoder;
-	struct intel_sdvo *intel_sdvo;
+	struct intel_sdvo *encoder;
 
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		intel_sdvo = enc_to_intel_sdvo(encoder);
-		if (intel_sdvo->base.type == INTEL_OUTPUT_ANALOG) {
-			list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-				if (encoder == intel_attached_encoder(connector))
+	list_for_each_entry(encoder,
+			    &dev->mode_config.encoder_list,
+			    base.base.head) {
+		if (encoder->base.type == INTEL_OUTPUT_ANALOG) {
+			list_for_each_entry(connector,
+					    &dev->mode_config.connector_list,
+					    head) {
+				if (&encoder->base ==
+				    intel_attached_encoder(connector))
 					return connector;
 			}
 		}
 	}
+
 	return NULL;
 }
 
@@ -1424,65 +1421,66 @@
 	return true;
 }
 
+/* Mac mini hack -- use the same DDC as the analog connector */
+static struct edid *
+intel_sdvo_get_analog_edid(struct drm_connector *connector)
+{
+	struct drm_i915_private *dev_priv = connector->dev->dev_private;
+
+	if (!intel_analog_is_connected(connector->dev))
+		return NULL;
+
+	return drm_get_edid(connector, &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+}
+
 enum drm_connector_status
 intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
-	enum drm_connector_status status = connector_status_connected;
-	struct edid *edid = NULL;
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
+	enum drm_connector_status status;
+	struct edid *edid;
 
-	edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
+	edid = intel_sdvo_get_edid(connector);
 
-	/* This is only applied to SDVO cards with multiple outputs */
 	if (edid == NULL && intel_sdvo_multifunc_encoder(intel_sdvo)) {
-		uint8_t saved_ddc, temp_ddc;
-		saved_ddc = intel_sdvo->ddc_bus;
-		temp_ddc = intel_sdvo->ddc_bus >> 1;
+		u8 ddc, saved_ddc = intel_sdvo->ddc_bus;
+
 		/*
 		 * Don't use the 1 as the argument of DDC bus switch to get
 		 * the EDID. It is used for SDVO SPD ROM.
 		 */
-		while(temp_ddc > 1) {
-			intel_sdvo->ddc_bus = temp_ddc;
-			edid = drm_get_edid(connector, intel_sdvo->base.ddc_bus);
-			if (edid) {
-				/*
-				 * When we can get the EDID, maybe it is the
-				 * correct DDC bus. Update it.
-				 */
-				intel_sdvo->ddc_bus = temp_ddc;
+		for (ddc = intel_sdvo->ddc_bus >> 1; ddc > 1; ddc >>= 1) {
+			intel_sdvo->ddc_bus = ddc;
+			edid = intel_sdvo_get_edid(connector);
+			if (edid)
 				break;
-			}
-			temp_ddc >>= 1;
 		}
+		/*
+		 * If we found the EDID on the other bus,
+		 * assume that is the correct DDC bus.
+		 */
 		if (edid == NULL)
 			intel_sdvo->ddc_bus = saved_ddc;
 	}
-	/* when there is no edid and no monitor is connected with VGA
-	 * port, try to use the CRT ddc to read the EDID for DVI-connector
+
+	/*
+	 * When there is no edid and no monitor is connected with VGA
+	 * port, try to use the CRT ddc to read the EDID for DVI-connector.
 	 */
-	if (edid == NULL && intel_sdvo->analog_ddc_bus &&
-	    !intel_analog_is_connected(connector->dev))
-		edid = drm_get_edid(connector, intel_sdvo->analog_ddc_bus);
+	if (edid == NULL)
+		edid = intel_sdvo_get_analog_edid(connector);
 
+	status = connector_status_unknown;
 	if (edid != NULL) {
-		bool is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL);
-		bool need_digital = !!(intel_sdvo_connector->output_flag & SDVO_TMDS_MASK);
-
 		/* DDC bus is shared, match EDID to connector type */
-		if (is_digital && need_digital)
+		if (edid->input & DRM_EDID_INPUT_DIGITAL) {
+			status = connector_status_connected;
 			intel_sdvo->is_hdmi = drm_detect_hdmi_monitor(edid);
-		else if (is_digital != need_digital)
-			status = connector_status_disconnected;
-
+		}
 		connector->display_info.raw_edid = NULL;
-	} else
-		status = connector_status_disconnected;
+		kfree(edid);
+	}
 	
-	kfree(edid);
-
 	return status;
 }
 
@@ -1490,13 +1488,12 @@
 intel_sdvo_detect(struct drm_connector *connector, bool force)
 {
 	uint16_t response;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
 	enum drm_connector_status ret;
 
 	if (!intel_sdvo_write_cmd(intel_sdvo,
-			     SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
+				  SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0))
 		return connector_status_unknown;
 	if (intel_sdvo->is_tv) {
 		/* add 30ms delay when the output type is SDVO-TV */
@@ -1505,7 +1502,9 @@
 	if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
 		return connector_status_unknown;
 
-	DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);
+	DRM_DEBUG_KMS("SDVO response %d %d [%x]\n",
+		      response & 0xff, response >> 8,
+		      intel_sdvo_connector->output_flag);
 
 	if (response == 0)
 		return connector_status_disconnected;
@@ -1538,12 +1537,10 @@
 
 static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-	int num_modes;
+	struct edid *edid;
 
 	/* set the bus switch and get the modes */
-	num_modes = intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+	edid = intel_sdvo_get_edid(connector);
 
 	/*
 	 * Mac mini hack.  On this device, the DVI-I connector shares one DDC
@@ -1551,12 +1548,14 @@
 	 * DDC fails, check to see if the analog output is disconnected, in
 	 * which case we'll look there for the digital DDC data.
 	 */
-	if (num_modes == 0 &&
-	    intel_sdvo->analog_ddc_bus &&
-	    !intel_analog_is_connected(connector->dev)) {
-		/* Switch to the analog ddc bus and try that
-		 */
-		(void) intel_ddc_get_modes(connector, intel_sdvo->analog_ddc_bus);
+	if (edid == NULL)
+		edid = intel_sdvo_get_analog_edid(connector);
+
+	if (edid != NULL) {
+		drm_mode_connector_update_edid_property(connector, edid);
+		drm_add_edid_modes(connector, edid);
+		connector->display_info.raw_edid = NULL;
+		kfree(edid);
 	}
 }
 
@@ -1627,8 +1626,7 @@
 
 static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct intel_sdvo_sdtv_resolution_request tv_res;
 	uint32_t reply = 0, format_map = 0;
 	int i;
@@ -1644,7 +1642,8 @@
 		return;
 
 	BUILD_BUG_ON(sizeof(tv_res) != 3);
-	if (!intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
+	if (!intel_sdvo_write_cmd(intel_sdvo,
+				  SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
 				  &tv_res, sizeof(tv_res)))
 		return;
 	if (!intel_sdvo_read_response(intel_sdvo, &reply, 3))
@@ -1662,8 +1661,7 @@
 
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct drm_i915_private *dev_priv = connector->dev->dev_private;
 	struct drm_display_mode *newmode;
 
@@ -1672,7 +1670,7 @@
 	 * Assume that the preferred modes are
 	 * arranged in priority order.
 	 */
-	intel_ddc_get_modes(connector, intel_sdvo->base.ddc_bus);
+	intel_ddc_get_modes(connector, intel_sdvo->i2c);
 	if (list_empty(&connector->probed_modes) == false)
 		goto end;
 
@@ -1693,6 +1691,10 @@
 		if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
 			intel_sdvo->sdvo_lvds_fixed_mode =
 				drm_mode_duplicate(connector->dev, newmode);
+
+			drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,
+					      0);
+
 			intel_sdvo->is_lvds = true;
 			break;
 		}
@@ -1775,8 +1777,7 @@
 			struct drm_property *property,
 			uint64_t val)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
+	struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 	struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector);
 	uint16_t temp_value;
 	uint8_t cmd;
@@ -1879,9 +1880,8 @@
 
 
 done:
-	if (encoder->crtc) {
-		struct drm_crtc *crtc = encoder->crtc;
-
+	if (intel_sdvo->base.base.crtc) {
+		struct drm_crtc *crtc = intel_sdvo->base.base.crtc;
 		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
 					 crtc->y, crtc->fb);
 	}
@@ -1909,20 +1909,18 @@
 static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
 	.get_modes = intel_sdvo_get_modes,
 	.mode_valid = intel_sdvo_mode_valid,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static void intel_sdvo_enc_destroy(struct drm_encoder *encoder)
 {
-	struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-
-	if (intel_sdvo->analog_ddc_bus)
-		intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
+	struct intel_sdvo *intel_sdvo = to_intel_sdvo(encoder);
 
 	if (intel_sdvo->sdvo_lvds_fixed_mode != NULL)
 		drm_mode_destroy(encoder->dev,
 				 intel_sdvo->sdvo_lvds_fixed_mode);
 
+	i2c_del_adapter(&intel_sdvo->ddc);
 	intel_encoder_destroy(encoder);
 }
 
@@ -1990,6 +1988,30 @@
 		intel_sdvo_guess_ddc_bus(sdvo);
 }
 
+static void
+intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
+			  struct intel_sdvo *sdvo, u32 reg)
+{
+	struct sdvo_device_mapping *mapping;
+	u8 pin, speed;
+
+	if (IS_SDVOB(reg))
+		mapping = &dev_priv->sdvo_mappings[0];
+	else
+		mapping = &dev_priv->sdvo_mappings[1];
+
+	pin = GMBUS_PORT_DPB;
+	speed = GMBUS_RATE_1MHZ >> 8;
+	if (mapping->initialized) {
+		pin = mapping->i2c_pin;
+		speed = mapping->i2c_speed;
+	}
+
+	sdvo->i2c = &dev_priv->gmbus[pin].adapter;
+	intel_gmbus_set_speed(sdvo->i2c, speed);
+	intel_gmbus_force_bit(sdvo->i2c, true);
+}
+
 static bool
 intel_sdvo_get_digital_encoding_mode(struct intel_sdvo *intel_sdvo, int device)
 {
@@ -1999,45 +2021,6 @@
 				     &intel_sdvo->is_hdmi, 1);
 }
 
-static struct intel_sdvo *
-intel_sdvo_chan_to_intel_sdvo(struct intel_i2c_chan *chan)
-{
-	struct drm_device *dev = chan->drm_dev;
-	struct drm_encoder *encoder;
-
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		struct intel_sdvo *intel_sdvo = enc_to_intel_sdvo(encoder);
-		if (intel_sdvo->base.ddc_bus == &chan->adapter)
-			return intel_sdvo;
-	}
-
-	return NULL;
-}
-
-static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
-				  struct i2c_msg msgs[], int num)
-{
-	struct intel_sdvo *intel_sdvo;
-	struct i2c_algo_bit_data *algo_data;
-	const struct i2c_algorithm *algo;
-
-	algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
-	intel_sdvo =
-		intel_sdvo_chan_to_intel_sdvo((struct intel_i2c_chan *)
-					      (algo_data->data));
-	if (intel_sdvo == NULL)
-		return -EINVAL;
-
-	algo = intel_sdvo->base.i2c_bus->algo;
-
-	intel_sdvo_set_control_bus_switch(intel_sdvo, intel_sdvo->ddc_bus);
-	return algo->master_xfer(i2c_adap, msgs, num);
-}
-
-static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
-	.master_xfer	= intel_sdvo_master_xfer,
-};
-
 static u8
 intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
 {
@@ -2076,26 +2059,29 @@
 }
 
 static void
-intel_sdvo_connector_init(struct drm_encoder *encoder,
-			  struct drm_connector *connector)
+intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
+			  struct intel_sdvo *encoder)
 {
-	drm_connector_init(encoder->dev, connector, &intel_sdvo_connector_funcs,
-			   connector->connector_type);
+	drm_connector_init(encoder->base.base.dev,
+			   &connector->base.base,
+			   &intel_sdvo_connector_funcs,
+			   connector->base.base.connector_type);
 
-	drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
+	drm_connector_helper_add(&connector->base.base,
+				 &intel_sdvo_connector_helper_funcs);
 
-	connector->interlace_allowed = 0;
-	connector->doublescan_allowed = 0;
-	connector->display_info.subpixel_order = SubPixelHorizontalRGB;
+	connector->base.base.interlace_allowed = 0;
+	connector->base.base.doublescan_allowed = 0;
+	connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
 
-	drm_mode_connector_attach_encoder(connector, encoder);
-	drm_sysfs_connector_add(connector);
+	intel_connector_attach_encoder(&connector->base, &encoder->base);
+	drm_sysfs_connector_add(&connector->base.base);
 }
 
 static bool
 intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 {
-	struct drm_encoder *encoder = &intel_sdvo->base.enc;
+	struct drm_encoder *encoder = &intel_sdvo->base.base;
 	struct drm_connector *connector;
 	struct intel_connector *intel_connector;
 	struct intel_sdvo_connector *intel_sdvo_connector;
@@ -2130,7 +2116,7 @@
 	intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
 				       (1 << INTEL_ANALOG_CLONE_BIT));
 
-	intel_sdvo_connector_init(encoder, connector);
+	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
 
 	return true;
 }
@@ -2138,83 +2124,10 @@
 static bool
 intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
 {
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
-
-	intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
-	if (!intel_sdvo_connector)
-		return false;
-
-	intel_connector = &intel_sdvo_connector->base;
-        connector = &intel_connector->base;
-        encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
-        connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
-
-        intel_sdvo->controlled_output |= type;
-        intel_sdvo_connector->output_flag = type;
-
-        intel_sdvo->is_tv = true;
-        intel_sdvo->base.needs_tv_clock = true;
-        intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
-
-        intel_sdvo_connector_init(encoder, connector);
-
-        if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
-		goto err;
-
-        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
-		goto err;
-
-        return true;
-
-err:
-	intel_sdvo_destroy_enhance_property(connector);
-	kfree(intel_sdvo_connector);
-	return false;
-}
-
-static bool
-intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
-{
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
-
-	intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
-	if (!intel_sdvo_connector)
-		return false;
-
-	intel_connector = &intel_sdvo_connector->base;
-        connector = &intel_connector->base;
-	connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-        encoder->encoder_type = DRM_MODE_ENCODER_DAC;
-        connector->connector_type = DRM_MODE_CONNECTOR_VGA;
-
-        if (device == 0) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
-        } else if (device == 1) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
-        }
-
-        intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
-				       (1 << INTEL_ANALOG_CLONE_BIT));
-
-        intel_sdvo_connector_init(encoder, connector);
-        return true;
-}
-
-static bool
-intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
-{
-        struct drm_encoder *encoder = &intel_sdvo->base.enc;
-        struct drm_connector *connector;
-        struct intel_connector *intel_connector;
-        struct intel_sdvo_connector *intel_sdvo_connector;
+	struct drm_encoder *encoder = &intel_sdvo->base.base;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *intel_sdvo_connector;
 
 	intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
 	if (!intel_sdvo_connector)
@@ -2222,29 +2135,101 @@
 
 	intel_connector = &intel_sdvo_connector->base;
 	connector = &intel_connector->base;
-        encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
-        connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+	encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
+	connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
 
-        if (device == 0) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
-        } else if (device == 1) {
-                intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
-                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
-        }
+	intel_sdvo->controlled_output |= type;
+	intel_sdvo_connector->output_flag = type;
 
-        intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
-				       (1 << INTEL_SDVO_LVDS_CLONE_BIT));
+	intel_sdvo->is_tv = true;
+	intel_sdvo->base.needs_tv_clock = true;
+	intel_sdvo->base.clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
 
-        intel_sdvo_connector_init(encoder, connector);
-        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+
+	if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
+		goto err;
+
+	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
 		goto err;
 
 	return true;
 
 err:
-	intel_sdvo_destroy_enhance_property(connector);
-	kfree(intel_sdvo_connector);
+	intel_sdvo_destroy(connector);
+	return false;
+}
+
+static bool
+intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
+{
+	struct drm_encoder *encoder = &intel_sdvo->base.base;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *intel_sdvo_connector;
+
+	intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
+	if (!intel_sdvo_connector)
+		return false;
+
+	intel_connector = &intel_sdvo_connector->base;
+	connector = &intel_connector->base;
+	connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+	encoder->encoder_type = DRM_MODE_ENCODER_DAC;
+	connector->connector_type = DRM_MODE_CONNECTOR_VGA;
+
+	if (device == 0) {
+		intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB0;
+		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB0;
+	} else if (device == 1) {
+		intel_sdvo->controlled_output |= SDVO_OUTPUT_RGB1;
+		intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
+	}
+
+	intel_sdvo->base.clone_mask = ((1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
+				       (1 << INTEL_ANALOG_CLONE_BIT));
+
+	intel_sdvo_connector_init(intel_sdvo_connector,
+				  intel_sdvo);
+	return true;
+}
+
+static bool
+intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
+{
+	struct drm_encoder *encoder = &intel_sdvo->base.base;
+	struct drm_connector *connector;
+	struct intel_connector *intel_connector;
+	struct intel_sdvo_connector *intel_sdvo_connector;
+
+	intel_sdvo_connector = kzalloc(sizeof(struct intel_sdvo_connector), GFP_KERNEL);
+	if (!intel_sdvo_connector)
+		return false;
+
+	intel_connector = &intel_sdvo_connector->base;
+	connector = &intel_connector->base;
+	encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+	connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
+
+	if (device == 0) {
+		intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS0;
+		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS0;
+	} else if (device == 1) {
+		intel_sdvo->controlled_output |= SDVO_OUTPUT_LVDS1;
+		intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
+	}
+
+	intel_sdvo->base.clone_mask = ((1 << INTEL_ANALOG_CLONE_BIT) |
+				       (1 << INTEL_SDVO_LVDS_CLONE_BIT));
+
+	intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+	if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
+		goto err;
+
+	return true;
+
+err:
+	intel_sdvo_destroy(connector);
 	return false;
 }
 
@@ -2309,7 +2294,7 @@
 					  struct intel_sdvo_connector *intel_sdvo_connector,
 					  int type)
 {
-	struct drm_device *dev = intel_sdvo->base.enc.dev;
+	struct drm_device *dev = intel_sdvo->base.base.dev;
 	struct intel_sdvo_tv_format format;
 	uint32_t format_map, i;
 
@@ -2375,7 +2360,7 @@
 				      struct intel_sdvo_connector *intel_sdvo_connector,
 				      struct intel_sdvo_enhancements_reply enhancements)
 {
-	struct drm_device *dev = intel_sdvo->base.enc.dev;
+	struct drm_device *dev = intel_sdvo->base.base.dev;
 	struct drm_connector *connector = &intel_sdvo_connector->base.base;
 	uint16_t response, data_value[2];
 
@@ -2504,7 +2489,7 @@
 					struct intel_sdvo_connector *intel_sdvo_connector,
 					struct intel_sdvo_enhancements_reply enhancements)
 {
-	struct drm_device *dev = intel_sdvo->base.enc.dev;
+	struct drm_device *dev = intel_sdvo->base.base.dev;
 	struct drm_connector *connector = &intel_sdvo_connector->base.base;
 	uint16_t response, data_value[2];
 
@@ -2522,11 +2507,10 @@
 		uint16_t response;
 	} enhancements;
 
-	if (!intel_sdvo_get_value(intel_sdvo,
-				  SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
-				  &enhancements, sizeof(enhancements)))
-		return false;
-
+	enhancements.response = 0;
+	intel_sdvo_get_value(intel_sdvo,
+			     SDVO_CMD_GET_SUPPORTED_ENHANCEMENTS,
+			     &enhancements, sizeof(enhancements));
 	if (enhancements.response == 0) {
 		DRM_DEBUG_KMS("No enhancement is supported\n");
 		return true;
@@ -2538,7 +2522,43 @@
 		return intel_sdvo_create_enhance_property_lvds(intel_sdvo, intel_sdvo_connector, enhancements.reply);
 	else
 		return true;
+}
 
+static int intel_sdvo_ddc_proxy_xfer(struct i2c_adapter *adapter,
+				     struct i2c_msg *msgs,
+				     int num)
+{
+	struct intel_sdvo *sdvo = adapter->algo_data;
+
+	if (!intel_sdvo_set_control_bus_switch(sdvo, sdvo->ddc_bus))
+		return -EIO;
+
+	return sdvo->i2c->algo->master_xfer(sdvo->i2c, msgs, num);
+}
+
+static u32 intel_sdvo_ddc_proxy_func(struct i2c_adapter *adapter)
+{
+	struct intel_sdvo *sdvo = adapter->algo_data;
+	return sdvo->i2c->algo->functionality(sdvo->i2c);
+}
+
+static const struct i2c_algorithm intel_sdvo_ddc_proxy = {
+	.master_xfer	= intel_sdvo_ddc_proxy_xfer,
+	.functionality	= intel_sdvo_ddc_proxy_func
+};
+
+static bool
+intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
+			  struct drm_device *dev)
+{
+	sdvo->ddc.owner = THIS_MODULE;
+	sdvo->ddc.class = I2C_CLASS_DDC;
+	snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy");
+	sdvo->ddc.dev.parent = &dev->pdev->dev;
+	sdvo->ddc.algo_data = sdvo;
+	sdvo->ddc.algo = &intel_sdvo_ddc_proxy;
+
+	return i2c_add_adapter(&sdvo->ddc) == 0;
 }
 
 bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
@@ -2546,95 +2566,66 @@
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct intel_encoder *intel_encoder;
 	struct intel_sdvo *intel_sdvo;
-	u8 ch[0x40];
 	int i;
-	u32 i2c_reg, ddc_reg, analog_ddc_reg;
 
 	intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
 	if (!intel_sdvo)
 		return false;
 
+	if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
+		kfree(intel_sdvo);
+		return false;
+	}
+
 	intel_sdvo->sdvo_reg = sdvo_reg;
 
 	intel_encoder = &intel_sdvo->base;
 	intel_encoder->type = INTEL_OUTPUT_SDVO;
+	/* encoder type will be decided later */
+	drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
 
-	if (HAS_PCH_SPLIT(dev)) {
-		i2c_reg = PCH_GPIOE;
-		ddc_reg = PCH_GPIOE;
-		analog_ddc_reg = PCH_GPIOA;
-	} else {
-		i2c_reg = GPIOE;
-		ddc_reg = GPIOE;
-		analog_ddc_reg = GPIOA;
-	}
-
-	/* setup the DDC bus. */
-	if (IS_SDVOB(sdvo_reg))
-		intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOB");
-	else
-		intel_encoder->i2c_bus = intel_i2c_create(dev, i2c_reg, "SDVOCTRL_E for SDVOC");
-
-	if (!intel_encoder->i2c_bus)
-		goto err_inteloutput;
-
-	intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg);
-
-	/* Save the bit-banging i2c functionality for use by the DDC wrapper */
-	intel_sdvo_i2c_bit_algo.functionality = intel_encoder->i2c_bus->algo->functionality;
+	intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+	intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
 
 	/* Read the regs to test if we can talk to the device */
 	for (i = 0; i < 0x40; i++) {
-		if (!intel_sdvo_read_byte(intel_sdvo, i, &ch[i])) {
+		u8 byte;
+
+		if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
 			DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
 				      IS_SDVOB(sdvo_reg) ? 'B' : 'C');
-			goto err_i2c;
+			goto err;
 		}
 	}
 
-	/* setup the DDC bus. */
-	if (IS_SDVOB(sdvo_reg)) {
-		intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOB DDC BUS");
-		intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
-						"SDVOB/VGA DDC BUS");
+	if (IS_SDVOB(sdvo_reg))
 		dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
-	} else {
-		intel_encoder->ddc_bus = intel_i2c_create(dev, ddc_reg, "SDVOC DDC BUS");
-		intel_sdvo->analog_ddc_bus = intel_i2c_create(dev, analog_ddc_reg,
-						"SDVOC/VGA DDC BUS");
+	else
 		dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
-	}
-	if (intel_encoder->ddc_bus == NULL || intel_sdvo->analog_ddc_bus == NULL)
-		goto err_i2c;
 
-	/* Wrap with our custom algo which switches to DDC mode */
-	intel_encoder->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
-
-	/* encoder type will be decided later */
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_sdvo_enc_funcs, 0);
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_sdvo_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_sdvo_helper_funcs);
 
 	/* In default case sdvo lvds is false */
 	if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
-		goto err_enc;
+		goto err;
 
 	if (intel_sdvo_output_setup(intel_sdvo,
 				    intel_sdvo->caps.output_flags) != true) {
 		DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
 			      IS_SDVOB(sdvo_reg) ? 'B' : 'C');
-		goto err_enc;
+		goto err;
 	}
 
 	intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
 
 	/* Set the input timing to the screen. Assume always input 0. */
 	if (!intel_sdvo_set_target_input(intel_sdvo))
-		goto err_enc;
+		goto err;
 
 	if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
 						    &intel_sdvo->pixel_clock_min,
 						    &intel_sdvo->pixel_clock_max))
-		goto err_enc;
+		goto err;
 
 	DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
 			"clock range %dMHz - %dMHz, "
@@ -2654,16 +2645,9 @@
 			(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
 	return true;
 
-err_enc:
-	drm_encoder_cleanup(&intel_encoder->enc);
-err_i2c:
-	if (intel_sdvo->analog_ddc_bus != NULL)
-		intel_i2c_destroy(intel_sdvo->analog_ddc_bus);
-	if (intel_encoder->ddc_bus != NULL)
-		intel_i2c_destroy(intel_encoder->ddc_bus);
-	if (intel_encoder->i2c_bus != NULL)
-		intel_i2c_destroy(intel_encoder->i2c_bus);
-err_inteloutput:
+err:
+	drm_encoder_cleanup(&intel_encoder->base);
+	i2c_del_adapter(&intel_sdvo->ddc);
 	kfree(intel_sdvo);
 
 	return false;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 4a117e3..2f76819 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -48,7 +48,7 @@
 	struct intel_encoder base;
 
 	int type;
-	char *tv_format;
+	const char *tv_format;
 	int margin[4];
 	u32 save_TV_H_CTL_1;
 	u32 save_TV_H_CTL_2;
@@ -350,7 +350,7 @@
 
 
 struct tv_mode {
-	char *name;
+	const char *name;
 	int clock;
 	int refresh; /* in millihertz (for precision) */
 	u32 oversample;
@@ -900,7 +900,14 @@
 
 static struct intel_tv *enc_to_intel_tv(struct drm_encoder *encoder)
 {
-	return container_of(enc_to_intel_encoder(encoder), struct intel_tv, base);
+	return container_of(encoder, struct intel_tv, base.base);
+}
+
+static struct intel_tv *intel_attached_tv(struct drm_connector *connector)
+{
+	return container_of(intel_attached_encoder(connector),
+			    struct intel_tv,
+			    base);
 }
 
 static void
@@ -922,7 +929,7 @@
 }
 
 static const struct tv_mode *
-intel_tv_mode_lookup (char *tv_format)
+intel_tv_mode_lookup(const char *tv_format)
 {
 	int i;
 
@@ -936,22 +943,23 @@
 }
 
 static const struct tv_mode *
-intel_tv_mode_find (struct intel_tv *intel_tv)
+intel_tv_mode_find(struct intel_tv *intel_tv)
 {
 	return intel_tv_mode_lookup(intel_tv->tv_format);
 }
 
 static enum drm_mode_status
-intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode)
+intel_tv_mode_valid(struct drm_connector *connector,
+		    struct drm_display_mode *mode)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
 	/* Ensure TV refresh is close to desired refresh */
 	if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
 				< 1000)
 		return MODE_OK;
+
 	return MODE_CLOCK_RANGE;
 }
 
@@ -1131,7 +1139,7 @@
 			   color_conversion->av);
 	}
 
-	if (IS_I965G(dev))
+	if (INTEL_INFO(dev)->gen >= 4)
 		I915_WRITE(TV_CLR_KNOBS, 0x00404000);
 	else
 		I915_WRITE(TV_CLR_KNOBS, 0x00606000);
@@ -1157,12 +1165,12 @@
 		I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
 
 		/* Wait for vblank for the disable to take effect */
-		if (!IS_I9XX(dev))
+		if (IS_GEN2(dev))
 			intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-		I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+		I915_WRITE(pipeconf_reg, pipeconf & ~PIPECONF_ENABLE);
 		/* Wait for vblank for the disable to take effect. */
-		intel_wait_for_vblank(dev, intel_crtc->pipe);
+		intel_wait_for_pipe_off(dev, intel_crtc->pipe);
 
 		/* Filter ctl must be set before TV_WIN_SIZE */
 		I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE);
@@ -1196,7 +1204,7 @@
 		I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
 	for (i = 0; i < 43; i++)
 		I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
-	I915_WRITE(TV_DAC, 0);
+	I915_WRITE(TV_DAC, I915_READ(TV_DAC) & TV_DAC_SAVE);
 	I915_WRITE(TV_CTL, tv_ctl);
 }
 
@@ -1228,15 +1236,13 @@
 static int
 intel_tv_detect_type (struct intel_tv *intel_tv)
 {
-	struct drm_encoder *encoder = &intel_tv->base.enc;
+	struct drm_encoder *encoder = &intel_tv->base.base;
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	unsigned long irqflags;
 	u32 tv_ctl, save_tv_ctl;
 	u32 tv_dac, save_tv_dac;
-	int type = DRM_MODE_CONNECTOR_Unknown;
-
-	tv_dac = I915_READ(TV_DAC);
+	int type;
 
 	/* Disable TV interrupts around load detect or we'll recurse */
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
@@ -1244,19 +1250,14 @@
 			      PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
 	spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
 
-	/*
-	 * Detect TV by polling)
-	 */
-	save_tv_dac = tv_dac;
-	tv_ctl = I915_READ(TV_CTL);
-	save_tv_ctl = tv_ctl;
-	tv_ctl &= ~TV_ENC_ENABLE;
-	tv_ctl &= ~TV_TEST_MODE_MASK;
+	save_tv_dac = tv_dac = I915_READ(TV_DAC);
+	save_tv_ctl = tv_ctl = I915_READ(TV_CTL);
+
+	/* Poll for TV detection */
+	tv_ctl &= ~(TV_ENC_ENABLE | TV_TEST_MODE_MASK);
 	tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
-	tv_dac &= ~TVDAC_SENSE_MASK;
-	tv_dac &= ~DAC_A_MASK;
-	tv_dac &= ~DAC_B_MASK;
-	tv_dac &= ~DAC_C_MASK;
+
+	tv_dac &= ~(TVDAC_SENSE_MASK | DAC_A_MASK | DAC_B_MASK | DAC_C_MASK);
 	tv_dac |= (TVDAC_STATE_CHG_EN |
 		   TVDAC_A_SENSE_CTL |
 		   TVDAC_B_SENSE_CTL |
@@ -1265,37 +1266,40 @@
 		   DAC_A_0_7_V |
 		   DAC_B_0_7_V |
 		   DAC_C_0_7_V);
+
 	I915_WRITE(TV_CTL, tv_ctl);
 	I915_WRITE(TV_DAC, tv_dac);
 	POSTING_READ(TV_DAC);
-	msleep(20);
 
-	tv_dac = I915_READ(TV_DAC);
-	I915_WRITE(TV_DAC, save_tv_dac);
-	I915_WRITE(TV_CTL, save_tv_ctl);
-	POSTING_READ(TV_CTL);
-	msleep(20);
+	intel_wait_for_vblank(intel_tv->base.base.dev,
+			      to_intel_crtc(intel_tv->base.base.crtc)->pipe);
 
-	/*
-	 *  A B C
-	 *  0 1 1 Composite
-	 *  1 0 X svideo
-	 *  0 0 0 Component
-	 */
-	if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
-		DRM_DEBUG_KMS("Detected Composite TV connection\n");
-		type = DRM_MODE_CONNECTOR_Composite;
-	} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
-		DRM_DEBUG_KMS("Detected S-Video TV connection\n");
-		type = DRM_MODE_CONNECTOR_SVIDEO;
-	} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
-		DRM_DEBUG_KMS("Detected Component TV connection\n");
-		type = DRM_MODE_CONNECTOR_Component;
-	} else {
-		DRM_DEBUG_KMS("No TV connection detected\n");
-		type = -1;
+	type = -1;
+	if (wait_for((tv_dac = I915_READ(TV_DAC)) & TVDAC_STATE_CHG, 20) == 0) {
+		DRM_DEBUG_KMS("TV detected: %x, %x\n", tv_ctl, tv_dac);
+		/*
+		 *  A B C
+		 *  0 1 1 Composite
+		 *  1 0 X svideo
+		 *  0 0 0 Component
+		 */
+		if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
+			DRM_DEBUG_KMS("Detected Composite TV connection\n");
+			type = DRM_MODE_CONNECTOR_Composite;
+		} else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
+			DRM_DEBUG_KMS("Detected S-Video TV connection\n");
+			type = DRM_MODE_CONNECTOR_SVIDEO;
+		} else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
+			DRM_DEBUG_KMS("Detected Component TV connection\n");
+			type = DRM_MODE_CONNECTOR_Component;
+		} else {
+			DRM_DEBUG_KMS("Unrecognised TV connection\n");
+		}
 	}
 
+	I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+	I915_WRITE(TV_CTL, save_tv_ctl);
+
 	/* Restore interrupt config */
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	i915_enable_pipestat(dev_priv, 0, PIPE_HOTPLUG_INTERRUPT_ENABLE |
@@ -1311,8 +1315,7 @@
  */
 static void intel_tv_find_better_format(struct drm_connector *connector)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 	int i;
 
@@ -1344,14 +1347,13 @@
 intel_tv_detect(struct drm_connector *connector, bool force)
 {
 	struct drm_display_mode mode;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	int type;
 
 	mode = reported_modes[0];
 	drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
 
-	if (encoder->crtc && encoder->crtc->enabled) {
+	if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
 		type = intel_tv_detect_type(intel_tv);
 	} else if (force) {
 		struct drm_crtc *crtc;
@@ -1375,11 +1377,10 @@
 	return connector_status_connected;
 }
 
-static struct input_res {
-	char *name;
+static const struct input_res {
+	const char *name;
 	int w, h;
-} input_res_table[] =
-{
+} input_res_table[] = {
 	{"640x480", 640, 480},
 	{"800x600", 800, 600},
 	{"1024x768", 1024, 768},
@@ -1396,8 +1397,7 @@
 intel_tv_chose_preferred_modes(struct drm_connector *connector,
 			       struct drm_display_mode *mode_ptr)
 {
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 
 	if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
@@ -1422,15 +1422,14 @@
 intel_tv_get_modes(struct drm_connector *connector)
 {
 	struct drm_display_mode *mode_ptr;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
 	const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
 	int j, count = 0;
 	u64 tmp;
 
 	for (j = 0; j < ARRAY_SIZE(input_res_table);
 	     j++) {
-		struct input_res *input = &input_res_table[j];
+		const struct input_res *input = &input_res_table[j];
 		unsigned int hactive_s = input->w;
 		unsigned int vactive_s = input->h;
 
@@ -1488,9 +1487,8 @@
 		      uint64_t val)
 {
 	struct drm_device *dev = connector->dev;
-	struct drm_encoder *encoder = intel_attached_encoder(connector);
-	struct intel_tv *intel_tv = enc_to_intel_tv(encoder);
-	struct drm_crtc *crtc = encoder->crtc;
+	struct intel_tv *intel_tv = intel_attached_tv(connector);
+	struct drm_crtc *crtc = intel_tv->base.base.crtc;
 	int ret = 0;
 	bool changed = false;
 
@@ -1555,7 +1553,7 @@
 static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
 	.mode_valid = intel_tv_mode_valid,
 	.get_modes = intel_tv_get_modes,
-	.best_encoder = intel_attached_encoder,
+	.best_encoder = intel_best_encoder,
 };
 
 static const struct drm_encoder_funcs intel_tv_enc_funcs = {
@@ -1607,7 +1605,7 @@
 	struct intel_encoder *intel_encoder;
 	struct intel_connector *intel_connector;
 	u32 tv_dac_on, tv_dac_off, save_tv_dac;
-	char **tv_format_names;
+	char *tv_format_names[ARRAY_SIZE(tv_modes)];
 	int i, initial_mode = 0;
 
 	if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
@@ -1661,15 +1659,15 @@
 	drm_connector_init(dev, connector, &intel_tv_connector_funcs,
 			   DRM_MODE_CONNECTOR_SVIDEO);
 
-	drm_encoder_init(dev, &intel_encoder->enc, &intel_tv_enc_funcs,
+	drm_encoder_init(dev, &intel_encoder->base, &intel_tv_enc_funcs,
 			 DRM_MODE_ENCODER_TVDAC);
 
-	drm_mode_connector_attach_encoder(&intel_connector->base, &intel_encoder->enc);
+	intel_connector_attach_encoder(intel_connector, intel_encoder);
 	intel_encoder->type = INTEL_OUTPUT_TVOUT;
 	intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
 	intel_encoder->clone_mask = (1 << INTEL_TV_CLONE_BIT);
-	intel_encoder->enc.possible_crtcs = ((1 << 0) | (1 << 1));
-	intel_encoder->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
+	intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
+	intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
 	intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
 
 	/* BIOS margin values */
@@ -1678,21 +1676,19 @@
 	intel_tv->margin[TV_MARGIN_RIGHT] = 46;
 	intel_tv->margin[TV_MARGIN_BOTTOM] = 37;
 
-	intel_tv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL);
+	intel_tv->tv_format = tv_modes[initial_mode].name;
 
-	drm_encoder_helper_add(&intel_encoder->enc, &intel_tv_helper_funcs);
+	drm_encoder_helper_add(&intel_encoder->base, &intel_tv_helper_funcs);
 	drm_connector_helper_add(connector, &intel_tv_connector_helper_funcs);
 	connector->interlace_allowed = false;
 	connector->doublescan_allowed = false;
 
 	/* Create TV properties then attach current values */
-	tv_format_names = kmalloc(sizeof(char *) * ARRAY_SIZE(tv_modes),
-				  GFP_KERNEL);
-	if (!tv_format_names)
-		goto out;
 	for (i = 0; i < ARRAY_SIZE(tv_modes); i++)
-		tv_format_names[i] = tv_modes[i].name;
-	drm_mode_create_tv_properties(dev, ARRAY_SIZE(tv_modes), tv_format_names);
+		tv_format_names[i] = (char *)tv_modes[i].name;
+	drm_mode_create_tv_properties(dev,
+				      ARRAY_SIZE(tv_modes),
+				      tv_format_names);
 
 	drm_connector_attach_property(connector, dev->mode_config.tv_mode_property,
 				   initial_mode);
@@ -1708,6 +1704,5 @@
 	drm_connector_attach_property(connector,
 				   dev->mode_config.tv_bottom_margin_property,
 				   intel_tv->margin[TV_MARGIN_BOTTOM]);
-out:
 	drm_sysfs_connector_add(connector);
 }
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 30e827a..bb5c418 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1041,13 +1041,6 @@
 	/*@{ */
 	spinlock_t object_name_lock;
 	struct idr object_name_idr;
-	atomic_t object_count;
-	atomic_t object_memory;
-	atomic_t pin_count;
-	atomic_t pin_memory;
-	atomic_t gtt_count;
-	atomic_t gtt_memory;
-	uint32_t gtt_total;
 	uint32_t invalidate_domains;    /* domains pending invalidation */
 	uint32_t flush_domains;         /* domains pending flush */
 	/*@} */
@@ -1378,7 +1371,6 @@
 extern int drm_vblank_info(struct seq_file *m, void *data);
 extern int drm_clients_info(struct seq_file *m, void* data);
 extern int drm_gem_name_info(struct seq_file *m, void *data);
-extern int drm_gem_object_info(struct seq_file *m, void* data);
 
 #if DRM_DEBUG_CODE
 extern int drm_vma_info(struct seq_file *m, void *data);
diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h
new file mode 100644
index 0000000..d3c81946
--- /dev/null
+++ b/include/drm/intel-gtt.h
@@ -0,0 +1,18 @@
+/* Common header for intel-gtt.ko and i915.ko */
+
+#ifndef _DRM_INTEL_GTT_H
+#define	_DRM_INTEL_GTT_H
+struct intel_gtt {
+	/* Number of stolen gtt entries at the beginning. */
+	unsigned int gtt_stolen_entries;
+	/* Total number of gtt entries. */
+	unsigned int gtt_total_entries;
+	/* Part of the gtt that is mappable by the cpu, for those chips where
+	 * this is not the full gtt. */
+	unsigned int gtt_mappable_entries;
+};
+
+struct intel_gtt *intel_gtt_get(void);
+
+#endif
+