Merge branch 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/i915: lock correct mutex around object unreference.
  drm/i915: add support for physical memory objects
  drm/i915: make LVDS fixed mode a preferred mode
  drm: handle depth & bpp changes correctly
  drm: initial KMS config fixes
  drm/i915: setup sarea properly in master_priv
  drm/i915: set vblank enabled flag correctly across IRQ install/uninstall
  drm/i915: don't enable vblanks on disabled pipes
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index d8a982b..964c5eb 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -36,7 +36,7 @@
 /*
  * Detailed mode info for 800x600@60Hz
  */
-static struct drm_display_mode std_mode[] = {
+static struct drm_display_mode std_modes[] = {
 	{ DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840,
 		   968, 1056, 0, 600, 601, 605, 628, 0,
 		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
@@ -60,15 +60,18 @@
  * changes have occurred.
  *
  * FIXME: take into account monitor limits
+ *
+ * RETURNS:
+ * Number of modes found on @connector.
  */
-void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
-					     uint32_t maxX, uint32_t maxY)
+int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
+					    uint32_t maxX, uint32_t maxY)
 {
 	struct drm_device *dev = connector->dev;
 	struct drm_display_mode *mode, *t;
 	struct drm_connector_helper_funcs *connector_funcs =
 		connector->helper_private;
-	int ret;
+	int count = 0;
 
 	DRM_DEBUG("%s\n", drm_get_connector_name(connector));
 	/* set all modes to the unverified state */
@@ -81,14 +84,14 @@
 		DRM_DEBUG("%s is disconnected\n",
 			  drm_get_connector_name(connector));
 		/* TODO set EDID to NULL */
-		return;
+		return 0;
 	}
 
-	ret = (*connector_funcs->get_modes)(connector);
+	count = (*connector_funcs->get_modes)(connector);
+	if (!count)
+		return 0;
 
-	if (ret) {
-		drm_mode_connector_list_update(connector);
-	}
+	drm_mode_connector_list_update(connector);
 
 	if (maxX && maxY)
 		drm_mode_validate_size(dev, &connector->modes, maxX,
@@ -102,25 +105,8 @@
 
 	drm_mode_prune_invalid(dev, &connector->modes, true);
 
-	if (list_empty(&connector->modes)) {
-		struct drm_display_mode *stdmode;
-
-		DRM_DEBUG("No valid modes on %s\n",
-			  drm_get_connector_name(connector));
-
-		/* Should we do this here ???
-		 * When no valid EDID modes are available we end up
-		 * here and bailed in the past, now we add a standard
-		 * 640x480@60Hz mode and carry on.
-		 */
-		stdmode = drm_mode_duplicate(dev, &std_mode[0]);
-		drm_mode_probed_add(connector, stdmode);
-		drm_mode_list_concat(&connector->probed_modes,
-				     &connector->modes);
-
-		DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
-			  drm_get_connector_name(connector));
-	}
+	if (list_empty(&connector->modes))
+		return 0;
 
 	drm_mode_sort(&connector->modes);
 
@@ -131,20 +117,58 @@
 		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
 		drm_mode_debug_printmodeline(mode);
 	}
+
+	return count;
 }
 EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
 
-void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
+int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
 				      uint32_t maxY)
 {
 	struct drm_connector *connector;
+	int count = 0;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		drm_helper_probe_single_connector_modes(connector, maxX, maxY);
+		count += drm_helper_probe_single_connector_modes(connector,
+								 maxX, maxY);
 	}
+
+	return count;
 }
 EXPORT_SYMBOL(drm_helper_probe_connector_modes);
 
+static void drm_helper_add_std_modes(struct drm_device *dev,
+				     struct drm_connector *connector)
+{
+	struct drm_display_mode *mode, *t;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(std_modes); i++) {
+		struct drm_display_mode *stdmode;
+
+		/*
+		 * When no valid EDID modes are available we end up
+		 * here and bailed in the past, now we add some standard
+		 * modes and move on.
+		 */
+		stdmode = drm_mode_duplicate(dev, &std_modes[i]);
+		drm_mode_probed_add(connector, stdmode);
+		drm_mode_list_concat(&connector->probed_modes,
+				     &connector->modes);
+
+		DRM_DEBUG("Adding mode %s to %s\n", stdmode->name,
+			  drm_get_connector_name(connector));
+	}
+	drm_mode_sort(&connector->modes);
+
+	DRM_DEBUG("Added std modes on %s\n", drm_get_connector_name(connector));
+	list_for_each_entry_safe(mode, t, &connector->modes, head) {
+		mode->vrefresh = drm_mode_vrefresh(mode);
+
+		drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+		drm_mode_debug_printmodeline(mode);
+	}
+}
 
 /**
  * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
@@ -237,6 +261,8 @@
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		enabled[i] = drm_connector_enabled(connector, true);
+		DRM_DEBUG("connector %d enabled? %s\n", connector->base.id,
+			  enabled[i] ? "yes" : "no");
 		any_enabled |= enabled[i];
 		i++;
 	}
@@ -265,11 +291,17 @@
 			continue;
 		}
 
+		DRM_DEBUG("looking for preferred mode on connector %d\n",
+			  connector->base.id);
+
 		modes[i] = drm_has_preferred_mode(connector, width, height);
-		if (!modes[i]) {
+		/* No preferred modes, pick one off the list */
+		if (!modes[i] && !list_empty(&connector->modes)) {
 			list_for_each_entry(modes[i], &connector->modes, head)
 				break;
 		}
+		DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name :
+			  "none");
 		i++;
 	}
 	return true;
@@ -369,6 +401,8 @@
 	int width, height;
 	int i, ret;
 
+	DRM_DEBUG("\n");
+
 	width = dev->mode_config.max_width;
 	height = dev->mode_config.max_height;
 
@@ -390,6 +424,8 @@
 	if (!ret)
 		DRM_ERROR("Unable to find initial modes\n");
 
+	DRM_DEBUG("picking CRTCs for %dx%d config\n", width, height);
+
 	drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
 
 	i = 0;
@@ -403,6 +439,8 @@
 		}
 
 		if (mode && crtc) {
+			DRM_DEBUG("desired mode %s set on crtc %d\n",
+				  mode->name, crtc->base.id);
 			crtc->desired_mode = mode;
 			connector->encoder->crtc = crtc;
 		} else
@@ -442,6 +480,7 @@
 	int saved_x, saved_y;
 	struct drm_encoder *encoder;
 	bool ret = true;
+	bool depth_changed, bpp_changed;
 
 	adjusted_mode = drm_mode_duplicate(dev, mode);
 
@@ -450,6 +489,15 @@
 	if (!crtc->enabled)
 		return true;
 
+	if (old_fb && crtc->fb) {
+		depth_changed = (old_fb->depth != crtc->fb->depth);
+		bpp_changed = (old_fb->bits_per_pixel !=
+			       crtc->fb->bits_per_pixel);
+	} else {
+		depth_changed = true;
+		bpp_changed = true;
+	}
+
 	saved_mode = crtc->mode;
 	saved_x = crtc->x;
 	saved_y = crtc->y;
@@ -462,7 +510,8 @@
 	crtc->y = y;
 
 	if (drm_mode_equal(&saved_mode, &crtc->mode)) {
-		if (saved_x != crtc->x || saved_y != crtc->y) {
+		if (saved_x != crtc->x || saved_y != crtc->y ||
+		    depth_changed || bpp_changed) {
 			crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
 						  old_fb);
 			goto done;
@@ -568,8 +617,8 @@
 	struct drm_encoder **save_encoders, *new_encoder;
 	struct drm_framebuffer *old_fb;
 	bool save_enabled;
-	bool changed = false;
-	bool flip_or_move = false;
+	bool mode_changed = false;
+	bool fb_changed = false;
 	struct drm_connector *connector;
 	int count = 0, ro, fail = 0;
 	struct drm_crtc_helper_funcs *crtc_funcs;
@@ -597,7 +646,10 @@
 	/* save previous config */
 	save_enabled = set->crtc->enabled;
 
-	/* this is meant to be num_connector not num_crtc */
+	/*
+	 * We do mode_config.num_connectors here since we'll look at the
+	 * CRTC and encoder associated with each connector later.
+	 */
 	save_crtcs = kzalloc(dev->mode_config.num_connector *
 			     sizeof(struct drm_crtc *), GFP_KERNEL);
 	if (!save_crtcs)
@@ -613,21 +665,25 @@
 	/* We should be able to check here if the fb has the same properties
 	 * and then just flip_or_move it */
 	if (set->crtc->fb != set->fb) {
-		/* if we have no fb then its a change not a flip */
+		/* If we have no fb then treat it as a full mode set */
 		if (set->crtc->fb == NULL)
-			changed = true;
+			mode_changed = true;
+		else if ((set->fb->bits_per_pixel !=
+			 set->crtc->fb->bits_per_pixel) ||
+			 set->fb->depth != set->crtc->fb->depth)
+			fb_changed = true;
 		else
-			flip_or_move = true;
+			fb_changed = true;
 	}
 
 	if (set->x != set->crtc->x || set->y != set->crtc->y)
-		flip_or_move = true;
+		fb_changed = true;
 
 	if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
 		DRM_DEBUG("modes are different\n");
 		drm_mode_debug_printmodeline(&set->crtc->mode);
 		drm_mode_debug_printmodeline(set->mode);
-		changed = true;
+		mode_changed = true;
 	}
 
 	/* a) traverse passed in connector list and get encoders for them */
@@ -650,7 +706,7 @@
 		}
 
 		if (new_encoder != connector->encoder) {
-			changed = true;
+			mode_changed = true;
 			connector->encoder = new_encoder;
 		}
 	}
@@ -677,16 +733,16 @@
 				new_crtc = set->crtc;
 		}
 		if (new_crtc != connector->encoder->crtc) {
-			changed = true;
+			mode_changed = true;
 			connector->encoder->crtc = new_crtc;
 		}
 	}
 
 	/* mode_set_base is not a required function */
-	if (flip_or_move && !crtc_funcs->mode_set_base)
-		changed = true;
+	if (fb_changed && !crtc_funcs->mode_set_base)
+		mode_changed = true;
 
-	if (changed) {
+	if (mode_changed) {
 		old_fb = set->crtc->fb;
 		set->crtc->fb = set->fb;
 		set->crtc->enabled = (set->mode != NULL);
@@ -705,7 +761,7 @@
 			set->crtc->desired_mode = set->mode;
 		}
 		drm_helper_disable_unused_functions(dev);
-	} else if (flip_or_move) {
+	} else if (fb_changed) {
 		old_fb = set->crtc->fb;
 		if (set->crtc->fb != set->fb)
 			set->crtc->fb = set->fb;
@@ -764,10 +820,31 @@
  */
 bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
 {
-	int ret = false;
+	struct drm_connector *connector;
+	int count = 0;
 
-	drm_helper_plugged_event(dev);
-	return ret;
+	count = drm_helper_probe_connector_modes(dev,
+						 dev->mode_config.max_width,
+						 dev->mode_config.max_height);
+
+	/*
+	 * None of the available connectors had any modes, so add some
+	 * and try to light them up anyway
+	 */
+	if (!count) {
+		DRM_ERROR("connectors have no modes, using standard modes\n");
+		list_for_each_entry(connector,
+				    &dev->mode_config.connector_list,
+				    head)
+			drm_helper_add_std_modes(dev, connector);
+	}
+
+	drm_setup_crtcs(dev);
+
+	/* alert the driver fb layer */
+	dev->mode_config.funcs->fb_changed(dev);
+
+	return 0;
 }
 EXPORT_SYMBOL(drm_helper_initial_config);
 
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 724e505..477caa1 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -267,7 +267,8 @@
  */
 int drm_irq_uninstall(struct drm_device * dev)
 {
-	int irq_enabled;
+	unsigned long irqflags;
+	int irq_enabled, i;
 
 	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
 		return -EINVAL;
@@ -277,6 +278,16 @@
 	dev->irq_enabled = 0;
 	mutex_unlock(&dev->struct_mutex);
 
+	/*
+	 * Wake up any waiters so they don't hang.
+	 */
+	spin_lock_irqsave(&dev->vbl_lock, irqflags);
+	for (i = 0; i < dev->num_crtcs; i++) {
+		DRM_WAKEUP(&dev->vbl_queue[i]);
+		dev->vblank_enabled[i] = 0;
+	}
+	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
 	if (!irq_enabled)
 		return -EINVAL;
 
@@ -652,8 +663,9 @@
 			  vblwait->request.sequence, crtc);
 		dev->last_vblank_wait[crtc] = vblwait->request.sequence;
 		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
-			    ((drm_vblank_count(dev, crtc)
-			      - vblwait->request.sequence) <= (1 << 23)));
+			    (((drm_vblank_count(dev, crtc) -
+			       vblwait->request.sequence) <= (1 << 23)) ||
+			     !dev->irq_enabled));
 
 		if (ret != -EINTR) {
 			struct timeval now;
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 62a4bf7..bbadf1c 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -177,6 +177,14 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
 
+	master_priv->sarea = drm_getsarea(dev);
+	if (master_priv->sarea) {
+		master_priv->sarea_priv = (drm_i915_sarea_t *)
+			((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
+	} else {
+		DRM_DEBUG("sarea not found assuming DRI2 userspace\n");
+	}
+
 	if (init->ring_size != 0) {
 		if (dev_priv->ring.ring_obj != NULL) {
 			i915_dma_cleanup(dev);
@@ -1152,6 +1160,8 @@
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
 		intel_modeset_cleanup(dev);
 
+		i915_gem_free_all_phys_object(dev);
+
 		mutex_lock(&dev->struct_mutex);
 		i915_gem_cleanup_ringbuffer(dev);
 		mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 563de18..e1351825 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -72,6 +72,18 @@
 #define WATCH_INACTIVE	0
 #define WATCH_PWRITE	0
 
+#define I915_GEM_PHYS_CURSOR_0 1
+#define I915_GEM_PHYS_CURSOR_1 2
+#define I915_GEM_PHYS_OVERLAY_REGS 3
+#define I915_MAX_PHYS_OBJECT (I915_GEM_PHYS_OVERLAY_REGS)
+
+struct drm_i915_gem_phys_object {
+	int id;
+	struct page **page_list;
+	drm_dma_handle_t *handle;
+	struct drm_gem_object *cur_obj;
+};
+
 typedef struct _drm_i915_ring_buffer {
 	int tail_mask;
 	unsigned long Size;
@@ -358,6 +370,9 @@
 		uint32_t bit_6_swizzle_x;
 		/** Bit 6 swizzling required for Y tiling */
 		uint32_t bit_6_swizzle_y;
+
+		/* storage for physical objects */
+		struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
 	} mm;
 } drm_i915_private_t;
 
@@ -436,6 +451,9 @@
 	/** User space pin count and filp owning the pin */
 	uint32_t user_pin_count;
 	struct drm_file *pin_filp;
+
+	/** for phy allocated objects */
+	struct drm_i915_gem_phys_object *phys_obj;
 };
 
 /**
@@ -598,6 +616,11 @@
 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_attach_phys_object(struct drm_device *dev,
+				struct drm_gem_object *obj, int id);
+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);
 
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 1384d66..96316fd 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -55,6 +55,9 @@
 static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
 static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
 static int i915_gem_evict_something(struct drm_device *dev);
+static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+				struct drm_i915_gem_pwrite *args,
+				struct drm_file *file_priv);
 
 int i915_gem_do_init(struct drm_device *dev, unsigned long start,
 		     unsigned long end)
@@ -386,8 +389,10 @@
 	 * pread/pwrite currently are reading and writing from the CPU
 	 * perspective, requiring manual detiling by the client.
 	 */
-	if (obj_priv->tiling_mode == I915_TILING_NONE &&
-	    dev->gtt_total != 0)
+	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)
 		ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
 	else
 		ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv);
@@ -2858,6 +2863,9 @@
 	while (obj_priv->pin_count > 0)
 		i915_gem_object_unpin(obj);
 
+	if (obj_priv->phys_obj)
+		i915_gem_detach_phys_object(dev, obj);
+
 	i915_gem_object_unbind(obj);
 
 	list = &obj->map_list;
@@ -3293,3 +3301,180 @@
 
 	i915_gem_detect_bit_6_swizzle(dev);
 }
+
+/*
+ * 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)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_gem_phys_object *phys_obj;
+	int ret;
+
+	if (dev_priv->mm.phys_objs[id - 1] || !size)
+		return 0;
+
+	phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
+	if (!phys_obj)
+		return -ENOMEM;
+
+	phys_obj->id = id;
+
+	phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff);
+	if (!phys_obj->handle) {
+		ret = -ENOMEM;
+		goto kfree_obj;
+	}
+#ifdef CONFIG_X86
+	set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
+#endif
+
+	dev_priv->mm.phys_objs[id - 1] = phys_obj;
+
+	return 0;
+kfree_obj:
+	drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
+	return ret;
+}
+
+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;
+
+	if (!dev_priv->mm.phys_objs[id - 1])
+		return;
+
+	phys_obj = dev_priv->mm.phys_objs[id - 1];
+	if (phys_obj->cur_obj) {
+		i915_gem_detach_phys_object(dev, phys_obj->cur_obj);
+	}
+
+#ifdef CONFIG_X86
+	set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
+#endif
+	drm_pci_free(dev, phys_obj->handle);
+	kfree(phys_obj);
+	dev_priv->mm.phys_objs[id - 1] = NULL;
+}
+
+void i915_gem_free_all_phys_object(struct drm_device *dev)
+{
+	int i;
+
+	for (i = 0; i < I915_MAX_PHYS_OBJECT; i++)
+		i915_gem_free_phys_object(dev, i);
+}
+
+void i915_gem_detach_phys_object(struct drm_device *dev,
+				 struct drm_gem_object *obj)
+{
+	struct drm_i915_gem_object *obj_priv;
+	int i;
+	int ret;
+	int page_count;
+
+	obj_priv = obj->driver_private;
+	if (!obj_priv->phys_obj)
+		return;
+
+	ret = i915_gem_object_get_page_list(obj);
+	if (ret)
+		goto out;
+
+	page_count = obj->size / PAGE_SIZE;
+
+	for (i = 0; i < page_count; i++) {
+		char *dst = kmap_atomic(obj_priv->page_list[i], KM_USER0);
+		char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
+
+		memcpy(dst, src, PAGE_SIZE);
+		kunmap_atomic(dst, KM_USER0);
+	}
+	drm_clflush_pages(obj_priv->page_list, page_count);
+	drm_agp_chipset_flush(dev);
+out:
+	obj_priv->phys_obj->cur_obj = NULL;
+	obj_priv->phys_obj = NULL;
+}
+
+int
+i915_gem_attach_phys_object(struct drm_device *dev,
+			    struct drm_gem_object *obj, int id)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_gem_object *obj_priv;
+	int ret = 0;
+	int page_count;
+	int i;
+
+	if (id > I915_MAX_PHYS_OBJECT)
+		return -EINVAL;
+
+	obj_priv = obj->driver_private;
+
+	if (obj_priv->phys_obj) {
+		if (obj_priv->phys_obj->id == id)
+			return 0;
+		i915_gem_detach_phys_object(dev, obj);
+	}
+
+
+	/* create a new object */
+	if (!dev_priv->mm.phys_objs[id - 1]) {
+		ret = i915_gem_init_phys_object(dev, id,
+						obj->size);
+		if (ret) {
+			DRM_ERROR("failed to init phys object %d size: %d\n", id, obj->size);
+			goto out;
+		}
+	}
+
+	/* bind to the object */
+	obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
+	obj_priv->phys_obj->cur_obj = obj;
+
+	ret = i915_gem_object_get_page_list(obj);
+	if (ret) {
+		DRM_ERROR("failed to get page list\n");
+		goto out;
+	}
+
+	page_count = obj->size / PAGE_SIZE;
+
+	for (i = 0; i < page_count; i++) {
+		char *src = kmap_atomic(obj_priv->page_list[i], KM_USER0);
+		char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
+
+		memcpy(dst, src, PAGE_SIZE);
+		kunmap_atomic(src, KM_USER0);
+	}
+
+	return 0;
+out:
+	return ret;
+}
+
+static int
+i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
+		     struct drm_i915_gem_pwrite *args,
+		     struct drm_file *file_priv)
+{
+	struct drm_i915_gem_object *obj_priv = obj->driver_private;
+	void *obj_addr;
+	int ret;
+	char __user *user_data;
+
+	user_data = (char __user *) (uintptr_t) args->data_ptr;
+	obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
+
+	DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size);
+	ret = copy_from_user(obj_addr, user_data, args->size);
+	if (ret)
+		return -EFAULT;
+
+	drm_agp_chipset_flush(dev);
+	return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 0cadafb..6290219 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -411,6 +411,12 @@
 {
 	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))
+		return -EINVAL;
 
 	spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
 	if (IS_I965G(dev))
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8ccb9c3..31c3732 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -401,6 +401,8 @@
 	I915_WRITE(dspstride, crtc->fb->pitch);
 
 	dspcntr = I915_READ(dspcntr_reg);
+	/* Mask out pixel format bits in case we change it */
+	dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 	switch (crtc->fb->bits_per_pixel) {
 	case 8:
 		dspcntr |= DISPPLANE_8BPP;
@@ -1014,21 +1016,25 @@
 
 	if (bo->size < width * height * 4) {
 		DRM_ERROR("buffer is to small\n");
-		drm_gem_object_unreference(bo);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto fail;
 	}
 
-	if (dev_priv->cursor_needs_physical) {
-		addr = dev->agp->base + obj_priv->gtt_offset;
-	} else {
+	/* we only need to pin inside GTT if cursor is non-phy */
+	if (!dev_priv->cursor_needs_physical) {
+		ret = i915_gem_object_pin(bo, PAGE_SIZE);
+		if (ret) {
+			DRM_ERROR("failed to pin cursor bo\n");
+			goto fail;
+		}
 		addr = obj_priv->gtt_offset;
-	}
-
-	ret = i915_gem_object_pin(bo, PAGE_SIZE);
-	if (ret) {
-		DRM_ERROR("failed to pin cursor bo\n");
-		drm_gem_object_unreference(bo);
-		return ret;
+	} else {
+		ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
+		if (ret) {
+			DRM_ERROR("failed to attach phys object\n");
+			goto fail;
+		}
+		addr = obj_priv->phys_obj->handle->busaddr;
 	}
 
 	temp = 0;
@@ -1041,14 +1047,25 @@
 	I915_WRITE(base, addr);
 
 	if (intel_crtc->cursor_bo) {
-		i915_gem_object_unpin(intel_crtc->cursor_bo);
+		if (dev_priv->cursor_needs_physical) {
+			if (intel_crtc->cursor_bo != bo)
+				i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
+		} else
+			i915_gem_object_unpin(intel_crtc->cursor_bo);
+		mutex_lock(&dev->struct_mutex);
 		drm_gem_object_unreference(intel_crtc->cursor_bo);
+		mutex_unlock(&dev->struct_mutex);
 	}
 
 	intel_crtc->cursor_addr = addr;
 	intel_crtc->cursor_bo = bo;
 
 	return 0;
+fail:
+	mutex_lock(&dev->struct_mutex);
+	drm_gem_object_unreference(bo);
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
 }
 
 static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index ccecfaf..2fafdcc 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -456,6 +456,13 @@
 		dev_priv->panel_fixed_mode =
 			drm_mode_duplicate(dev, dev_priv->vbt_mode);
 		mutex_unlock(&dev->mode_config.mutex);
+		if (dev_priv->panel_fixed_mode) {
+			dev_priv->panel_fixed_mode->type |=
+				DRM_MODE_TYPE_PREFERRED;
+			drm_mode_probed_add(connector,
+					    dev_priv->panel_fixed_mode);
+			goto out;
+		}
 	}
 
 	/*
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 0acb07f..47809ac 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -395,7 +395,7 @@
 	void (*save)(struct drm_connector *connector);
 	void (*restore)(struct drm_connector *connector);
 	enum drm_connector_status (*detect)(struct drm_connector *connector);
-	void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
+	int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
 	int (*set_property)(struct drm_connector *connector, struct drm_property *property,
 			     uint64_t val);
 	void (*destroy)(struct drm_connector *connector);
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 4bc04cf..0c6f0e1 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -88,7 +88,7 @@
 	struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
 };
 
-extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
+extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
 extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
 extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);