Merge commit 'Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux'

This backmerges Linus' merge commit of the latest drm-fixes pull:

commit 549f3a1218ba18fcde11ef0e22b07e6365645788
Merge: 42577ca 058ca4a
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Tue Jul 23 15:47:08 2013 -0700

    Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux

We've accrued a few too many conflicts, but the real reason is that I
want to merge the 100% solution for Haswell concurrent registers
writes into drm-intel-next. But that depends upon the 90% bandaid
merged into -fixes:

commit a7cd1b8fea2f341b626b255d9898a5ca5fabbf0a
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Fri Jul 19 20:36:51 2013 +0100

    drm/i915: Serialize almost all register access

Also, we can roll up on accrued conflicts.

Usually I'd backmerge a tagged -rc, but I want to get this done before
heading off to vacations next week ;-)

Conflicts:
	drivers/gpu/drm/i915/i915_dma.c
	drivers/gpu/drm/i915/i915_gem.c

v2: For added hilarity we have a init sequence conflict around the
gt_lock, so need to move that one, too. Spotted by Jani Nikula.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 738a429..6a64749 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -677,6 +677,11 @@
 					/* don't break so fail path works correct */
 					fail = 1;
 				break;
+
+				if (connector->dpms != DRM_MODE_DPMS_ON) {
+					DRM_DEBUG_KMS("connector dpms not on, full mode switch\n");
+					mode_changed = true;
+				}
 			}
 		}
 
@@ -754,6 +759,12 @@
 				ret = -EINVAL;
 				goto fail;
 			}
+			DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+			for (i = 0; i < set->num_connectors; i++) {
+				DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+					      drm_get_connector_name(set->connectors[i]));
+				set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
+			}
 		}
 		drm_helper_disable_unused_functions(dev);
 	} else if (fb_changed) {
@@ -771,22 +782,6 @@
 		}
 	}
 
-	/*
-	 * crtc set_config helpers implicit set the crtc and all connected
-	 * encoders to DPMS on for a full mode set. But for just an fb update it
-	 * doesn't do that. To not confuse userspace, do an explicit DPMS_ON
-	 * unconditionally. This will also ensure driver internal dpms state is
-	 * consistent again.
-	 */
-	if (set->crtc->enabled) {
-		DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
-		for (i = 0; i < set->num_connectors; i++) {
-			DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
-				      drm_get_connector_name(set->connectors[i]));
-			set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
-		}
-	}
-
 	kfree(save_connectors);
 	kfree(save_encoders);
 	kfree(save_crtcs);
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 2dc1a60..95d6f4b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -968,6 +968,9 @@
 	u8 csum = 0;
 	struct edid *edid = (struct edid *)raw_edid;
 
+	if (WARN_ON(!raw_edid))
+		return false;
+
 	if (edid_fixup > 8 || edid_fixup < 0)
 		edid_fixup = 6;
 
@@ -1010,15 +1013,15 @@
 		break;
 	}
 
-	return 1;
+	return true;
 
 bad:
-	if (raw_edid && print_bad_edid) {
+	if (print_bad_edid) {
 		printk(KERN_ERR "Raw EDID:\n");
 		print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1,
 			       raw_edid, EDID_LENGTH, false);
 	}
-	return 0;
+	return false;
 }
 EXPORT_SYMBOL(drm_edid_block_valid);
 
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
index a4f5ce1..271b42b 100644
--- a/drivers/gpu/drm/drm_edid_load.c
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -133,8 +133,8 @@
 	},
 };
 
-static u8 *edid_load(struct drm_connector *connector, char *name,
-			char *connector_name)
+static u8 *edid_load(struct drm_connector *connector, const char *name,
+			const char *connector_name)
 {
 	const struct firmware *fw;
 	struct platform_device *pdev;
@@ -242,7 +242,7 @@
 
 int drm_load_edid_firmware(struct drm_connector *connector)
 {
-	char *connector_name = drm_get_connector_name(connector);
+	const char *connector_name = drm_get_connector_name(connector);
 	char *edidname = edid_firmware, *last, *colon;
 	int ret;
 	struct edid *edid;
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index 0b5af7d..c385cc5 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -92,7 +92,7 @@
 
 	ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs);
 	if (ret) {
-		dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret);
+		dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret);
 		kfree(fb_cma);
 		return ERR_PTR(ret);
 	}
@@ -376,7 +376,7 @@
 
 	ret = drm_fb_helper_initial_config(helper, preferred_bpp);
 	if (ret < 0) {
-		dev_err(dev->dev, "Failed to set inital hw configuration.\n");
+		dev_err(dev->dev, "Failed to set initial hw configuration.\n");
 		goto err_drm_fb_helper_fini;
 	}
 
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 429e07d..3a24385 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -271,6 +271,11 @@
 	priv->uid = current_euid();
 	priv->pid = get_pid(task_pid(current));
 	priv->minor = idr_find(&drm_minors_idr, minor_id);
+	if (!priv->minor) {
+		ret = -ENODEV;
+		goto out_put_pid;
+	}
+
 	priv->ioctl_count = 0;
 	/* for compatibility root is always authenticated */
 	priv->authenticated = capable(CAP_SYS_ADMIN);
@@ -292,7 +297,7 @@
 	if (dev->driver->open) {
 		ret = dev->driver->open(dev, priv);
 		if (ret < 0)
-			goto out_free;
+			goto out_prime_destroy;
 	}
 
 
@@ -304,7 +309,7 @@
 		if (!priv->minor->master) {
 			mutex_unlock(&dev->struct_mutex);
 			ret = -ENOMEM;
-			goto out_free;
+			goto out_close;
 		}
 
 		priv->is_master = 1;
@@ -322,7 +327,7 @@
 				drm_master_put(&priv->minor->master);
 				drm_master_put(&priv->master);
 				mutex_unlock(&dev->struct_mutex);
-				goto out_free;
+				goto out_close;
 			}
 		}
 		mutex_lock(&dev->struct_mutex);
@@ -333,7 +338,7 @@
 				drm_master_put(&priv->minor->master);
 				drm_master_put(&priv->master);
 				mutex_unlock(&dev->struct_mutex);
-				goto out_free;
+				goto out_close;
 			}
 		}
 		mutex_unlock(&dev->struct_mutex);
@@ -367,7 +372,17 @@
 #endif
 
 	return 0;
-      out_free:
+
+out_close:
+	if (dev->driver->postclose)
+		dev->driver->postclose(dev, priv);
+out_prime_destroy:
+	if (drm_core_check_feature(dev, DRIVER_PRIME))
+		drm_prime_destroy_file_private(&priv->prime);
+	if (dev->driver->driver_features & DRIVER_GEM)
+		drm_gem_release(dev, priv);
+out_put_pid:
+	put_pid(priv->pid);
 	kfree(priv);
 	filp->private_data = NULL;
 	return ret;
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index bcedaf7..603f256 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -108,12 +108,8 @@
 		return -ENOMEM;
 	}
 
-	if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
-			DRM_FILE_PAGE_OFFSET_SIZE)) {
-		drm_ht_remove(&mm->offset_hash);
-		kfree(mm);
-		return -ENOMEM;
-	}
+	drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
+		    DRM_FILE_PAGE_OFFSET_SIZE);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
index ce06397..ece72a8 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -317,288 +317,81 @@
 EXPORT_SYMBOL_GPL(drm_gem_cma_describe);
 #endif
 
-/* -----------------------------------------------------------------------------
- * DMA-BUF
- */
-
-struct drm_gem_cma_dmabuf_attachment {
-	struct sg_table sgt;
-	enum dma_data_direction dir;
-};
-
-static int drm_gem_cma_dmabuf_attach(struct dma_buf *dmabuf, struct device *dev,
-				     struct dma_buf_attachment *attach)
+/* low-level interface prime helpers */
+struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj)
 {
-	struct drm_gem_cma_dmabuf_attachment *cma_attach;
-
-	cma_attach = kzalloc(sizeof(*cma_attach), GFP_KERNEL);
-	if (!cma_attach)
-		return -ENOMEM;
-
-	cma_attach->dir = DMA_NONE;
-	attach->priv = cma_attach;
-
-	return 0;
-}
-
-static void drm_gem_cma_dmabuf_detach(struct dma_buf *dmabuf,
-				      struct dma_buf_attachment *attach)
-{
-	struct drm_gem_cma_dmabuf_attachment *cma_attach = attach->priv;
+	struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
 	struct sg_table *sgt;
+	int ret;
 
-	if (cma_attach == NULL)
-		return;
+	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+	if (!sgt)
+		return NULL;
 
-	sgt = &cma_attach->sgt;
+	ret = dma_get_sgtable(obj->dev->dev, sgt, cma_obj->vaddr,
+			      cma_obj->paddr, obj->size);
+	if (ret < 0)
+		goto out;
 
-	if (cma_attach->dir != DMA_NONE)
-		dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
-				cma_attach->dir);
+	return sgt;
 
-	sg_free_table(sgt);
-	kfree(cma_attach);
-	attach->priv = NULL;
+out:
+	kfree(sgt);
+	return NULL;
 }
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_get_sg_table);
 
-static struct sg_table *
-drm_gem_cma_dmabuf_map(struct dma_buf_attachment *attach,
-		       enum dma_data_direction dir)
+struct drm_gem_object *
+drm_gem_cma_prime_import_sg_table(struct drm_device *dev, size_t size,
+				  struct sg_table *sgt)
 {
-	struct drm_gem_cma_dmabuf_attachment *cma_attach = attach->priv;
-	struct drm_gem_cma_object *cma_obj = attach->dmabuf->priv;
-	struct drm_device *drm = cma_obj->base.dev;
-	struct scatterlist *rd, *wr;
-	struct sg_table *sgt;
-	unsigned int i;
-	int nents, ret;
+	struct drm_gem_cma_object *cma_obj;
 
-	DRM_DEBUG_PRIME("\n");
-
-	if (WARN_ON(dir == DMA_NONE))
+	if (sgt->nents != 1)
 		return ERR_PTR(-EINVAL);
 
-	/* Return the cached mapping when possible. */
-	if (cma_attach->dir == dir)
-		return &cma_attach->sgt;
+	/* Create a CMA GEM buffer. */
+	cma_obj = __drm_gem_cma_create(dev, size);
+	if (IS_ERR(cma_obj))
+		return ERR_PTR(PTR_ERR(cma_obj));
 
-	/* Two mappings with different directions for the same attachment are
-	 * not allowed.
-	 */
-	if (WARN_ON(cma_attach->dir != DMA_NONE))
-		return ERR_PTR(-EBUSY);
+	cma_obj->paddr = sg_dma_address(sgt->sgl);
+	cma_obj->sgt = sgt;
 
-	sgt = &cma_attach->sgt;
+	DRM_DEBUG_PRIME("dma_addr = 0x%x, size = %zu\n", cma_obj->paddr, size);
 
-	ret = sg_alloc_table(sgt, cma_obj->sgt->orig_nents, GFP_KERNEL);
-	if (ret) {
-		DRM_ERROR("failed to alloc sgt.\n");
-		return ERR_PTR(-ENOMEM);
-	}
-
-	mutex_lock(&drm->struct_mutex);
-
-	rd = cma_obj->sgt->sgl;
-	wr = sgt->sgl;
-	for (i = 0; i < sgt->orig_nents; ++i) {
-		sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
-		rd = sg_next(rd);
-		wr = sg_next(wr);
-	}
-
-	nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);
-	if (!nents) {
-		DRM_ERROR("failed to map sgl with iommu.\n");
-		sg_free_table(sgt);
-		sgt = ERR_PTR(-EIO);
-		goto done;
-	}
-
-	cma_attach->dir = dir;
-	attach->priv = cma_attach;
-
-	DRM_DEBUG_PRIME("buffer size = %zu\n", cma_obj->base.size);
-
-done:
-	mutex_unlock(&drm->struct_mutex);
-	return sgt;
+	return &cma_obj->base;
 }
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table);
 
-static void drm_gem_cma_dmabuf_unmap(struct dma_buf_attachment *attach,
-				     struct sg_table *sgt,
-				     enum dma_data_direction dir)
+int drm_gem_cma_prime_mmap(struct drm_gem_object *obj,
+			   struct vm_area_struct *vma)
 {
-	/* Nothing to do. */
-}
-
-static void drm_gem_cma_dmabuf_release(struct dma_buf *dmabuf)
-{
-	struct drm_gem_cma_object *cma_obj = dmabuf->priv;
-
-	DRM_DEBUG_PRIME("%s\n", __FILE__);
-
-	/*
-	 * drm_gem_cma_dmabuf_release() call means that file object's
-	 * f_count is 0 and it calls drm_gem_object_handle_unreference()
-	 * to drop the references that these values had been increased
-	 * at drm_prime_handle_to_fd()
-	 */
-	if (cma_obj->base.export_dma_buf == dmabuf) {
-		cma_obj->base.export_dma_buf = NULL;
-
-		/*
-		 * drop this gem object refcount to release allocated buffer
-		 * and resources.
-		 */
-		drm_gem_object_unreference_unlocked(&cma_obj->base);
-	}
-}
-
-static void *drm_gem_cma_dmabuf_kmap_atomic(struct dma_buf *dmabuf,
-					    unsigned long page_num)
-{
-	/* TODO */
-
-	return NULL;
-}
-
-static void drm_gem_cma_dmabuf_kunmap_atomic(struct dma_buf *dmabuf,
-					     unsigned long page_num, void *addr)
-{
-	/* TODO */
-}
-
-static void *drm_gem_cma_dmabuf_kmap(struct dma_buf *dmabuf,
-				     unsigned long page_num)
-{
-	/* TODO */
-
-	return NULL;
-}
-
-static void drm_gem_cma_dmabuf_kunmap(struct dma_buf *dmabuf,
-				      unsigned long page_num, void *addr)
-{
-	/* TODO */
-}
-
-static int drm_gem_cma_dmabuf_mmap(struct dma_buf *dmabuf,
-				   struct vm_area_struct *vma)
-{
-	struct drm_gem_cma_object *cma_obj = dmabuf->priv;
-	struct drm_gem_object *gem_obj = &cma_obj->base;
-	struct drm_device *dev = gem_obj->dev;
+	struct drm_gem_cma_object *cma_obj;
+	struct drm_device *dev = obj->dev;
 	int ret;
 
 	mutex_lock(&dev->struct_mutex);
-	ret = drm_gem_mmap_obj(gem_obj, gem_obj->size, vma);
+	ret = drm_gem_mmap_obj(obj, obj->size, vma);
 	mutex_unlock(&dev->struct_mutex);
 	if (ret < 0)
 		return ret;
 
+	cma_obj = to_drm_gem_cma_obj(obj);
 	return drm_gem_cma_mmap_obj(cma_obj, vma);
 }
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_mmap);
 
-static void *drm_gem_cma_dmabuf_vmap(struct dma_buf *dmabuf)
-{
-	struct drm_gem_cma_object *cma_obj = dmabuf->priv;
-
-	return cma_obj->vaddr;
-}
-
-static struct dma_buf_ops drm_gem_cma_dmabuf_ops = {
-	.attach			= drm_gem_cma_dmabuf_attach,
-	.detach			= drm_gem_cma_dmabuf_detach,
-	.map_dma_buf		= drm_gem_cma_dmabuf_map,
-	.unmap_dma_buf		= drm_gem_cma_dmabuf_unmap,
-	.kmap			= drm_gem_cma_dmabuf_kmap,
-	.kmap_atomic		= drm_gem_cma_dmabuf_kmap_atomic,
-	.kunmap			= drm_gem_cma_dmabuf_kunmap,
-	.kunmap_atomic		= drm_gem_cma_dmabuf_kunmap_atomic,
-	.mmap			= drm_gem_cma_dmabuf_mmap,
-	.vmap			= drm_gem_cma_dmabuf_vmap,
-	.release		= drm_gem_cma_dmabuf_release,
-};
-
-struct dma_buf *drm_gem_cma_dmabuf_export(struct drm_device *drm,
-					  struct drm_gem_object *obj, int flags)
+void *drm_gem_cma_prime_vmap(struct drm_gem_object *obj)
 {
 	struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
 
-	return dma_buf_export(cma_obj, &drm_gem_cma_dmabuf_ops,
-			      cma_obj->base.size, flags);
+	return cma_obj->vaddr;
 }
-EXPORT_SYMBOL_GPL(drm_gem_cma_dmabuf_export);
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vmap);
 
-struct drm_gem_object *drm_gem_cma_dmabuf_import(struct drm_device *drm,
-						 struct dma_buf *dma_buf)
+void drm_gem_cma_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
 {
-	struct drm_gem_cma_object *cma_obj;
-	struct dma_buf_attachment *attach;
-	struct sg_table *sgt;
-	int ret;
-
-	DRM_DEBUG_PRIME("%s\n", __FILE__);
-
-	/* is this one of own objects? */
-	if (dma_buf->ops == &drm_gem_cma_dmabuf_ops) {
-		struct drm_gem_object *obj;
-
-		cma_obj = dma_buf->priv;
-		obj = &cma_obj->base;
-
-		/* is it from our device? */
-		if (obj->dev == drm) {
-			/*
-			 * Importing dmabuf exported from out own gem increases
-			 * refcount on gem itself instead of f_count of dmabuf.
-			 */
-			drm_gem_object_reference(obj);
-			dma_buf_put(dma_buf);
-			return obj;
-		}
-	}
-
-	/* Create a CMA GEM buffer. */
-	cma_obj = __drm_gem_cma_create(drm, dma_buf->size);
-	if (IS_ERR(cma_obj))
-		return ERR_PTR(PTR_ERR(cma_obj));
-
-	/* Attach to the buffer and map it. Make sure the mapping is contiguous
-	 * on the device memory bus, as that's all we support.
-	 */
-	attach = dma_buf_attach(dma_buf, drm->dev);
-	if (IS_ERR(attach)) {
-		ret = -EINVAL;
-		goto error_gem_free;
-	}
-
-	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
-	if (IS_ERR_OR_NULL(sgt)) {
-		ret = sgt ? PTR_ERR(sgt) : -ENOMEM;
-		goto error_buf_detach;
-	}
-
-	if (sgt->nents != 1) {
-		ret = -EINVAL;
-		goto error_buf_unmap;
-	}
-
-	cma_obj->base.import_attach = attach;
-	cma_obj->paddr = sg_dma_address(sgt->sgl);
-	cma_obj->sgt = sgt;
-
-	DRM_DEBUG_PRIME("dma_addr = 0x%x, size = %zu\n", cma_obj->paddr,
-			dma_buf->size);
-
-	return &cma_obj->base;
-
-error_buf_unmap:
-	dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
-error_buf_detach:
-	dma_buf_detach(dma_buf, attach);
-error_gem_free:
-	drm_gem_cma_free_object(&cma_obj->base);
-	return ERR_PTR(ret);
+	/* Nothing to do */
 }
-EXPORT_SYMBOL_GPL(drm_gem_cma_dmabuf_import);
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vunmap);
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 52e0ee7..fe304f9 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -664,7 +664,7 @@
 }
 EXPORT_SYMBOL(drm_mm_clean);
 
-int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
+void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 {
 	INIT_LIST_HEAD(&mm->hole_stack);
 	INIT_LIST_HEAD(&mm->unused_nodes);
@@ -685,8 +685,6 @@
 	list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
 
 	mm->color_adjust = NULL;
-
-	return 0;
 }
 EXPORT_SYMBOL(drm_mm_init);
 
@@ -694,8 +692,8 @@
 {
 	struct drm_mm_node *entry, *next;
 
-	if (!list_empty(&mm->head_node.node_list)) {
-		DRM_ERROR("Memory manager not clean. Delaying takedown\n");
+	if (WARN(!list_empty(&mm->head_node.node_list),
+		 "Memory manager not clean. Delaying takedown\n")) {
 		return;
 	}
 
@@ -711,36 +709,37 @@
 }
 EXPORT_SYMBOL(drm_mm_takedown);
 
+static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
+				       const char *prefix)
+{
+	unsigned long hole_start, hole_end, hole_size;
+
+	if (entry->hole_follows) {
+		hole_start = drm_mm_hole_node_start(entry);
+		hole_end = drm_mm_hole_node_end(entry);
+		hole_size = hole_end - hole_start;
+		printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
+			prefix, hole_start, hole_end,
+			hole_size);
+		return hole_size;
+	}
+
+	return 0;
+}
+
 void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
 {
 	struct drm_mm_node *entry;
 	unsigned long total_used = 0, total_free = 0, total = 0;
-	unsigned long hole_start, hole_end, hole_size;
 
-	hole_start = drm_mm_hole_node_start(&mm->head_node);
-	hole_end = drm_mm_hole_node_end(&mm->head_node);
-	hole_size = hole_end - hole_start;
-	if (hole_size)
-		printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
-			prefix, hole_start, hole_end,
-			hole_size);
-	total_free += hole_size;
+	total_free += drm_mm_debug_hole(&mm->head_node, prefix);
 
 	drm_mm_for_each_node(entry, mm) {
 		printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
 			prefix, entry->start, entry->start + entry->size,
 			entry->size);
 		total_used += entry->size;
-
-		if (entry->hole_follows) {
-			hole_start = drm_mm_hole_node_start(entry);
-			hole_end = drm_mm_hole_node_end(entry);
-			hole_size = hole_end - hole_start;
-			printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
-				prefix, hole_start, hole_end,
-				hole_size);
-			total_free += hole_size;
-		}
+		total_free += drm_mm_debug_hole(entry, prefix);
 	}
 	total = total_free + total_used;
 
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 52709f2..85e450e 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -119,12 +119,13 @@
 		return;
 
 	sgt = prime_attach->sgt;
+	if (sgt) {
+		if (prime_attach->dir != DMA_NONE)
+			dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
+					prime_attach->dir);
+		sg_free_table(sgt);
+	}
 
-	if (prime_attach->dir != DMA_NONE)
-		dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
-				prime_attach->dir);
-
-	sg_free_table(sgt);
 	kfree(sgt);
 	kfree(prime_attach);
 	attach->priv = NULL;
@@ -244,7 +245,13 @@
 static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf,
 		struct vm_area_struct *vma)
 {
-	return -EINVAL;
+	struct drm_gem_object *obj = dma_buf->priv;
+	struct drm_device *dev = obj->dev;
+
+	if (!dev->driver->gem_prime_mmap)
+		return -ENOSYS;
+
+	return dev->driver->gem_prime_mmap(obj, vma);
 }
 
 static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
@@ -347,10 +354,13 @@
 out_have_obj:
 	get_dma_buf(dmabuf);
 	ret = dma_buf_fd(dmabuf, flags);
-	if (ret < 0)
+	if (ret < 0) {
 		dma_buf_put(dmabuf);
-	else
+	} else {
 		*prime_fd = ret;
+		ret = 0;
+	}
+
 	goto out;
 
 fail_rm_handle:
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 0229665..2290b3b 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -30,14 +30,14 @@
 };
 
 /**
- * drm_class_suspend - DRM class suspend hook
+ * __drm_class_suspend - internal DRM class suspend routine
  * @dev: Linux device to suspend
  * @state: power state to enter
  *
  * Just figures out what the actual struct drm_device associated with
  * @dev is and calls its suspend hook, if present.
  */
-static int drm_class_suspend(struct device *dev, pm_message_t state)
+static int __drm_class_suspend(struct device *dev, pm_message_t state)
 {
 	if (dev->type == &drm_sysfs_device_minor) {
 		struct drm_minor *drm_minor = to_drm_minor(dev);
@@ -52,6 +52,26 @@
 }
 
 /**
+ * drm_class_suspend - internal DRM class suspend hook. Simply calls
+ * __drm_class_suspend() with the correct pm state.
+ * @dev: Linux device to suspend
+ */
+static int drm_class_suspend(struct device *dev)
+{
+	return __drm_class_suspend(dev, PMSG_SUSPEND);
+}
+
+/**
+ * drm_class_freeze - internal DRM class freeze hook. Simply calls
+ * __drm_class_suspend() with the correct pm state.
+ * @dev: Linux device to freeze
+ */
+static int drm_class_freeze(struct device *dev)
+{
+	return __drm_class_suspend(dev, PMSG_FREEZE);
+}
+
+/**
  * drm_class_resume - DRM class resume hook
  * @dev: Linux device to resume
  *
@@ -72,6 +92,12 @@
 	return 0;
 }
 
+static const struct dev_pm_ops drm_class_dev_pm_ops = {
+	.suspend	= drm_class_suspend,
+	.resume		= drm_class_resume,
+	.freeze		= drm_class_freeze,
+};
+
 static char *drm_devnode(struct device *dev, umode_t *mode)
 {
 	return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
@@ -106,8 +132,7 @@
 		goto err_out;
 	}
 
-	class->suspend = drm_class_suspend;
-	class->resume = drm_class_resume;
+	class->pm = &drm_class_dev_pm_ops;
 
 	err = class_create_file(class, &class_attr_version.attr);
 	if (err)
diff --git a/drivers/gpu/drm/drm_trace.h b/drivers/gpu/drm/drm_trace.h
index 03ea964..27cc95f 100644
--- a/drivers/gpu/drm/drm_trace.h
+++ b/drivers/gpu/drm/drm_trace.h
@@ -21,7 +21,7 @@
 		    __entry->crtc = crtc;
 		    __entry->seq = seq;
 		    ),
-	    TP_printk("crtc=%d, seq=%d", __entry->crtc, __entry->seq)
+	    TP_printk("crtc=%d, seq=%u", __entry->crtc, __entry->seq)
 );
 
 TRACE_EVENT(drm_vblank_event_queued,
@@ -37,7 +37,7 @@
 		    __entry->crtc = crtc;
 		    __entry->seq = seq;
 		    ),
-	    TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \
+	    TP_printk("pid=%d, crtc=%d, seq=%u", __entry->pid, __entry->crtc, \
 		      __entry->seq)
 );
 
@@ -54,7 +54,7 @@
 		    __entry->crtc = crtc;
 		    __entry->seq = seq;
 		    ),
-	    TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \
+	    TP_printk("pid=%d, crtc=%d, seq=%u", __entry->pid, __entry->crtc, \
 		      __entry->seq)
 );
 
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c
index 4e9b5ba..95c75ed 100644
--- a/drivers/gpu/drm/exynos/exynos_ddc.c
+++ b/drivers/gpu/drm/exynos/exynos_ddc.c
@@ -53,6 +53,8 @@
 	{
 		.compatible = "samsung,exynos5-hdmiddc",
 	}, {
+		.compatible = "samsung,exynos4210-hdmiddc",
+	}, {
 		/* end node */
 	}
 };
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 57affae..b8ac06d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -24,8 +24,6 @@
 	enum dma_attr attr;
 	unsigned int nr_pages;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (buf->dma_addr) {
 		DRM_DEBUG_KMS("already allocated.\n");
 		return 0;
@@ -59,8 +57,7 @@
 		dma_addr_t start_addr;
 		unsigned int i = 0;
 
-		buf->pages = kzalloc(sizeof(struct page) * nr_pages,
-					GFP_KERNEL);
+		buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
 		if (!buf->pages) {
 			DRM_ERROR("failed to allocate pages.\n");
 			return -ENOMEM;
@@ -71,8 +68,8 @@
 					&buf->dma_attrs);
 		if (!buf->kvaddr) {
 			DRM_ERROR("failed to allocate buffer.\n");
-			kfree(buf->pages);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto err_free;
 		}
 
 		start_addr = buf->dma_addr;
@@ -109,9 +106,9 @@
 	dma_free_attrs(dev->dev, buf->size, buf->pages,
 			(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
 	buf->dma_addr = (dma_addr_t)NULL;
-
+err_free:
 	if (!is_drm_iommu_supported(dev))
-		kfree(buf->pages);
+		drm_free_large(buf->pages);
 
 	return ret;
 }
@@ -119,8 +116,6 @@
 static void lowlevel_buffer_deallocate(struct drm_device *dev,
 		unsigned int flags, struct exynos_drm_gem_buf *buf)
 {
-	DRM_DEBUG_KMS("%s.\n", __FILE__);
-
 	if (!buf->dma_addr) {
 		DRM_DEBUG_KMS("dma_addr is invalid.\n");
 		return;
@@ -138,7 +133,7 @@
 	if (!is_drm_iommu_supported(dev)) {
 		dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
 				(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
-		kfree(buf->pages);
+		drm_free_large(buf->pages);
 	} else
 		dma_free_attrs(dev->dev, buf->size, buf->pages,
 				(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
@@ -151,7 +146,6 @@
 {
 	struct exynos_drm_gem_buf *buffer;
 
-	DRM_DEBUG_KMS("%s.\n", __FILE__);
 	DRM_DEBUG_KMS("desired size = 0x%x\n", size);
 
 	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
@@ -167,8 +161,6 @@
 void exynos_drm_fini_buf(struct drm_device *dev,
 				struct exynos_drm_gem_buf *buffer)
 {
-	DRM_DEBUG_KMS("%s.\n", __FILE__);
-
 	if (!buffer) {
 		DRM_DEBUG_KMS("buffer is null.\n");
 		return;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 8bcc13a..02a8bc5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -34,7 +34,6 @@
 			struct exynos_drm_panel_info *panel)
 {
 	struct fb_videomode *timing = &panel->timing;
-	DRM_DEBUG_KMS("%s\n", __FILE__);
 
 	mode->clock = timing->pixclock / 1000;
 	mode->vrefresh = timing->refresh;
@@ -58,37 +57,6 @@
 		mode->flags |= DRM_MODE_FLAG_DBLSCAN;
 }
 
-/* convert drm_display_mode to exynos_video_timings */
-static inline void
-convert_to_video_timing(struct fb_videomode *timing,
-			struct drm_display_mode *mode)
-{
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	memset(timing, 0, sizeof(*timing));
-
-	timing->pixclock = mode->clock * 1000;
-	timing->refresh = drm_mode_vrefresh(mode);
-
-	timing->xres = mode->hdisplay;
-	timing->right_margin = mode->hsync_start - mode->hdisplay;
-	timing->hsync_len = mode->hsync_end - mode->hsync_start;
-	timing->left_margin = mode->htotal - mode->hsync_end;
-
-	timing->yres = mode->vdisplay;
-	timing->lower_margin = mode->vsync_start - mode->vdisplay;
-	timing->vsync_len = mode->vsync_end - mode->vsync_start;
-	timing->upper_margin = mode->vtotal - mode->vsync_end;
-
-	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
-		timing->vmode = FB_VMODE_INTERLACED;
-	else
-		timing->vmode = FB_VMODE_NONINTERLACED;
-
-	if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-		timing->vmode |= FB_VMODE_DOUBLE;
-}
-
 static int exynos_drm_connector_get_modes(struct drm_connector *connector)
 {
 	struct exynos_drm_connector *exynos_connector =
@@ -99,8 +67,6 @@
 	unsigned int count = 0;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (!display_ops) {
 		DRM_DEBUG_KMS("display_ops is null.\n");
 		return 0;
@@ -168,15 +134,12 @@
 					to_exynos_connector(connector);
 	struct exynos_drm_manager *manager = exynos_connector->manager;
 	struct exynos_drm_display_ops *display_ops = manager->display_ops;
-	struct fb_videomode timing;
 	int ret = MODE_BAD;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	convert_to_video_timing(&timing, mode);
-
-	if (display_ops && display_ops->check_timing)
-		if (!display_ops->check_timing(manager->dev, (void *)&timing))
+	if (display_ops && display_ops->check_mode)
+		if (!display_ops->check_mode(manager->dev, mode))
 			ret = MODE_OK;
 
 	return ret;
@@ -190,8 +153,6 @@
 	struct drm_mode_object *obj;
 	struct drm_encoder *encoder;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	obj = drm_mode_object_find(dev, exynos_connector->encoder_id,
 				   DRM_MODE_OBJECT_ENCODER);
 	if (!obj) {
@@ -234,8 +195,6 @@
 static void exynos_drm_connector_dpms(struct drm_connector *connector,
 					int mode)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * in case that drm_crtc_helper_set_mode() is called,
 	 * encoder/crtc->funcs->dpms() will be just returned
@@ -282,8 +241,6 @@
 					manager->display_ops;
 	enum drm_connector_status status = connector_status_disconnected;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (display_ops && display_ops->is_connected) {
 		if (display_ops->is_connected(manager->dev))
 			status = connector_status_connected;
@@ -299,8 +256,6 @@
 	struct exynos_drm_connector *exynos_connector =
 		to_exynos_connector(connector);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	drm_sysfs_connector_remove(connector);
 	drm_connector_cleanup(connector);
 	kfree(exynos_connector);
@@ -322,8 +277,6 @@
 	int type;
 	int err;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
 	if (!exynos_connector) {
 		DRM_ERROR("failed to allocate connector\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 4667c9f..1bef6dc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -27,8 +27,6 @@
 	struct drm_connector *connector;
 	int ret;
 
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	subdrv->manager->dev = subdrv->dev;
 
 	/* create and initialize a encoder for this sub driver. */
@@ -102,8 +100,6 @@
 static void exynos_drm_subdrv_remove(struct drm_device *dev,
 				      struct exynos_drm_subdrv *subdrv)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	if (subdrv->remove)
 		subdrv->remove(dev, subdrv->dev);
 }
@@ -114,8 +110,6 @@
 	unsigned int fine_cnt = 0;
 	int err;
 
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	if (!dev)
 		return -EINVAL;
 
@@ -158,8 +152,6 @@
 {
 	struct exynos_drm_subdrv *subdrv;
 
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	if (!dev) {
 		WARN(1, "Unexpected drm device unregister!\n");
 		return -EINVAL;
@@ -176,8 +168,6 @@
 
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	if (!subdrv)
 		return -EINVAL;
 
@@ -189,8 +179,6 @@
 
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	if (!subdrv)
 		return -EINVAL;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 073c10a..9a35d17 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -76,8 +76,6 @@
 
 static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* drm framework doesn't check NULL. */
 }
 
@@ -85,8 +83,6 @@
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
 	exynos_plane_commit(exynos_crtc->plane);
 	exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
@@ -97,8 +93,6 @@
 			    const struct drm_display_mode *mode,
 			    struct drm_display_mode *adjusted_mode)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* drm framework doesn't check NULL */
 	return true;
 }
@@ -115,8 +109,6 @@
 	int pipe = exynos_crtc->pipe;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * copy the mode data adjusted by mode_fixup() into crtc->mode
 	 * so that hardware can be seet to proper mode.
@@ -139,7 +131,7 @@
 	return 0;
 }
 
-static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
 					  struct drm_framebuffer *old_fb)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
@@ -148,8 +140,6 @@
 	unsigned int crtc_h;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* when framebuffer changing is requested, crtc's dpms should be on */
 	if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
 		DRM_ERROR("failed framebuffer changing request.\n");
@@ -169,12 +159,16 @@
 	return 0;
 }
 
+static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+					  struct drm_framebuffer *old_fb)
+{
+	return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb);
+}
+
 static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF);
 	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 }
@@ -199,8 +193,6 @@
 	struct drm_framebuffer *old_fb = crtc->fb;
 	int ret = -EINVAL;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* when the page flip is requested, crtc's dpms should be on */
 	if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
 		DRM_ERROR("failed page flip request.\n");
@@ -230,7 +222,7 @@
 		spin_unlock_irq(&dev->event_lock);
 
 		crtc->fb = fb;
-		ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
+		ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
 						    NULL);
 		if (ret) {
 			crtc->fb = old_fb;
@@ -253,8 +245,6 @@
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 	struct exynos_drm_private *private = crtc->dev->dev_private;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	private->crtc[exynos_crtc->pipe] = NULL;
 
 	drm_crtc_cleanup(crtc);
@@ -269,8 +259,6 @@
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (property == dev_priv->crtc_mode_property) {
 		enum exynos_crtc_mode mode = val;
 
@@ -315,8 +303,6 @@
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 	struct drm_property *prop;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	prop = dev_priv->crtc_mode_property;
 	if (!prop) {
 		prop = drm_property_create_enum(dev, 0, "mode", mode_names,
@@ -336,8 +322,6 @@
 	struct exynos_drm_private *private = dev->dev_private;
 	struct drm_crtc *crtc;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
 	if (!exynos_crtc) {
 		DRM_ERROR("failed to allocate exynos crtc\n");
@@ -372,8 +356,6 @@
 	struct exynos_drm_crtc *exynos_crtc =
 		to_exynos_crtc(private->crtc[crtc]);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
 		return -EPERM;
 
@@ -389,8 +371,6 @@
 	struct exynos_drm_crtc *exynos_crtc =
 		to_exynos_crtc(private->crtc[crtc]);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
 		return;
 
@@ -406,8 +386,6 @@
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
 	unsigned long flags;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	spin_lock_irqsave(&dev->event_lock, flags);
 
 	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index ff7f2a8..a0f997e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -71,8 +71,6 @@
 	unsigned int i;
 	int nents, ret;
 
-	DRM_DEBUG_PRIME("%s\n", __FILE__);
-
 	/* just return current sgt if already requested. */
 	if (exynos_attach->dir == dir && exynos_attach->is_mapped)
 		return &exynos_attach->sgt;
@@ -133,8 +131,6 @@
 {
 	struct exynos_drm_gem_obj *exynos_gem_obj = dmabuf->priv;
 
-	DRM_DEBUG_PRIME("%s\n", __FILE__);
-
 	/*
 	 * exynos_dmabuf_release() call means that file object's
 	 * f_count is 0 and it calls drm_gem_object_handle_unreference()
@@ -219,8 +215,6 @@
 	struct exynos_drm_gem_buf *buffer;
 	int ret;
 
-	DRM_DEBUG_PRIME("%s\n", __FILE__);
-
 	/* is this one of own objects? */
 	if (dma_buf->ops == &exynos_dmabuf_ops) {
 		struct drm_gem_object *obj;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index ba6d995..ca2729a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -46,8 +46,6 @@
 	int ret;
 	int nr;
 
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
 	if (!private) {
 		DRM_ERROR("failed to allocate private\n");
@@ -140,8 +138,6 @@
 
 static int exynos_drm_unload(struct drm_device *dev)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	exynos_drm_fbdev_fini(dev);
 	exynos_drm_device_unregister(dev);
 	drm_vblank_cleanup(dev);
@@ -159,8 +155,7 @@
 static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 {
 	struct drm_exynos_file_private *file_priv;
-
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
+	int ret;
 
 	file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
 	if (!file_priv)
@@ -168,7 +163,13 @@
 
 	file->driver_priv = file_priv;
 
-	return exynos_drm_subdrv_open(dev, file);
+	ret = exynos_drm_subdrv_open(dev, file);
+	if (ret) {
+		kfree(file_priv);
+		file->driver_priv = NULL;
+	}
+
+	return ret;
 }
 
 static void exynos_drm_preclose(struct drm_device *dev,
@@ -178,8 +179,6 @@
 	struct drm_pending_vblank_event *e, *t;
 	unsigned long flags;
 
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	/* release events of current file */
 	spin_lock_irqsave(&dev->event_lock, flags);
 	list_for_each_entry_safe(e, t, &private->pageflip_event_list,
@@ -196,8 +195,6 @@
 
 static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	if (!file->driver_priv)
 		return;
 
@@ -207,8 +204,6 @@
 
 static void exynos_drm_lastclose(struct drm_device *dev)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	exynos_drm_fbdev_restore_mode(dev);
 }
 
@@ -292,8 +287,6 @@
 
 static int exynos_drm_platform_probe(struct platform_device *pdev)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 	exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
 
@@ -302,8 +295,6 @@
 
 static int exynos_drm_platform_remove(struct platform_device *pdev)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	drm_platform_exit(&exynos_drm_driver, pdev);
 
 	return 0;
@@ -322,8 +313,6 @@
 {
 	int ret;
 
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 #ifdef CONFIG_DRM_EXYNOS_FIMD
 	ret = platform_driver_register(&fimd_driver);
 	if (ret < 0)
@@ -455,8 +444,6 @@
 
 static void __exit exynos_drm_exit(void)
 {
-	DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
 	platform_device_unregister(exynos_drm_pdev);
 
 	platform_driver_unregister(&exynos_drm_platform_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 680a7c1..eaa1966 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -142,7 +142,7 @@
  * @is_connected: check for that display is connected or not.
  * @get_edid: get edid modes from display driver.
  * @get_panel: get panel object from display driver.
- * @check_timing: check if timing is valid or not.
+ * @check_mode: check if mode is valid or not.
  * @power_on: display device on or off.
  */
 struct exynos_drm_display_ops {
@@ -151,7 +151,7 @@
 	struct edid *(*get_edid)(struct device *dev,
 			struct drm_connector *connector);
 	void *(*get_panel)(struct device *dev);
-	int (*check_timing)(struct device *dev, void *timing);
+	int (*check_mode)(struct device *dev, struct drm_display_mode *mode);
 	int (*power_on)(struct device *dev, int mode);
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index c63721f..a99a033 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -61,7 +61,7 @@
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 
-	DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
+	DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
 
 	if (exynos_encoder->dpms == mode) {
 		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
@@ -104,8 +104,6 @@
 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (connector->encoder == encoder)
 			if (manager_ops && manager_ops->mode_fixup)
@@ -155,8 +153,6 @@
 	struct exynos_drm_manager *manager;
 	struct exynos_drm_manager_ops *manager_ops;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (connector->encoder == encoder) {
 			struct exynos_drm_encoder *exynos_encoder;
@@ -189,8 +185,6 @@
 
 static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* drm framework doesn't check NULL. */
 }
 
@@ -200,8 +194,6 @@
 	struct exynos_drm_manager *manager = exynos_encoder->manager;
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (manager_ops && manager_ops->commit)
 		manager_ops->commit(manager->dev);
 
@@ -274,8 +266,6 @@
 	struct exynos_drm_encoder *exynos_encoder =
 		to_exynos_encoder(encoder);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_encoder->manager->pipe = -1;
 
 	drm_encoder_cleanup(encoder);
@@ -315,8 +305,6 @@
 {
 	struct drm_encoder *encoder;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
 		encoder->possible_clones = exynos_drm_encoder_clones(encoder);
 }
@@ -329,8 +317,6 @@
 	struct drm_encoder *encoder;
 	struct exynos_drm_encoder *exynos_encoder;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (!manager || !possible_crtcs)
 		return NULL;
 
@@ -427,8 +413,6 @@
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	int mode = *(int *)data;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (manager_ops && manager_ops->dpms)
 		manager_ops->dpms(manager->dev, mode);
 
@@ -449,8 +433,6 @@
 		to_exynos_encoder(encoder)->manager;
 	int pipe = *(int *)data;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * when crtc is detached from encoder, this pipe is used
 	 * to select manager operation
@@ -465,8 +447,6 @@
 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
 	struct exynos_drm_overlay *overlay = data;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (overlay_ops && overlay_ops->mode_set)
 		overlay_ops->mode_set(manager->dev, overlay);
 }
@@ -478,8 +458,6 @@
 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
 	int zpos = DEFAULT_ZPOS;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (data)
 		zpos = *(int *)data;
 
@@ -494,8 +472,6 @@
 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
 	int zpos = DEFAULT_ZPOS;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (data)
 		zpos = *(int *)data;
 
@@ -510,8 +486,6 @@
 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
 	int zpos = DEFAULT_ZPOS;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (data)
 		zpos = *(int *)data;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 0e04f4e..c2d149f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -70,8 +70,6 @@
 	struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
 	unsigned int i;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* make sure that overlay data are updated before relesing fb. */
 	exynos_drm_encoder_complete_scanout(fb);
 
@@ -97,8 +95,6 @@
 {
 	struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* This fb should have only one gem object. */
 	if (WARN_ON(exynos_fb->buf_cnt != 1))
 		return -EINVAL;
@@ -112,8 +108,6 @@
 				unsigned color, struct drm_clip_rect *clips,
 				unsigned num_clips)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* TODO */
 
 	return 0;
@@ -225,8 +219,6 @@
 	struct exynos_drm_fb *exynos_fb;
 	int i, ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
 	if (!exynos_fb) {
 		DRM_ERROR("failed to allocate exynos drm framebuffer\n");
@@ -293,8 +285,6 @@
 	struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
 	struct exynos_drm_gem_buf *buffer;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (index >= MAX_FB_BUFFER)
 		return NULL;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 8f007aa..8e60bd6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -43,8 +43,6 @@
 	unsigned long vm_size;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
 
 	vm_size = vma->vm_end - vma->vm_start;
@@ -84,8 +82,6 @@
 	unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
 	unsigned long offset;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
 	drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
 
@@ -148,8 +144,6 @@
 	unsigned long size;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
 			sizes->surface_width, sizes->surface_height,
 			sizes->surface_bpp);
@@ -238,8 +232,6 @@
 	unsigned int num_crtc;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
 		return 0;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 4a1616a..61b094f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -175,8 +175,6 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* stop dma operation */
 	cfg = fimc_read(EXYNOS_CISTATUS);
 	if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg)) {
@@ -210,8 +208,6 @@
 
 static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx)
 {
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK,
 				  SYSREG_FIMD0WB_DEST_MASK,
 				  ctx->id << SYSREG_FIMD0WB_DEST_SHIFT);
@@ -221,7 +217,7 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:wb[%d]\n", __func__, wb);
+	DRM_DEBUG_KMS("wb[%d]\n", wb);
 
 	cfg = fimc_read(EXYNOS_CIGCTRL);
 	cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK |
@@ -257,10 +253,10 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:inv_pclk[%d]inv_vsync[%d]\n",
-		__func__, pol->inv_pclk, pol->inv_vsync);
-	DRM_DEBUG_KMS("%s:inv_href[%d]inv_hsync[%d]\n",
-		__func__, pol->inv_href, pol->inv_hsync);
+	DRM_DEBUG_KMS("inv_pclk[%d]inv_vsync[%d]\n",
+		pol->inv_pclk, pol->inv_vsync);
+	DRM_DEBUG_KMS("inv_href[%d]inv_hsync[%d]\n",
+		pol->inv_href, pol->inv_hsync);
 
 	cfg = fimc_read(EXYNOS_CIGCTRL);
 	cfg &= ~(EXYNOS_CIGCTRL_INVPOLPCLK | EXYNOS_CIGCTRL_INVPOLVSYNC |
@@ -282,7 +278,7 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+	DRM_DEBUG_KMS("enable[%d]\n", enable);
 
 	cfg = fimc_read(EXYNOS_CIGCTRL);
 	if (enable)
@@ -298,7 +294,7 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:enable[%d]overflow[%d]level[%d]\n", __func__,
+	DRM_DEBUG_KMS("enable[%d]overflow[%d]level[%d]\n",
 			enable, overflow, level);
 
 	cfg = fimc_read(EXYNOS_CIGCTRL);
@@ -319,8 +315,6 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	cfg = fimc_read(EXYNOS_CIGCTRL);
 	cfg |= EXYNOS_CIGCTRL_IRQ_CLR;
 	fimc_write(cfg, EXYNOS_CIGCTRL);
@@ -335,7 +329,7 @@
 	flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB |
 		EXYNOS_CISTATUS_OVFICR;
 
-	DRM_DEBUG_KMS("%s:flag[0x%x]\n", __func__, flag);
+	DRM_DEBUG_KMS("flag[0x%x]\n", flag);
 
 	if (status & flag) {
 		cfg = fimc_read(EXYNOS_CIWDOFST);
@@ -364,7 +358,7 @@
 
 	cfg = fimc_read(EXYNOS_CISTATUS);
 
-	DRM_DEBUG_KMS("%s:cfg[0x%x]\n", __func__, cfg);
+	DRM_DEBUG_KMS("cfg[0x%x]\n", cfg);
 
 	if (!(cfg & EXYNOS_CISTATUS_FRAMEEND))
 		return false;
@@ -380,15 +374,13 @@
 	u32 cfg;
 	int frame_cnt, buf_id;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	cfg = fimc_read(EXYNOS_CISTATUS2);
 	frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg);
 
 	if (frame_cnt == 0)
 		frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg);
 
-	DRM_DEBUG_KMS("%s:present[%d]before[%d]\n", __func__,
+	DRM_DEBUG_KMS("present[%d]before[%d]\n",
 		EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg),
 		EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg));
 
@@ -398,7 +390,7 @@
 	}
 
 	buf_id = frame_cnt - 1;
-	DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, buf_id);
+	DRM_DEBUG_KMS("buf_id[%d]\n", buf_id);
 
 	return buf_id;
 }
@@ -407,7 +399,7 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+	DRM_DEBUG_KMS("enable[%d]\n", enable);
 
 	cfg = fimc_read(EXYNOS_CIOCTRL);
 	if (enable)
@@ -424,7 +416,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
 
 	/* RGB */
 	cfg = fimc_read(EXYNOS_CISCCTRL);
@@ -497,7 +489,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
 
 	cfg = fimc_read(EXYNOS_MSCTRL);
 	cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB;
@@ -557,8 +549,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg1, cfg2;
 
-	DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
-		degree, flip);
+	DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
 
 	cfg1 = fimc_read(EXYNOS_MSCTRL);
 	cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR |
@@ -621,10 +612,9 @@
 	v1 = pos->y;
 	v2 = sz->vsize - pos->h - pos->y;
 
-	DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
-	__func__, pos->x, pos->y, pos->w, pos->h, sz->hsize, sz->vsize);
-	DRM_DEBUG_KMS("%s:h1[%d]h2[%d]v1[%d]v2[%d]\n", __func__,
-		h1, h2, v1, v2);
+	DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
+		pos->x, pos->y, pos->w, pos->h, sz->hsize, sz->vsize);
+	DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2);
 
 	/*
 	 * set window offset 1, 2 size
@@ -653,8 +643,8 @@
 	struct drm_exynos_sz img_sz = *sz;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:swap[%d]hsize[%d]vsize[%d]\n",
-		__func__, swap, sz->hsize, sz->vsize);
+	DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n",
+		swap, sz->hsize, sz->vsize);
 
 	/* original size */
 	cfg = (EXYNOS_ORGISIZE_HORIZONTAL(img_sz.hsize) |
@@ -662,8 +652,7 @@
 
 	fimc_write(cfg, EXYNOS_ORGISIZE);
 
-	DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]\n", __func__,
-		pos->x, pos->y, pos->w, pos->h);
+	DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h);
 
 	if (swap) {
 		img_pos.w = pos->h;
@@ -720,7 +709,7 @@
 
 	property = &c_node->property;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
+	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
 		property->prop_id, buf_id, buf_type);
 
 	if (buf_id > FIMC_MAX_SRC) {
@@ -772,7 +761,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
 
 	/* RGB */
 	cfg = fimc_read(EXYNOS_CISCCTRL);
@@ -851,7 +840,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
 
 	cfg = fimc_read(EXYNOS_CIEXTEN);
 
@@ -919,8 +908,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
-		degree, flip);
+	DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
 
 	cfg = fimc_read(EXYNOS_CITRGFMT);
 	cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK;
@@ -970,7 +958,7 @@
 
 static int fimc_get_ratio_shift(u32 src, u32 dst, u32 *ratio, u32 *shift)
 {
-	DRM_DEBUG_KMS("%s:src[%d]dst[%d]\n", __func__, src, dst);
+	DRM_DEBUG_KMS("src[%d]dst[%d]\n", src, dst);
 
 	if (src >= dst * 64) {
 		DRM_ERROR("failed to make ratio and shift.\n");
@@ -1039,20 +1027,20 @@
 
 	pre_dst_width = src_w / pre_hratio;
 	pre_dst_height = src_h / pre_vratio;
-	DRM_DEBUG_KMS("%s:pre_dst_width[%d]pre_dst_height[%d]\n", __func__,
+	DRM_DEBUG_KMS("pre_dst_width[%d]pre_dst_height[%d]\n",
 		pre_dst_width, pre_dst_height);
-	DRM_DEBUG_KMS("%s:pre_hratio[%d]hfactor[%d]pre_vratio[%d]vfactor[%d]\n",
-		__func__, pre_hratio, hfactor, pre_vratio, vfactor);
+	DRM_DEBUG_KMS("pre_hratio[%d]hfactor[%d]pre_vratio[%d]vfactor[%d]\n",
+		pre_hratio, hfactor, pre_vratio, vfactor);
 
 	sc->hratio = (src_w << 14) / (dst_w << hfactor);
 	sc->vratio = (src_h << 14) / (dst_h << vfactor);
 	sc->up_h = (dst_w >= src_w) ? true : false;
 	sc->up_v = (dst_h >= src_h) ? true : false;
-	DRM_DEBUG_KMS("%s:hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n",
-	__func__, sc->hratio, sc->vratio, sc->up_h, sc->up_v);
+	DRM_DEBUG_KMS("hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n",
+		sc->hratio, sc->vratio, sc->up_h, sc->up_v);
 
 	shfactor = FIMC_SHFACTOR - (hfactor + vfactor);
-	DRM_DEBUG_KMS("%s:shfactor[%d]\n", __func__, shfactor);
+	DRM_DEBUG_KMS("shfactor[%d]\n", shfactor);
 
 	cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) |
 		EXYNOS_CISCPRERATIO_PREHORRATIO(pre_hratio) |
@@ -1070,10 +1058,10 @@
 {
 	u32 cfg, cfg_ext;
 
-	DRM_DEBUG_KMS("%s:range[%d]bypass[%d]up_h[%d]up_v[%d]\n",
-		__func__, sc->range, sc->bypass, sc->up_h, sc->up_v);
-	DRM_DEBUG_KMS("%s:hratio[%d]vratio[%d]\n",
-		__func__, sc->hratio, sc->vratio);
+	DRM_DEBUG_KMS("range[%d]bypass[%d]up_h[%d]up_v[%d]\n",
+		sc->range, sc->bypass, sc->up_h, sc->up_v);
+	DRM_DEBUG_KMS("hratio[%d]vratio[%d]\n",
+		sc->hratio, sc->vratio);
 
 	cfg = fimc_read(EXYNOS_CISCCTRL);
 	cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS |
@@ -1113,8 +1101,8 @@
 	struct drm_exynos_sz img_sz = *sz;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:swap[%d]hsize[%d]vsize[%d]\n",
-		__func__, swap, sz->hsize, sz->vsize);
+	DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n",
+		swap, sz->hsize, sz->vsize);
 
 	/* original size */
 	cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(img_sz.hsize) |
@@ -1122,8 +1110,7 @@
 
 	fimc_write(cfg, EXYNOS_ORGOSIZE);
 
-	DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]\n",
-		__func__, pos->x, pos->y, pos->w, pos->h);
+	DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h);
 
 	/* CSC ITU */
 	cfg = fimc_read(EXYNOS_CIGCTRL);
@@ -1180,7 +1167,7 @@
 		if (cfg & (mask << i))
 			buf_num++;
 
-	DRM_DEBUG_KMS("%s:buf_num[%d]\n", __func__, buf_num);
+	DRM_DEBUG_KMS("buf_num[%d]\n", buf_num);
 
 	return buf_num;
 }
@@ -1194,8 +1181,7 @@
 	u32 mask = 0x00000001 << buf_id;
 	int ret = 0;
 
-	DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__,
-		buf_id, buf_type);
+	DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
 
 	mutex_lock(&ctx->lock);
 
@@ -1252,7 +1238,7 @@
 
 	property = &c_node->property;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
+	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
 		property->prop_id, buf_id, buf_type);
 
 	if (buf_id > FIMC_MAX_DST) {
@@ -1302,7 +1288,7 @@
 
 static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable)
 {
-	DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+	DRM_DEBUG_KMS("enable[%d]\n", enable);
 
 	if (enable) {
 		clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
@@ -1326,7 +1312,7 @@
 		c_node->event_work;
 	int buf_id;
 
-	DRM_DEBUG_KMS("%s:fimc id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("fimc id[%d]\n", ctx->id);
 
 	fimc_clear_irq(ctx);
 	if (fimc_check_ovf(ctx))
@@ -1339,7 +1325,7 @@
 	if (buf_id < 0)
 		return IRQ_HANDLED;
 
-	DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, buf_id);
+	DRM_DEBUG_KMS("buf_id[%d]\n", buf_id);
 
 	if (fimc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE) < 0) {
 		DRM_ERROR("failed to dequeue.\n");
@@ -1357,8 +1343,6 @@
 {
 	struct drm_exynos_ipp_prop_list *prop_list;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL);
 	if (!prop_list) {
 		DRM_ERROR("failed to alloc property list.\n");
@@ -1402,7 +1386,7 @@
 	case EXYNOS_DRM_FLIP_BOTH:
 		return true;
 	default:
-		DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
+		DRM_DEBUG_KMS("invalid flip\n");
 		return false;
 	}
 }
@@ -1419,8 +1403,6 @@
 	bool swap;
 	int i;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	for_each_ipp_ops(i) {
 		if ((i == EXYNOS_DRM_OPS_SRC) &&
 			(property->cmd == IPP_CMD_WB))
@@ -1526,8 +1508,6 @@
 {
 	int i;
 
-	DRM_DEBUG_KMS("%s:\n", __func__);
-
 	for (i = 0; i < FIMC_MAX_SRC; i++) {
 		fimc_write(0, EXYNOS_CIIYSA(i));
 		fimc_write(0, EXYNOS_CIICBSA(i));
@@ -1545,8 +1525,6 @@
 {
 	struct fimc_context *ctx = get_fimc_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* reset h/w block */
 	fimc_sw_reset(ctx);
 
@@ -1570,7 +1548,7 @@
 	int ret, i;
 	u32 cfg0, cfg1;
 
-	DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
+	DRM_DEBUG_KMS("cmd[%d]\n", cmd);
 
 	if (!c_node) {
 		DRM_ERROR("failed to get c_node.\n");
@@ -1679,7 +1657,7 @@
 	struct drm_exynos_ipp_set_wb set_wb = {0, 0};
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
+	DRM_DEBUG_KMS("cmd[%d]\n", cmd);
 
 	switch (cmd) {
 	case IPP_CMD_M2M:
@@ -1869,8 +1847,7 @@
 		goto err_put_clk;
 	}
 
-	DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
-		(int)ippdrv);
+	DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
 
 	mutex_init(&ctx->lock);
 	platform_set_drvdata(pdev, ctx);
@@ -1917,7 +1894,7 @@
 {
 	struct fimc_context *ctx = get_fimc_context(dev);
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("id[%d]\n", ctx->id);
 
 	if (pm_runtime_suspended(dev))
 		return 0;
@@ -1929,7 +1906,7 @@
 {
 	struct fimc_context *ctx = get_fimc_context(dev);
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("id[%d]\n", ctx->id);
 
 	if (!pm_runtime_suspended(dev))
 		return fimc_clk_ctrl(ctx, true);
@@ -1943,7 +1920,7 @@
 {
 	struct fimc_context *ctx = get_fimc_context(dev);
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("id[%d]\n", ctx->id);
 
 	return  fimc_clk_ctrl(ctx, false);
 }
@@ -1952,7 +1929,7 @@
 {
 	struct fimc_context *ctx = get_fimc_context(dev);
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("id[%d]\n", ctx->id);
 
 	return  fimc_clk_ctrl(ctx, true);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 97c61db..3e106be 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -63,14 +63,24 @@
 
 struct fimd_driver_data {
 	unsigned int timing_base;
+
+	unsigned int has_shadowcon:1;
+	unsigned int has_clksel:1;
+};
+
+static struct fimd_driver_data s3c64xx_fimd_driver_data = {
+	.timing_base = 0x0,
+	.has_clksel = 1,
 };
 
 static struct fimd_driver_data exynos4_fimd_driver_data = {
 	.timing_base = 0x0,
+	.has_shadowcon = 1,
 };
 
 static struct fimd_driver_data exynos5_fimd_driver_data = {
 	.timing_base = 0x20000,
+	.has_shadowcon = 1,
 };
 
 struct fimd_win_data {
@@ -107,10 +117,13 @@
 	atomic_t			wait_vsync_event;
 
 	struct exynos_drm_panel_info *panel;
+	struct fimd_driver_data *driver_data;
 };
 
 #ifdef CONFIG_OF
 static const struct of_device_id fimd_driver_dt_match[] = {
+	{ .compatible = "samsung,s3c6400-fimd",
+	  .data = &s3c64xx_fimd_driver_data },
 	{ .compatible = "samsung,exynos4210-fimd",
 	  .data = &exynos4_fimd_driver_data },
 	{ .compatible = "samsung,exynos5250-fimd",
@@ -137,8 +150,6 @@
 
 static bool fimd_display_is_connected(struct device *dev)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* TODO. */
 
 	return true;
@@ -148,15 +159,11 @@
 {
 	struct fimd_context *ctx = get_fimd_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	return ctx->panel;
 }
 
-static int fimd_check_timing(struct device *dev, void *timing)
+static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* TODO. */
 
 	return 0;
@@ -164,8 +171,6 @@
 
 static int fimd_display_power_on(struct device *dev, int mode)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* TODO */
 
 	return 0;
@@ -175,7 +180,7 @@
 	.type = EXYNOS_DISPLAY_TYPE_LCD,
 	.is_connected = fimd_display_is_connected,
 	.get_panel = fimd_get_panel,
-	.check_timing = fimd_check_timing,
+	.check_mode = fimd_check_mode,
 	.power_on = fimd_display_power_on,
 };
 
@@ -183,7 +188,7 @@
 {
 	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+	DRM_DEBUG_KMS("%d\n", mode);
 
 	mutex_lock(&ctx->lock);
 
@@ -221,8 +226,6 @@
 	struct fimd_win_data *win_data;
 	int i;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	for (i = 0; i < WINDOWS_NR; i++) {
 		win_data = &ctx->win_data[i];
 		if (win_data->enabled && (ovl_ops && ovl_ops->commit))
@@ -239,15 +242,12 @@
 	struct exynos_drm_panel_info *panel = ctx->panel;
 	struct fb_videomode *timing = &panel->timing;
 	struct fimd_driver_data *driver_data;
-	struct platform_device *pdev = to_platform_device(dev);
 	u32 val;
 
-	driver_data = drm_fimd_get_driver_data(pdev);
+	driver_data = ctx->driver_data;
 	if (ctx->suspended)
 		return;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* setup polarity values from machine code. */
 	writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
 
@@ -274,6 +274,11 @@
 	val = ctx->vidcon0;
 	val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
 
+	if (ctx->driver_data->has_clksel) {
+		val &= ~VIDCON0_CLKSEL_MASK;
+		val |= VIDCON0_CLKSEL_LCD;
+	}
+
 	if (ctx->clkdiv > 1)
 		val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
 	else
@@ -292,8 +297,6 @@
 	struct fimd_context *ctx = get_fimd_context(dev);
 	u32 val;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ctx->suspended)
 		return -EPERM;
 
@@ -319,8 +322,6 @@
 	struct fimd_context *ctx = get_fimd_context(dev);
 	u32 val;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ctx->suspended)
 		return;
 
@@ -370,8 +371,6 @@
 	int win;
 	unsigned long offset;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (!overlay) {
 		dev_err(dev, "overlay is NULL\n");
 		return;
@@ -381,7 +380,7 @@
 	if (win == DEFAULT_ZPOS)
 		win = ctx->default_win;
 
-	if (win < 0 || win > WINDOWS_NR)
+	if (win < 0 || win >= WINDOWS_NR)
 		return;
 
 	offset = overlay->fb_x * (overlay->bpp >> 3);
@@ -418,8 +417,6 @@
 	struct fimd_win_data *win_data = &ctx->win_data[win];
 	unsigned long val;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	val = WINCONx_ENWIN;
 
 	switch (win_data->bpp) {
@@ -478,8 +475,6 @@
 	struct fimd_context *ctx = get_fimd_context(dev);
 	unsigned int keycon0 = 0, keycon1 = 0;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
 			WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
 
@@ -489,6 +484,33 @@
 	writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
 }
 
+/**
+ * shadow_protect_win() - disable updating values from shadow registers at vsync
+ *
+ * @win: window to protect registers for
+ * @protect: 1 to protect (disable updates)
+ */
+static void fimd_shadow_protect_win(struct fimd_context *ctx,
+							int win, bool protect)
+{
+	u32 reg, bits, val;
+
+	if (ctx->driver_data->has_shadowcon) {
+		reg = SHADOWCON;
+		bits = SHADOWCON_WINx_PROTECT(win);
+	} else {
+		reg = PRTCON;
+		bits = PRTCON_PROTECT;
+	}
+
+	val = readl(ctx->regs + reg);
+	if (protect)
+		val |= bits;
+	else
+		val &= ~bits;
+	writel(val, ctx->regs + reg);
+}
+
 static void fimd_win_commit(struct device *dev, int zpos)
 {
 	struct fimd_context *ctx = get_fimd_context(dev);
@@ -498,21 +520,19 @@
 	unsigned int last_x;
 	unsigned int last_y;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ctx->suspended)
 		return;
 
 	if (win == DEFAULT_ZPOS)
 		win = ctx->default_win;
 
-	if (win < 0 || win > WINDOWS_NR)
+	if (win < 0 || win >= WINDOWS_NR)
 		return;
 
 	win_data = &ctx->win_data[win];
 
 	/*
-	 * SHADOWCON register is used for enabling timing.
+	 * SHADOWCON/PRTCON register is used for enabling timing.
 	 *
 	 * for example, once only width value of a register is set,
 	 * if the dma is started then fimd hardware could malfunction so
@@ -522,9 +542,7 @@
 	 */
 
 	/* protect windows */
-	val = readl(ctx->regs + SHADOWCON);
-	val |= SHADOWCON_WINx_PROTECT(win);
-	writel(val, ctx->regs + SHADOWCON);
+	fimd_shadow_protect_win(ctx, win, true);
 
 	/* buffer start address */
 	val = (unsigned long)win_data->dma_addr;
@@ -602,10 +620,13 @@
 	writel(val, ctx->regs + WINCON(win));
 
 	/* Enable DMA channel and unprotect windows */
-	val = readl(ctx->regs + SHADOWCON);
-	val |= SHADOWCON_CHx_ENABLE(win);
-	val &= ~SHADOWCON_WINx_PROTECT(win);
-	writel(val, ctx->regs + SHADOWCON);
+	fimd_shadow_protect_win(ctx, win, false);
+
+	if (ctx->driver_data->has_shadowcon) {
+		val = readl(ctx->regs + SHADOWCON);
+		val |= SHADOWCON_CHx_ENABLE(win);
+		writel(val, ctx->regs + SHADOWCON);
+	}
 
 	win_data->enabled = true;
 }
@@ -617,12 +638,10 @@
 	int win = zpos;
 	u32 val;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (win == DEFAULT_ZPOS)
 		win = ctx->default_win;
 
-	if (win < 0 || win > WINDOWS_NR)
+	if (win < 0 || win >= WINDOWS_NR)
 		return;
 
 	win_data = &ctx->win_data[win];
@@ -634,9 +653,7 @@
 	}
 
 	/* protect windows */
-	val = readl(ctx->regs + SHADOWCON);
-	val |= SHADOWCON_WINx_PROTECT(win);
-	writel(val, ctx->regs + SHADOWCON);
+	fimd_shadow_protect_win(ctx, win, true);
 
 	/* wincon */
 	val = readl(ctx->regs + WINCON(win));
@@ -644,10 +661,13 @@
 	writel(val, ctx->regs + WINCON(win));
 
 	/* unprotect windows */
-	val = readl(ctx->regs + SHADOWCON);
-	val &= ~SHADOWCON_CHx_ENABLE(win);
-	val &= ~SHADOWCON_WINx_PROTECT(win);
-	writel(val, ctx->regs + SHADOWCON);
+	if (ctx->driver_data->has_shadowcon) {
+		val = readl(ctx->regs + SHADOWCON);
+		val &= ~SHADOWCON_CHx_ENABLE(win);
+		writel(val, ctx->regs + SHADOWCON);
+	}
+
+	fimd_shadow_protect_win(ctx, win, false);
 
 	win_data->enabled = false;
 }
@@ -697,8 +717,6 @@
 
 static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * enable drm irq mode.
 	 * - with irq_enabled = 1, we can use the vblank feature.
@@ -725,8 +743,6 @@
 
 static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* detach this sub driver from iommu mapping if supported. */
 	if (is_drm_iommu_supported(drm_dev))
 		drm_iommu_detach_device(drm_dev, dev);
@@ -741,8 +757,6 @@
 	u32 best_framerate = 0;
 	u32 framerate;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	retrace = timing->left_margin + timing->hsync_len +
 				timing->right_margin + timing->xres;
 	retrace *= timing->upper_margin + timing->vsync_len +
@@ -777,10 +791,6 @@
 
 static void fimd_clear_win(struct fimd_context *ctx, int win)
 {
-	u32 val;
-
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	writel(0, ctx->regs + WINCON(win));
 	writel(0, ctx->regs + VIDOSD_A(win));
 	writel(0, ctx->regs + VIDOSD_B(win));
@@ -789,15 +799,11 @@
 	if (win == 1 || win == 2)
 		writel(0, ctx->regs + VIDOSD_D(win));
 
-	val = readl(ctx->regs + SHADOWCON);
-	val &= ~SHADOWCON_WINx_PROTECT(win);
-	writel(val, ctx->regs + SHADOWCON);
+	fimd_shadow_protect_win(ctx, win, false);
 }
 
 static int fimd_clock(struct fimd_context *ctx, bool enable)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (enable) {
 		int ret;
 
@@ -883,8 +889,6 @@
 	int win;
 	int ret = -EINVAL;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (dev->of_node) {
 		pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 		if (!pdata) {
@@ -949,6 +953,7 @@
 		return ret;
 	}
 
+	ctx->driver_data = drm_fimd_get_driver_data(pdev);
 	ctx->vidcon0 = pdata->vidcon0;
 	ctx->vidcon1 = pdata->vidcon1;
 	ctx->default_win = pdata->default_win;
@@ -989,8 +994,6 @@
 	struct device *dev = &pdev->dev;
 	struct fimd_context *ctx = platform_get_drvdata(pdev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_drm_subdrv_unregister(&ctx->subdrv);
 
 	if (ctx->suspended)
@@ -1055,8 +1058,6 @@
 {
 	struct fimd_context *ctx = get_fimd_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	return fimd_activate(ctx, false);
 }
 
@@ -1064,14 +1065,15 @@
 {
 	struct fimd_context *ctx = get_fimd_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	return fimd_activate(ctx, true);
 }
 #endif
 
 static struct platform_device_id fimd_driver_ids[] = {
 	{
+		.name		= "s3c64xx-fb",
+		.driver_data	= (unsigned long)&s3c64xx_fimd_driver_data,
+	}, {
 		.name		= "exynos4-fb",
 		.driver_data	= (unsigned long)&exynos4_fimd_driver_data,
 	}, {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index af75434..42a5a546 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -388,12 +388,9 @@
 
 	sg_free_table(g2d_userptr->sgt);
 	kfree(g2d_userptr->sgt);
-	g2d_userptr->sgt = NULL;
 
-	kfree(g2d_userptr->pages);
-	g2d_userptr->pages = NULL;
+	drm_free_large(g2d_userptr->pages);
 	kfree(g2d_userptr);
-	g2d_userptr = NULL;
 }
 
 static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
@@ -463,11 +460,11 @@
 	npages = (end - start) >> PAGE_SHIFT;
 	g2d_userptr->npages = npages;
 
-	pages = kzalloc(npages * sizeof(struct page *), GFP_KERNEL);
+	pages = drm_calloc_large(npages, sizeof(struct page *));
 	if (!pages) {
 		DRM_ERROR("failed to allocate pages.\n");
-		kfree(g2d_userptr);
-		return ERR_PTR(-ENOMEM);
+		ret = -ENOMEM;
+		goto err_free;
 	}
 
 	vma = find_vma(current->mm, userptr);
@@ -543,7 +540,6 @@
 
 err_free_sgt:
 	kfree(sgt);
-	sgt = NULL;
 
 err_free_userptr:
 	exynos_gem_put_pages_to_userptr(g2d_userptr->pages,
@@ -554,10 +550,10 @@
 	exynos_gem_put_vma(g2d_userptr->vma);
 
 err_free_pages:
-	kfree(pages);
+	drm_free_large(pages);
+
+err_free:
 	kfree(g2d_userptr);
-	pages = NULL;
-	g2d_userptr = NULL;
 
 	return ERR_PTR(ret);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index cf4543f..24c22a8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -132,8 +132,6 @@
 	struct drm_gem_object *obj;
 	struct exynos_drm_gem_buf *buf;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	obj = &exynos_gem_obj->base;
 	buf = exynos_gem_obj->buffer;
 
@@ -227,7 +225,6 @@
 	}
 
 	size = roundup_gem_size(size, flags);
-	DRM_DEBUG_KMS("%s\n", __FILE__);
 
 	ret = check_gem_flags(flags);
 	if (ret)
@@ -249,13 +246,14 @@
 	exynos_gem_obj->flags = flags;
 
 	ret = exynos_drm_alloc_buf(dev, buf, flags);
-	if (ret < 0) {
-		drm_gem_object_release(&exynos_gem_obj->base);
-		goto err_fini_buf;
-	}
+	if (ret < 0)
+		goto err_gem_fini;
 
 	return exynos_gem_obj;
 
+err_gem_fini:
+	drm_gem_object_release(&exynos_gem_obj->base);
+	kfree(exynos_gem_obj);
 err_fini_buf:
 	exynos_drm_fini_buf(dev, buf);
 	return ERR_PTR(ret);
@@ -268,8 +266,6 @@
 	struct exynos_drm_gem_obj *exynos_gem_obj;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
 	if (IS_ERR(exynos_gem_obj))
 		return PTR_ERR(exynos_gem_obj);
@@ -331,8 +327,6 @@
 {
 	struct drm_exynos_gem_map_off *args = data;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
 			args->handle, (unsigned long)args->offset);
 
@@ -371,8 +365,6 @@
 	unsigned long vm_size;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
 	vma->vm_private_data = obj;
 	vma->vm_ops = drm_dev->driver->gem_vm_ops;
@@ -429,9 +421,7 @@
 {
 	struct drm_exynos_gem_mmap *args = data;
 	struct drm_gem_object *obj;
-	unsigned int addr;
-
-	DRM_DEBUG_KMS("%s\n", __FILE__);
+	unsigned long addr;
 
 	if (!(dev->driver->driver_features & DRIVER_GEM)) {
 		DRM_ERROR("does not support GEM.\n");
@@ -473,14 +463,14 @@
 
 	drm_gem_object_unreference(obj);
 
-	if (IS_ERR((void *)addr)) {
+	if (IS_ERR_VALUE(addr)) {
 		/* check filp->f_op, filp->private_data are restored */
 		if (file_priv->filp->f_op == &exynos_drm_gem_fops) {
 			file_priv->filp->f_op = fops_get(dev->driver->fops);
 			file_priv->filp->private_data = file_priv;
 		}
 		mutex_unlock(&dev->struct_mutex);
-		return PTR_ERR((void *)addr);
+		return (int)addr;
 	}
 
 	mutex_unlock(&dev->struct_mutex);
@@ -643,8 +633,6 @@
 
 int exynos_drm_gem_init_object(struct drm_gem_object *obj)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	return 0;
 }
 
@@ -653,8 +641,6 @@
 	struct exynos_drm_gem_obj *exynos_gem_obj;
 	struct exynos_drm_gem_buf *buf;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_gem_obj = to_exynos_gem_obj(obj);
 	buf = exynos_gem_obj->buffer;
 
@@ -671,8 +657,6 @@
 	struct exynos_drm_gem_obj *exynos_gem_obj;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * alocate memory to be used for framebuffer.
 	 * - this callback would be called by user application
@@ -704,8 +688,6 @@
 	struct drm_gem_object *obj;
 	int ret = 0;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	mutex_lock(&dev->struct_mutex);
 
 	/*
@@ -743,8 +725,6 @@
 {
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * obj->refcount and obj->handle_count are decreased and
 	 * if both them are 0 then exynos_drm_gem_free_object()
@@ -788,8 +768,6 @@
 	struct drm_gem_object *obj;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* set vm_area_struct. */
 	ret = drm_gem_mmap(filp, vma);
 	if (ret < 0) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 762f40d..472e3b2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -400,8 +400,6 @@
 	u32 cfg;
 	int count = GSC_RESET_TIMEOUT;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* s/w reset */
 	cfg = (GSC_SW_RESET_SRESET);
 	gsc_write(cfg, GSC_SW_RESET);
@@ -441,8 +439,6 @@
 {
 	u32 gscblk_cfg;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	gscblk_cfg = readl(SYSREG_GSCBLK_CFG1);
 
 	if (enable)
@@ -460,7 +456,7 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:enable[%d]overflow[%d]level[%d]\n", __func__,
+	DRM_DEBUG_KMS("enable[%d]overflow[%d]level[%d]\n",
 			enable, overflow, done);
 
 	cfg = gsc_read(GSC_IRQ);
@@ -491,7 +487,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
 
 	cfg = gsc_read(GSC_IN_CON);
 	cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK |
@@ -567,8 +563,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
-		degree, flip);
+	DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
 
 	cfg = gsc_read(GSC_IN_CON);
 	cfg &= ~GSC_IN_ROT_MASK;
@@ -616,8 +611,8 @@
 	struct gsc_scaler *sc = &ctx->sc;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
-		__func__, swap, pos->x, pos->y, pos->w, pos->h);
+	DRM_DEBUG_KMS("swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
+		swap, pos->x, pos->y, pos->w, pos->h);
 
 	if (swap) {
 		img_pos.w = pos->h;
@@ -634,8 +629,7 @@
 		GSC_CROPPED_HEIGHT(img_pos.h));
 	gsc_write(cfg, GSC_CROPPED_SIZE);
 
-	DRM_DEBUG_KMS("%s:hsize[%d]vsize[%d]\n",
-		__func__, sz->hsize, sz->vsize);
+	DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", sz->hsize, sz->vsize);
 
 	/* original size */
 	cfg = gsc_read(GSC_SRCIMG_SIZE);
@@ -650,8 +644,7 @@
 	cfg = gsc_read(GSC_IN_CON);
 	cfg &= ~GSC_IN_RGB_TYPE_MASK;
 
-	DRM_DEBUG_KMS("%s:width[%d]range[%d]\n",
-		__func__, pos->w, sc->range);
+	DRM_DEBUG_KMS("width[%d]range[%d]\n", pos->w, sc->range);
 
 	if (pos->w >= GSC_WIDTH_ITU_709)
 		if (sc->range)
@@ -677,8 +670,7 @@
 	u32 cfg;
 	u32 mask = 0x00000001 << buf_id;
 
-	DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__,
-		buf_id, buf_type);
+	DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
 
 	/* mask register set */
 	cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);
@@ -721,7 +713,7 @@
 
 	property = &c_node->property;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
+	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
 		property->prop_id, buf_id, buf_type);
 
 	if (buf_id > GSC_MAX_SRC) {
@@ -765,7 +757,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+	DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
 
 	cfg = gsc_read(GSC_OUT_CON);
 	cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK |
@@ -838,8 +830,7 @@
 	struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
-		degree, flip);
+	DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
 
 	cfg = gsc_read(GSC_IN_CON);
 	cfg &= ~GSC_IN_ROT_MASK;
@@ -881,7 +872,7 @@
 
 static int gsc_get_ratio_shift(u32 src, u32 dst, u32 *ratio)
 {
-	DRM_DEBUG_KMS("%s:src[%d]dst[%d]\n", __func__, src, dst);
+	DRM_DEBUG_KMS("src[%d]dst[%d]\n", src, dst);
 
 	if (src >= dst * 8) {
 		DRM_ERROR("failed to make ratio and shift.\n");
@@ -944,20 +935,19 @@
 		return ret;
 	}
 
-	DRM_DEBUG_KMS("%s:pre_hratio[%d]pre_vratio[%d]\n",
-		__func__, sc->pre_hratio, sc->pre_vratio);
+	DRM_DEBUG_KMS("pre_hratio[%d]pre_vratio[%d]\n",
+		sc->pre_hratio, sc->pre_vratio);
 
 	sc->main_hratio = (src_w << 16) / dst_w;
 	sc->main_vratio = (src_h << 16) / dst_h;
 
-	DRM_DEBUG_KMS("%s:main_hratio[%ld]main_vratio[%ld]\n",
-		__func__, sc->main_hratio, sc->main_vratio);
+	DRM_DEBUG_KMS("main_hratio[%ld]main_vratio[%ld]\n",
+		sc->main_hratio, sc->main_vratio);
 
 	gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio,
 		&sc->pre_shfactor);
 
-	DRM_DEBUG_KMS("%s:pre_shfactor[%d]\n", __func__,
-		sc->pre_shfactor);
+	DRM_DEBUG_KMS("pre_shfactor[%d]\n", sc->pre_shfactor);
 
 	cfg = (GSC_PRESC_SHFACTOR(sc->pre_shfactor) |
 		GSC_PRESC_H_RATIO(sc->pre_hratio) |
@@ -1023,8 +1013,8 @@
 {
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:main_hratio[%ld]main_vratio[%ld]\n",
-		__func__, sc->main_hratio, sc->main_vratio);
+	DRM_DEBUG_KMS("main_hratio[%ld]main_vratio[%ld]\n",
+		sc->main_hratio, sc->main_vratio);
 
 	gsc_set_h_coef(ctx, sc->main_hratio);
 	cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio);
@@ -1043,8 +1033,8 @@
 	struct gsc_scaler *sc = &ctx->sc;
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
-		__func__, swap, pos->x, pos->y, pos->w, pos->h);
+	DRM_DEBUG_KMS("swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
+		swap, pos->x, pos->y, pos->w, pos->h);
 
 	if (swap) {
 		img_pos.w = pos->h;
@@ -1060,8 +1050,7 @@
 	cfg = (GSC_SCALED_WIDTH(img_pos.w) | GSC_SCALED_HEIGHT(img_pos.h));
 	gsc_write(cfg, GSC_SCALED_SIZE);
 
-	DRM_DEBUG_KMS("%s:hsize[%d]vsize[%d]\n",
-		__func__, sz->hsize, sz->vsize);
+	DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", sz->hsize, sz->vsize);
 
 	/* original size */
 	cfg = gsc_read(GSC_DSTIMG_SIZE);
@@ -1074,8 +1063,7 @@
 	cfg = gsc_read(GSC_OUT_CON);
 	cfg &= ~GSC_OUT_RGB_TYPE_MASK;
 
-	DRM_DEBUG_KMS("%s:width[%d]range[%d]\n",
-		__func__, pos->w, sc->range);
+	DRM_DEBUG_KMS("width[%d]range[%d]\n", pos->w, sc->range);
 
 	if (pos->w >= GSC_WIDTH_ITU_709)
 		if (sc->range)
@@ -1104,7 +1092,7 @@
 		if (cfg & (mask << i))
 			buf_num--;
 
-	DRM_DEBUG_KMS("%s:buf_num[%d]\n", __func__, buf_num);
+	DRM_DEBUG_KMS("buf_num[%d]\n", buf_num);
 
 	return buf_num;
 }
@@ -1118,8 +1106,7 @@
 	u32 mask = 0x00000001 << buf_id;
 	int ret = 0;
 
-	DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__,
-		buf_id, buf_type);
+	DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
 
 	mutex_lock(&ctx->lock);
 
@@ -1177,7 +1164,7 @@
 
 	property = &c_node->property;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
+	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
 		property->prop_id, buf_id, buf_type);
 
 	if (buf_id > GSC_MAX_DST) {
@@ -1217,7 +1204,7 @@
 
 static int gsc_clk_ctrl(struct gsc_context *ctx, bool enable)
 {
-	DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+	DRM_DEBUG_KMS("enable[%d]\n", enable);
 
 	if (enable) {
 		clk_enable(ctx->gsc_clk);
@@ -1236,7 +1223,7 @@
 	u32 buf_id = GSC_MAX_SRC;
 	int ret;
 
-	DRM_DEBUG_KMS("%s:gsc id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
 
 	cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);
 	curr_index = GSC_IN_CURR_GET_INDEX(cfg);
@@ -1259,7 +1246,7 @@
 		return ret;
 	}
 
-	DRM_DEBUG_KMS("%s:cfg[0x%x]curr_index[%d]buf_id[%d]\n", __func__, cfg,
+	DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
 		curr_index, buf_id);
 
 	return buf_id;
@@ -1271,7 +1258,7 @@
 	u32 buf_id = GSC_MAX_DST;
 	int ret;
 
-	DRM_DEBUG_KMS("%s:gsc id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
 
 	cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK);
 	curr_index = GSC_OUT_CURR_GET_INDEX(cfg);
@@ -1294,7 +1281,7 @@
 		return ret;
 	}
 
-	DRM_DEBUG_KMS("%s:cfg[0x%x]curr_index[%d]buf_id[%d]\n", __func__, cfg,
+	DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
 		curr_index, buf_id);
 
 	return buf_id;
@@ -1310,7 +1297,7 @@
 	u32 status;
 	int buf_id[EXYNOS_DRM_OPS_MAX];
 
-	DRM_DEBUG_KMS("%s:gsc id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
 
 	status = gsc_read(GSC_IRQ);
 	if (status & GSC_IRQ_STATUS_OR_IRQ) {
@@ -1331,7 +1318,7 @@
 		if (buf_id[EXYNOS_DRM_OPS_DST] < 0)
 			return IRQ_HANDLED;
 
-		DRM_DEBUG_KMS("%s:buf_id_src[%d]buf_id_dst[%d]\n", __func__,
+		DRM_DEBUG_KMS("buf_id_src[%d]buf_id_dst[%d]\n",
 			buf_id[EXYNOS_DRM_OPS_SRC], buf_id[EXYNOS_DRM_OPS_DST]);
 
 		event_work->ippdrv = ippdrv;
@@ -1350,8 +1337,6 @@
 {
 	struct drm_exynos_ipp_prop_list *prop_list;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL);
 	if (!prop_list) {
 		DRM_ERROR("failed to alloc property list.\n");
@@ -1394,7 +1379,7 @@
 	case EXYNOS_DRM_FLIP_BOTH:
 		return true;
 	default:
-		DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
+		DRM_DEBUG_KMS("invalid flip\n");
 		return false;
 	}
 }
@@ -1411,8 +1396,6 @@
 	bool swap;
 	int i;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	for_each_ipp_ops(i) {
 		if ((i == EXYNOS_DRM_OPS_SRC) &&
 			(property->cmd == IPP_CMD_WB))
@@ -1521,8 +1504,6 @@
 	struct gsc_scaler *sc = &ctx->sc;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* reset h/w block */
 	ret = gsc_sw_reset(ctx);
 	if (ret < 0) {
@@ -1549,7 +1530,7 @@
 	u32 cfg;
 	int ret, i;
 
-	DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
+	DRM_DEBUG_KMS("cmd[%d]\n", cmd);
 
 	if (!c_node) {
 		DRM_ERROR("failed to get c_node.\n");
@@ -1643,7 +1624,7 @@
 	struct drm_exynos_ipp_set_wb set_wb = {0, 0};
 	u32 cfg;
 
-	DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
+	DRM_DEBUG_KMS("cmd[%d]\n", cmd);
 
 	switch (cmd) {
 	case IPP_CMD_M2M:
@@ -1728,8 +1709,7 @@
 		return ret;
 	}
 
-	DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
-		(int)ippdrv);
+	DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
 
 	mutex_init(&ctx->lock);
 	platform_set_drvdata(pdev, ctx);
@@ -1772,7 +1752,7 @@
 {
 	struct gsc_context *ctx = get_gsc_context(dev);
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("id[%d]\n", ctx->id);
 
 	if (pm_runtime_suspended(dev))
 		return 0;
@@ -1784,7 +1764,7 @@
 {
 	struct gsc_context *ctx = get_gsc_context(dev);
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("id[%d]\n", ctx->id);
 
 	if (!pm_runtime_suspended(dev))
 		return gsc_clk_ctrl(ctx, true);
@@ -1798,7 +1778,7 @@
 {
 	struct gsc_context *ctx = get_gsc_context(dev);
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+	DRM_DEBUG_KMS("id[%d]\n", ctx->id);
 
 	return  gsc_clk_ctrl(ctx, false);
 }
@@ -1807,7 +1787,7 @@
 {
 	struct gsc_context *ctx = get_gsc_context(dev);
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __FILE__, ctx->id);
+	DRM_DEBUG_KMS("id[%d]\n", ctx->id);
 
 	return  gsc_clk_ctrl(ctx, true);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 437fb94..aaa550d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -88,16 +88,12 @@
 
 void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ops)
 		hdmi_ops = ops;
 }
 
 void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ops)
 		mixer_ops = ops;
 }
@@ -106,8 +102,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (hdmi_ops && hdmi_ops->is_connected)
 		return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
 
@@ -119,34 +113,31 @@
 {
 	struct drm_hdmi_context *ctx = to_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (hdmi_ops && hdmi_ops->get_edid)
 		return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
 
 	return NULL;
 }
 
-static int drm_hdmi_check_timing(struct device *dev, void *timing)
+static int drm_hdmi_check_mode(struct device *dev,
+		struct drm_display_mode *mode)
 {
 	struct drm_hdmi_context *ctx = to_context(dev);
 	int ret = 0;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	* Both, mixer and hdmi should be able to handle the requested mode.
 	* If any of the two fails, return mode as BAD.
 	*/
 
-	if (mixer_ops && mixer_ops->check_timing)
-		ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, timing);
+	if (mixer_ops && mixer_ops->check_mode)
+		ret = mixer_ops->check_mode(ctx->mixer_ctx->ctx, mode);
 
 	if (ret)
 		return ret;
 
-	if (hdmi_ops && hdmi_ops->check_timing)
-		return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
+	if (hdmi_ops && hdmi_ops->check_mode)
+		return hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode);
 
 	return 0;
 }
@@ -155,8 +146,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (hdmi_ops && hdmi_ops->power_on)
 		return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
 
@@ -167,7 +156,7 @@
 	.type = EXYNOS_DISPLAY_TYPE_HDMI,
 	.is_connected = drm_hdmi_is_connected,
 	.get_edid = drm_hdmi_get_edid,
-	.check_timing = drm_hdmi_check_timing,
+	.check_mode = drm_hdmi_check_mode,
 	.power_on = drm_hdmi_power_on,
 };
 
@@ -177,8 +166,6 @@
 	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
 	struct exynos_drm_manager *manager = subdrv->manager;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (mixer_ops && mixer_ops->enable_vblank)
 		return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
 						manager->pipe);
@@ -190,8 +177,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (mixer_ops && mixer_ops->disable_vblank)
 		return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
 }
@@ -200,8 +185,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (mixer_ops && mixer_ops->wait_for_vblank)
 		mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
 }
@@ -214,11 +197,9 @@
 	struct drm_display_mode *m;
 	int mode_ok;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	drm_mode_set_crtcinfo(adjusted_mode, 0);
 
-	mode_ok = drm_hdmi_check_timing(subdrv_dev, adjusted_mode);
+	mode_ok = drm_hdmi_check_mode(subdrv_dev, adjusted_mode);
 
 	/* just return if user desired mode exists. */
 	if (mode_ok == 0)
@@ -229,7 +210,7 @@
 	 * to adjusted_mode.
 	 */
 	list_for_each_entry(m, &connector->modes, head) {
-		mode_ok = drm_hdmi_check_timing(subdrv_dev, m);
+		mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
 
 		if (mode_ok == 0) {
 			struct drm_mode_object base;
@@ -256,8 +237,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (hdmi_ops && hdmi_ops->mode_set)
 		hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
 }
@@ -267,8 +246,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (hdmi_ops && hdmi_ops->get_max_resol)
 		hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
 }
@@ -277,8 +254,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (hdmi_ops && hdmi_ops->commit)
 		hdmi_ops->commit(ctx->hdmi_ctx->ctx);
 }
@@ -287,8 +262,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (mixer_ops && mixer_ops->dpms)
 		mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
 
@@ -301,8 +274,6 @@
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 	int i;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	for (i = 0; i < MIXER_WIN_NR; i++) {
 		if (!ctx->enabled[i])
 			continue;
@@ -331,8 +302,6 @@
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (mixer_ops && mixer_ops->win_mode_set)
 		mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
 }
@@ -342,9 +311,7 @@
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	if (win < 0 || win > MIXER_WIN_NR) {
+	if (win < 0 || win >= MIXER_WIN_NR) {
 		DRM_ERROR("mixer window[%d] is wrong\n", win);
 		return;
 	}
@@ -360,9 +327,7 @@
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	if (win < 0 || win > MIXER_WIN_NR) {
+	if (win < 0 || win >= MIXER_WIN_NR) {
 		DRM_ERROR("mixer window[%d] is wrong\n", win);
 		return;
 	}
@@ -392,8 +357,6 @@
 	struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
 	struct drm_hdmi_context *ctx;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (!hdmi_ctx) {
 		DRM_ERROR("hdmi context not initialized.\n");
 		return -EFAULT;
@@ -440,8 +403,6 @@
 	struct exynos_drm_subdrv *subdrv;
 	struct drm_hdmi_context *ctx;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx) {
 		DRM_LOG_KMS("failed to alloc common hdmi context.\n");
@@ -466,8 +427,6 @@
 {
 	struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_drm_subdrv_unregister(&ctx->subdrv);
 
 	return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 6b70944..724cab1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -32,11 +32,11 @@
 	bool (*is_connected)(void *ctx);
 	struct edid *(*get_edid)(void *ctx,
 			struct drm_connector *connector);
-	int (*check_timing)(void *ctx, struct fb_videomode *timing);
+	int (*check_mode)(void *ctx, struct drm_display_mode *mode);
 	int (*power_on)(void *ctx, int mode);
 
 	/* manager */
-	void (*mode_set)(void *ctx, void *mode);
+	void (*mode_set)(void *ctx, struct drm_display_mode *mode);
 	void (*get_max_resol)(void *ctx, unsigned int *width,
 				unsigned int *height);
 	void (*commit)(void *ctx);
@@ -57,7 +57,7 @@
 	void (*win_disable)(void *ctx, int zpos);
 
 	/* display */
-	int (*check_timing)(void *ctx, struct fb_videomode *timing);
+	int (*check_mode)(void *ctx, struct drm_display_mode *mode);
 };
 
 void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index be1e884..b1ef8e7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -131,8 +131,6 @@
 
 int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
 {
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!ippdrv)
 		return -EINVAL;
 
@@ -145,8 +143,6 @@
 
 int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv)
 {
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!ippdrv)
 		return -EINVAL;
 
@@ -162,8 +158,6 @@
 {
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* do the allocation under our mutexlock */
 	mutex_lock(lock);
 	ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL);
@@ -179,7 +173,7 @@
 {
 	void *obj;
 
-	DRM_DEBUG_KMS("%s:id[%d]\n", __func__, id);
+	DRM_DEBUG_KMS("id[%d]\n", id);
 
 	mutex_lock(lock);
 
@@ -216,7 +210,7 @@
 	struct exynos_drm_ippdrv *ippdrv;
 	u32 ipp_id = property->ipp_id;
 
-	DRM_DEBUG_KMS("%s:ipp_id[%d]\n", __func__, ipp_id);
+	DRM_DEBUG_KMS("ipp_id[%d]\n", ipp_id);
 
 	if (ipp_id) {
 		/* find ipp driver using idr */
@@ -257,14 +251,13 @@
 		 */
 		list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
 			if (ipp_check_dedicated(ippdrv, property->cmd)) {
-				DRM_DEBUG_KMS("%s:used device.\n", __func__);
+				DRM_DEBUG_KMS("used device.\n");
 				continue;
 			}
 
 			if (ippdrv->check_property &&
 			    ippdrv->check_property(ippdrv->dev, property)) {
-				DRM_DEBUG_KMS("%s:not support property.\n",
-					__func__);
+				DRM_DEBUG_KMS("not support property.\n");
 				continue;
 			}
 
@@ -283,10 +276,10 @@
 	struct drm_exynos_ipp_cmd_node *c_node;
 	int count = 0;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, prop_id);
+	DRM_DEBUG_KMS("prop_id[%d]\n", prop_id);
 
 	if (list_empty(&exynos_drm_ippdrv_list)) {
-		DRM_DEBUG_KMS("%s:ippdrv_list is empty.\n", __func__);
+		DRM_DEBUG_KMS("ippdrv_list is empty.\n");
 		return ERR_PTR(-ENODEV);
 	}
 
@@ -296,8 +289,7 @@
 	 * e.g PAUSE state, queue buf, command contro.
 	 */
 	list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
-		DRM_DEBUG_KMS("%s:count[%d]ippdrv[0x%x]\n", __func__,
-			count++, (int)ippdrv);
+		DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv);
 
 		if (!list_empty(&ippdrv->cmd_list)) {
 			list_for_each_entry(c_node, &ippdrv->cmd_list, list)
@@ -320,8 +312,6 @@
 	struct exynos_drm_ippdrv *ippdrv;
 	int count = 0;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!ctx) {
 		DRM_ERROR("invalid context.\n");
 		return -EINVAL;
@@ -332,7 +322,7 @@
 		return -EINVAL;
 	}
 
-	DRM_DEBUG_KMS("%s:ipp_id[%d]\n", __func__, prop_list->ipp_id);
+	DRM_DEBUG_KMS("ipp_id[%d]\n", prop_list->ipp_id);
 
 	if (!prop_list->ipp_id) {
 		list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list)
@@ -371,11 +361,11 @@
 	struct drm_exynos_pos *pos = &config->pos;
 	struct drm_exynos_sz *sz = &config->sz;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]ops[%s]fmt[0x%x]\n",
-		__func__, property->prop_id, idx ? "dst" : "src", config->fmt);
+	DRM_DEBUG_KMS("prop_id[%d]ops[%s]fmt[0x%x]\n",
+		property->prop_id, idx ? "dst" : "src", config->fmt);
 
-	DRM_DEBUG_KMS("%s:pos[%d %d %d %d]sz[%d %d]f[%d]r[%d]\n",
-		__func__, pos->x, pos->y, pos->w, pos->h,
+	DRM_DEBUG_KMS("pos[%d %d %d %d]sz[%d %d]f[%d]r[%d]\n",
+		pos->x, pos->y, pos->w, pos->h,
 		sz->hsize, sz->vsize, config->flip, config->degree);
 }
 
@@ -385,7 +375,7 @@
 	struct drm_exynos_ipp_cmd_node *c_node;
 	u32 prop_id = property->prop_id;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, prop_id);
+	DRM_DEBUG_KMS("prop_id[%d]\n", prop_id);
 
 	ippdrv = ipp_find_drv_by_handle(prop_id);
 	if (IS_ERR(ippdrv)) {
@@ -401,8 +391,8 @@
 	list_for_each_entry(c_node, &ippdrv->cmd_list, list) {
 		if ((c_node->property.prop_id == prop_id) &&
 		    (c_node->state == IPP_STATE_STOP)) {
-			DRM_DEBUG_KMS("%s:found cmd[%d]ippdrv[0x%x]\n",
-				__func__, property->cmd, (int)ippdrv);
+			DRM_DEBUG_KMS("found cmd[%d]ippdrv[0x%x]\n",
+				property->cmd, (int)ippdrv);
 
 			c_node->property = *property;
 			return 0;
@@ -418,8 +408,6 @@
 {
 	struct drm_exynos_ipp_cmd_work *cmd_work;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	cmd_work = kzalloc(sizeof(*cmd_work), GFP_KERNEL);
 	if (!cmd_work) {
 		DRM_ERROR("failed to alloc cmd_work.\n");
@@ -435,8 +423,6 @@
 {
 	struct drm_exynos_ipp_event_work *event_work;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	event_work = kzalloc(sizeof(*event_work), GFP_KERNEL);
 	if (!event_work) {
 		DRM_ERROR("failed to alloc event_work.\n");
@@ -460,8 +446,6 @@
 	struct drm_exynos_ipp_cmd_node *c_node;
 	int ret, i;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!ctx) {
 		DRM_ERROR("invalid context.\n");
 		return -EINVAL;
@@ -486,7 +470,7 @@
 	 * instead of allocation.
 	 */
 	if (property->prop_id) {
-		DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
+		DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
 		return ipp_find_and_set_property(property);
 	}
 
@@ -512,8 +496,8 @@
 		goto err_clear;
 	}
 
-	DRM_DEBUG_KMS("%s:created prop_id[%d]cmd[%d]ippdrv[0x%x]\n",
-		__func__, property->prop_id, property->cmd, (int)ippdrv);
+	DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[0x%x]\n",
+		property->prop_id, property->cmd, (int)ippdrv);
 
 	/* stored property information and ippdrv in private data */
 	c_node->priv = priv;
@@ -569,8 +553,6 @@
 
 static void ipp_clean_cmd_node(struct drm_exynos_ipp_cmd_node *c_node)
 {
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* delete list */
 	list_del(&c_node->list);
 
@@ -593,8 +575,6 @@
 	struct list_head *head;
 	int ret, i, count[EXYNOS_DRM_OPS_MAX] = { 0, };
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	mutex_lock(&c_node->mem_lock);
 
 	for_each_ipp_ops(i) {
@@ -602,20 +582,19 @@
 		head = &c_node->mem_list[i];
 
 		if (list_empty(head)) {
-			DRM_DEBUG_KMS("%s:%s memory empty.\n", __func__,
-				i ? "dst" : "src");
+			DRM_DEBUG_KMS("%s memory empty.\n", i ? "dst" : "src");
 			continue;
 		}
 
 		/* find memory node entry */
 		list_for_each_entry(m_node, head, list) {
-			DRM_DEBUG_KMS("%s:%s,count[%d]m_node[0x%x]\n", __func__,
+			DRM_DEBUG_KMS("%s,count[%d]m_node[0x%x]\n",
 				i ? "dst" : "src", count[i], (int)m_node);
 			count[i]++;
 		}
 	}
 
-	DRM_DEBUG_KMS("%s:min[%d]max[%d]\n", __func__,
+	DRM_DEBUG_KMS("min[%d]max[%d]\n",
 		min(count[EXYNOS_DRM_OPS_SRC], count[EXYNOS_DRM_OPS_DST]),
 		max(count[EXYNOS_DRM_OPS_SRC], count[EXYNOS_DRM_OPS_DST]));
 
@@ -644,15 +623,14 @@
 	struct list_head *head;
 	int count = 0;
 
-	DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, qbuf->buf_id);
+	DRM_DEBUG_KMS("buf_id[%d]\n", qbuf->buf_id);
 
 	/* source/destination memory list */
 	head = &c_node->mem_list[qbuf->ops_id];
 
 	/* find memory node from memory list */
 	list_for_each_entry(m_node, head, list) {
-		DRM_DEBUG_KMS("%s:count[%d]m_node[0x%x]\n",
-			__func__, count++, (int)m_node);
+		DRM_DEBUG_KMS("count[%d]m_node[0x%x]\n", count++, (int)m_node);
 
 		/* compare buffer id */
 		if (m_node->buf_id == qbuf->buf_id)
@@ -669,7 +647,7 @@
 	struct exynos_drm_ipp_ops *ops = NULL;
 	int ret = 0;
 
-	DRM_DEBUG_KMS("%s:node[0x%x]\n", __func__, (int)m_node);
+	DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
 
 	if (!m_node) {
 		DRM_ERROR("invalid queue node.\n");
@@ -678,7 +656,7 @@
 
 	mutex_lock(&c_node->mem_lock);
 
-	DRM_DEBUG_KMS("%s:ops_id[%d]\n", __func__, m_node->ops_id);
+	DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
 
 	/* get operations callback */
 	ops = ippdrv->ops[m_node->ops_id];
@@ -714,8 +692,6 @@
 	void *addr;
 	int i;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	mutex_lock(&c_node->mem_lock);
 
 	m_node = kzalloc(sizeof(*m_node), GFP_KERNEL);
@@ -732,14 +708,11 @@
 	m_node->prop_id = qbuf->prop_id;
 	m_node->buf_id = qbuf->buf_id;
 
-	DRM_DEBUG_KMS("%s:m_node[0x%x]ops_id[%d]\n", __func__,
-		(int)m_node, qbuf->ops_id);
-	DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]\n", __func__,
-		qbuf->prop_id, m_node->buf_id);
+	DRM_DEBUG_KMS("m_node[0x%x]ops_id[%d]\n", (int)m_node, qbuf->ops_id);
+	DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id);
 
 	for_each_ipp_planar(i) {
-		DRM_DEBUG_KMS("%s:i[%d]handle[0x%x]\n", __func__,
-			i, qbuf->handle[i]);
+		DRM_DEBUG_KMS("i[%d]handle[0x%x]\n", i, qbuf->handle[i]);
 
 		/* get dma address by handle */
 		if (qbuf->handle[i]) {
@@ -752,9 +725,8 @@
 
 			buf_info.handles[i] = qbuf->handle[i];
 			buf_info.base[i] = *(dma_addr_t *) addr;
-			DRM_DEBUG_KMS("%s:i[%d]base[0x%x]hd[0x%x]\n",
-				__func__, i, buf_info.base[i],
-				(int)buf_info.handles[i]);
+			DRM_DEBUG_KMS("i[%d]base[0x%x]hd[0x%x]\n",
+				i, buf_info.base[i], (int)buf_info.handles[i]);
 		}
 	}
 
@@ -778,7 +750,7 @@
 {
 	int i;
 
-	DRM_DEBUG_KMS("%s:node[0x%x]\n", __func__, (int)m_node);
+	DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
 
 	if (!m_node) {
 		DRM_ERROR("invalid dequeue node.\n");
@@ -792,7 +764,7 @@
 
 	mutex_lock(&c_node->mem_lock);
 
-	DRM_DEBUG_KMS("%s:ops_id[%d]\n", __func__, m_node->ops_id);
+	DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
 
 	/* put gem buffer */
 	for_each_ipp_planar(i) {
@@ -824,8 +796,7 @@
 	struct drm_exynos_ipp_send_event *e;
 	unsigned long flags;
 
-	DRM_DEBUG_KMS("%s:ops_id[%d]buf_id[%d]\n", __func__,
-		qbuf->ops_id, qbuf->buf_id);
+	DRM_DEBUG_KMS("ops_id[%d]buf_id[%d]\n", qbuf->ops_id, qbuf->buf_id);
 
 	e = kzalloc(sizeof(*e), GFP_KERNEL);
 
@@ -857,16 +828,13 @@
 	struct drm_exynos_ipp_send_event *e, *te;
 	int count = 0;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (list_empty(&c_node->event_list)) {
-		DRM_DEBUG_KMS("%s:event_list is empty.\n", __func__);
+		DRM_DEBUG_KMS("event_list is empty.\n");
 		return;
 	}
 
 	list_for_each_entry_safe(e, te, &c_node->event_list, base.link) {
-		DRM_DEBUG_KMS("%s:count[%d]e[0x%x]\n",
-			__func__, count++, (int)e);
+		DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e);
 
 		/*
 		 * quf == NULL condition means all event deletion.
@@ -912,8 +880,6 @@
 	struct exynos_drm_ipp_ops *ops;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	ippdrv = ipp_find_drv_by_handle(qbuf->prop_id);
 	if (IS_ERR(ippdrv)) {
 		DRM_ERROR("failed to get ipp driver.\n");
@@ -929,12 +895,12 @@
 	property = &c_node->property;
 
 	if (c_node->state != IPP_STATE_START) {
-		DRM_DEBUG_KMS("%s:bypass for invalid state.\n" , __func__);
+		DRM_DEBUG_KMS("bypass for invalid state.\n");
 		return 0;
 	}
 
 	if (!ipp_check_mem_list(c_node)) {
-		DRM_DEBUG_KMS("%s:empty memory.\n", __func__);
+		DRM_DEBUG_KMS("empty memory.\n");
 		return 0;
 	}
 
@@ -964,8 +930,6 @@
 {
 	struct drm_exynos_ipp_mem_node *m_node, *tm_node;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!list_empty(&c_node->mem_list[qbuf->ops_id])) {
 		/* delete list */
 		list_for_each_entry_safe(m_node, tm_node,
@@ -989,8 +953,6 @@
 	struct drm_exynos_ipp_mem_node *m_node;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!qbuf) {
 		DRM_ERROR("invalid buf parameter.\n");
 		return -EINVAL;
@@ -1001,8 +963,8 @@
 		return -EINVAL;
 	}
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]ops_id[%s]buf_id[%d]buf_type[%d]\n",
-		__func__, qbuf->prop_id, qbuf->ops_id ? "dst" : "src",
+	DRM_DEBUG_KMS("prop_id[%d]ops_id[%s]buf_id[%d]buf_type[%d]\n",
+		qbuf->prop_id, qbuf->ops_id ? "dst" : "src",
 		qbuf->buf_id, qbuf->buf_type);
 
 	/* find command node */
@@ -1075,8 +1037,6 @@
 static bool exynos_drm_ipp_check_valid(struct device *dev,
 		enum drm_exynos_ipp_ctrl ctrl, enum drm_exynos_ipp_state state)
 {
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (ctrl != IPP_CTRL_PLAY) {
 		if (pm_runtime_suspended(dev)) {
 			DRM_ERROR("pm:runtime_suspended.\n");
@@ -1104,7 +1064,6 @@
 	default:
 		DRM_ERROR("invalid state.\n");
 		goto err_status;
-		break;
 	}
 
 	return true;
@@ -1126,8 +1085,6 @@
 	struct drm_exynos_ipp_cmd_work *cmd_work;
 	struct drm_exynos_ipp_cmd_node *c_node;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!ctx) {
 		DRM_ERROR("invalid context.\n");
 		return -EINVAL;
@@ -1138,7 +1095,7 @@
 		return -EINVAL;
 	}
 
-	DRM_DEBUG_KMS("%s:ctrl[%d]prop_id[%d]\n", __func__,
+	DRM_DEBUG_KMS("ctrl[%d]prop_id[%d]\n",
 		cmd_ctrl->ctrl, cmd_ctrl->prop_id);
 
 	ippdrv = ipp_find_drv_by_handle(cmd_ctrl->prop_id);
@@ -1213,7 +1170,7 @@
 		return -EINVAL;
 	}
 
-	DRM_DEBUG_KMS("%s:done ctrl[%d]prop_id[%d]\n", __func__,
+	DRM_DEBUG_KMS("done ctrl[%d]prop_id[%d]\n",
 		cmd_ctrl->ctrl, cmd_ctrl->prop_id);
 
 	return 0;
@@ -1249,7 +1206,7 @@
 		return -EINVAL;
 	}
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
+	DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
 
 	/* reset h/w block */
 	if (ippdrv->reset &&
@@ -1310,13 +1267,13 @@
 	struct list_head *head;
 	int ret, i;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
+	DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
 
 	/* store command info in ippdrv */
 	ippdrv->c_node = c_node;
 
 	if (!ipp_check_mem_list(c_node)) {
-		DRM_DEBUG_KMS("%s:empty memory.\n", __func__);
+		DRM_DEBUG_KMS("empty memory.\n");
 		return -ENOMEM;
 	}
 
@@ -1343,8 +1300,7 @@
 				return ret;
 			}
 
-			DRM_DEBUG_KMS("%s:m_node[0x%x]\n",
-				__func__, (int)m_node);
+			DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node);
 
 			ret = ipp_set_mem_node(ippdrv, c_node, m_node);
 			if (ret) {
@@ -1382,7 +1338,7 @@
 		return -EINVAL;
 	}
 
-	DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, property->cmd);
+	DRM_DEBUG_KMS("cmd[%d]\n", property->cmd);
 
 	/* start operations */
 	if (ippdrv->start) {
@@ -1405,7 +1361,7 @@
 	struct list_head *head;
 	int ret = 0, i;
 
-	DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
+	DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
 
 	/* put event */
 	ipp_put_event(c_node, NULL);
@@ -1418,8 +1374,7 @@
 			head = &c_node->mem_list[i];
 
 			if (list_empty(head)) {
-				DRM_DEBUG_KMS("%s:mem_list is empty.\n",
-					__func__);
+				DRM_DEBUG_KMS("mem_list is empty.\n");
 				break;
 			}
 
@@ -1439,7 +1394,7 @@
 		head = &c_node->mem_list[EXYNOS_DRM_OPS_DST];
 
 		if (list_empty(head)) {
-			DRM_DEBUG_KMS("%s:mem_list is empty.\n", __func__);
+			DRM_DEBUG_KMS("mem_list is empty.\n");
 			break;
 		}
 
@@ -1456,7 +1411,7 @@
 		head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC];
 
 		if (list_empty(head)) {
-			DRM_DEBUG_KMS("%s:mem_list is empty.\n", __func__);
+			DRM_DEBUG_KMS("mem_list is empty.\n");
 			break;
 		}
 
@@ -1491,8 +1446,6 @@
 	struct drm_exynos_ipp_property *property;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	ippdrv = cmd_work->ippdrv;
 	if (!ippdrv) {
 		DRM_ERROR("invalid ippdrv list.\n");
@@ -1550,7 +1503,7 @@
 		break;
 	}
 
-	DRM_DEBUG_KMS("%s:ctrl[%d] done.\n", __func__, cmd_work->ctrl);
+	DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl);
 
 err_unlock:
 	mutex_unlock(&c_node->cmd_lock);
@@ -1571,8 +1524,7 @@
 	int ret, i;
 
 	for_each_ipp_ops(i)
-		DRM_DEBUG_KMS("%s:%s buf_id[%d]\n", __func__,
-			i ? "dst" : "src", buf_id[i]);
+		DRM_DEBUG_KMS("%s buf_id[%d]\n", i ? "dst" : "src", buf_id[i]);
 
 	if (!drm_dev) {
 		DRM_ERROR("failed to get drm_dev.\n");
@@ -1585,12 +1537,12 @@
 	}
 
 	if (list_empty(&c_node->event_list)) {
-		DRM_DEBUG_KMS("%s:event list is empty.\n", __func__);
+		DRM_DEBUG_KMS("event list is empty.\n");
 		return 0;
 	}
 
 	if (!ipp_check_mem_list(c_node)) {
-		DRM_DEBUG_KMS("%s:empty memory.\n", __func__);
+		DRM_DEBUG_KMS("empty memory.\n");
 		return 0;
 	}
 
@@ -1609,7 +1561,7 @@
 			}
 
 			tbuf_id[i] = m_node->buf_id;
-			DRM_DEBUG_KMS("%s:%s buf_id[%d]\n", __func__,
+			DRM_DEBUG_KMS("%s buf_id[%d]\n",
 				i ? "dst" : "src", tbuf_id[i]);
 
 			ret = ipp_put_mem_node(drm_dev, c_node, m_node);
@@ -1677,8 +1629,7 @@
 	}
 
 	do_gettimeofday(&now);
-	DRM_DEBUG_KMS("%s:tv_sec[%ld]tv_usec[%ld]\n"
-		, __func__, now.tv_sec, now.tv_usec);
+	DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec);
 	e->event.tv_sec = now.tv_sec;
 	e->event.tv_usec = now.tv_usec;
 	e->event.prop_id = property->prop_id;
@@ -1692,7 +1643,7 @@
 	wake_up_interruptible(&e->base.file_priv->event_wait);
 	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
 
-	DRM_DEBUG_KMS("%s:done cmd[%d]prop_id[%d]buf_id[%d]\n", __func__,
+	DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n",
 		property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]);
 
 	return 0;
@@ -1711,8 +1662,7 @@
 		return;
 	}
 
-	DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__,
-		event_work->buf_id[EXYNOS_DRM_OPS_DST]);
+	DRM_DEBUG_KMS("buf_id[%d]\n", event_work->buf_id[EXYNOS_DRM_OPS_DST]);
 
 	ippdrv = event_work->ippdrv;
 	if (!ippdrv) {
@@ -1733,8 +1683,8 @@
 	 * or going out operations.
 	 */
 	if (c_node->state != IPP_STATE_START) {
-		DRM_DEBUG_KMS("%s:bypass state[%d]prop_id[%d]\n",
-			__func__, c_node->state, c_node->property.prop_id);
+		DRM_DEBUG_KMS("bypass state[%d]prop_id[%d]\n",
+			c_node->state, c_node->property.prop_id);
 		goto err_completion;
 	}
 
@@ -1759,8 +1709,6 @@
 	struct exynos_drm_ippdrv *ippdrv;
 	int ret, count = 0;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* get ipp driver entry */
 	list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
 		ippdrv->drm_dev = drm_dev;
@@ -1772,7 +1720,7 @@
 			goto err_idr;
 		}
 
-		DRM_DEBUG_KMS("%s:count[%d]ippdrv[0x%x]ipp_id[%d]\n", __func__,
+		DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n",
 			count++, (int)ippdrv, ippdrv->ipp_id);
 
 		if (ippdrv->ipp_id == 0) {
@@ -1816,8 +1764,6 @@
 {
 	struct exynos_drm_ippdrv *ippdrv;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* get ipp driver entry */
 	list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
 		if (is_drm_iommu_supported(drm_dev))
@@ -1834,8 +1780,6 @@
 	struct drm_exynos_file_private *file_priv = file->driver_priv;
 	struct exynos_drm_ipp_private *priv;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv) {
 		DRM_ERROR("failed to allocate priv.\n");
@@ -1846,7 +1790,7 @@
 
 	INIT_LIST_HEAD(&priv->event_list);
 
-	DRM_DEBUG_KMS("%s:done priv[0x%x]\n", __func__, (int)priv);
+	DRM_DEBUG_KMS("done priv[0x%x]\n", (int)priv);
 
 	return 0;
 }
@@ -1860,10 +1804,10 @@
 	struct drm_exynos_ipp_cmd_node *c_node, *tc_node;
 	int count = 0;
 
-	DRM_DEBUG_KMS("%s:for priv[0x%x]\n", __func__, (int)priv);
+	DRM_DEBUG_KMS("for priv[0x%x]\n", (int)priv);
 
 	if (list_empty(&exynos_drm_ippdrv_list)) {
-		DRM_DEBUG_KMS("%s:ippdrv_list is empty.\n", __func__);
+		DRM_DEBUG_KMS("ippdrv_list is empty.\n");
 		goto err_clear;
 	}
 
@@ -1873,8 +1817,8 @@
 
 		list_for_each_entry_safe(c_node, tc_node,
 			&ippdrv->cmd_list, list) {
-			DRM_DEBUG_KMS("%s:count[%d]ippdrv[0x%x]\n",
-				__func__, count++, (int)ippdrv);
+			DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n",
+				count++, (int)ippdrv);
 
 			if (c_node->priv == priv) {
 				/*
@@ -1913,8 +1857,6 @@
 	if (!ctx)
 		return -ENOMEM;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	mutex_init(&ctx->ipp_lock);
 	mutex_init(&ctx->prop_lock);
 
@@ -1978,8 +1920,6 @@
 {
 	struct ipp_context *ctx = platform_get_drvdata(pdev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	/* unregister sub driver */
 	exynos_drm_subdrv_unregister(&ctx->subdrv);
 
@@ -1999,7 +1939,7 @@
 
 static int ipp_power_ctrl(struct ipp_context *ctx, bool enable)
 {
-	DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+	DRM_DEBUG_KMS("enable[%d]\n", enable);
 
 	return 0;
 }
@@ -2009,8 +1949,6 @@
 {
 	struct ipp_context *ctx = get_ipp_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (pm_runtime_suspended(dev))
 		return 0;
 
@@ -2021,8 +1959,6 @@
 {
 	struct ipp_context *ctx = get_ipp_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!pm_runtime_suspended(dev))
 		return ipp_power_ctrl(ctx, true);
 
@@ -2035,8 +1971,6 @@
 {
 	struct ipp_context *ctx = get_ipp_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	return ipp_power_ctrl(ctx, false);
 }
 
@@ -2044,8 +1978,6 @@
 {
 	struct ipp_context *ctx = get_ipp_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	return ipp_power_ctrl(ctx, true);
 }
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 83efc66..6ee55e6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -81,8 +81,6 @@
 	int nr;
 	int i;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	nr = exynos_drm_fb_get_buf_cnt(fb);
 	for (i = 0; i < nr; i++) {
 		struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);
@@ -159,8 +157,6 @@
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (mode == DRM_MODE_DPMS_ON) {
 		if (exynos_plane->enabled)
 			return;
@@ -189,8 +185,6 @@
 {
 	int ret;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
 			crtc_w, crtc_h, src_x >> 16, src_y >> 16,
 			src_w >> 16, src_h >> 16);
@@ -207,8 +201,6 @@
 
 static int exynos_disable_plane(struct drm_plane *plane)
 {
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
 
 	return 0;
@@ -218,8 +210,6 @@
 {
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	exynos_disable_plane(plane);
 	drm_plane_cleanup(plane);
 	kfree(exynos_plane);
@@ -233,8 +223,6 @@
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (property == dev_priv->plane_zpos_property) {
 		exynos_plane->overlay.zpos = val;
 		return 0;
@@ -256,8 +244,6 @@
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 	struct drm_property *prop;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	prop = dev_priv->plane_zpos_property;
 	if (!prop) {
 		prop = drm_property_create_range(dev, 0, "zpos", 0,
@@ -277,8 +263,6 @@
 	struct exynos_plane *exynos_plane;
 	int err;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
 	if (!exynos_plane) {
 		DRM_ERROR("failed to allocate plane\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index 9b6c709..427640a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -244,7 +244,7 @@
 	/* Get format */
 	fmt = rotator_reg_get_fmt(rot);
 	if (!rotator_check_reg_fmt(fmt)) {
-		DRM_ERROR("%s:invalid format.\n", __func__);
+		DRM_ERROR("invalid format.\n");
 		return -EINVAL;
 	}
 
@@ -287,7 +287,7 @@
 		/* Get format */
 		fmt = rotator_reg_get_fmt(rot);
 		if (!rotator_check_reg_fmt(fmt)) {
-			DRM_ERROR("%s:invalid format.\n", __func__);
+			DRM_ERROR("invalid format.\n");
 			return -EINVAL;
 		}
 
@@ -381,7 +381,7 @@
 	/* Get format */
 	fmt = rotator_reg_get_fmt(rot);
 	if (!rotator_check_reg_fmt(fmt)) {
-		DRM_ERROR("%s:invalid format.\n", __func__);
+		DRM_ERROR("invalid format.\n");
 		return -EINVAL;
 	}
 
@@ -422,7 +422,7 @@
 		/* Get format */
 		fmt = rotator_reg_get_fmt(rot);
 		if (!rotator_check_reg_fmt(fmt)) {
-			DRM_ERROR("%s:invalid format.\n", __func__);
+			DRM_ERROR("invalid format.\n");
 			return -EINVAL;
 		}
 
@@ -471,8 +471,6 @@
 {
 	struct drm_exynos_ipp_prop_list *prop_list;
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL);
 	if (!prop_list) {
 		DRM_ERROR("failed to alloc property list.\n");
@@ -502,7 +500,7 @@
 	case DRM_FORMAT_NV12:
 		return true;
 	default:
-		DRM_DEBUG_KMS("%s:not support format\n", __func__);
+		DRM_DEBUG_KMS("not support format\n");
 		return false;
 	}
 }
@@ -516,7 +514,7 @@
 	case EXYNOS_DRM_FLIP_BOTH:
 		return true;
 	default:
-		DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
+		DRM_DEBUG_KMS("invalid flip\n");
 		return false;
 	}
 }
@@ -536,19 +534,18 @@
 
 	/* Check format configuration */
 	if (src_config->fmt != dst_config->fmt) {
-		DRM_DEBUG_KMS("%s:not support csc feature\n", __func__);
+		DRM_DEBUG_KMS("not support csc feature\n");
 		return -EINVAL;
 	}
 
 	if (!rotator_check_drm_fmt(dst_config->fmt)) {
-		DRM_DEBUG_KMS("%s:invalid format\n", __func__);
+		DRM_DEBUG_KMS("invalid format\n");
 		return -EINVAL;
 	}
 
 	/* Check transform configuration */
 	if (src_config->degree != EXYNOS_DRM_DEGREE_0) {
-		DRM_DEBUG_KMS("%s:not support source-side rotation\n",
-			__func__);
+		DRM_DEBUG_KMS("not support source-side rotation\n");
 		return -EINVAL;
 	}
 
@@ -561,51 +558,47 @@
 		/* No problem */
 		break;
 	default:
-		DRM_DEBUG_KMS("%s:invalid degree\n", __func__);
+		DRM_DEBUG_KMS("invalid degree\n");
 		return -EINVAL;
 	}
 
 	if (src_config->flip != EXYNOS_DRM_FLIP_NONE) {
-		DRM_DEBUG_KMS("%s:not support source-side flip\n", __func__);
+		DRM_DEBUG_KMS("not support source-side flip\n");
 		return -EINVAL;
 	}
 
 	if (!rotator_check_drm_flip(dst_config->flip)) {
-		DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
+		DRM_DEBUG_KMS("invalid flip\n");
 		return -EINVAL;
 	}
 
 	/* Check size configuration */
 	if ((src_pos->x + src_pos->w > src_sz->hsize) ||
 		(src_pos->y + src_pos->h > src_sz->vsize)) {
-		DRM_DEBUG_KMS("%s:out of source buffer bound\n", __func__);
+		DRM_DEBUG_KMS("out of source buffer bound\n");
 		return -EINVAL;
 	}
 
 	if (swap) {
 		if ((dst_pos->x + dst_pos->h > dst_sz->vsize) ||
 			(dst_pos->y + dst_pos->w > dst_sz->hsize)) {
-			DRM_DEBUG_KMS("%s:out of destination buffer bound\n",
-				__func__);
+			DRM_DEBUG_KMS("out of destination buffer bound\n");
 			return -EINVAL;
 		}
 
 		if ((src_pos->w != dst_pos->h) || (src_pos->h != dst_pos->w)) {
-			DRM_DEBUG_KMS("%s:not support scale feature\n",
-				__func__);
+			DRM_DEBUG_KMS("not support scale feature\n");
 			return -EINVAL;
 		}
 	} else {
 		if ((dst_pos->x + dst_pos->w > dst_sz->hsize) ||
 			(dst_pos->y + dst_pos->h > dst_sz->vsize)) {
-			DRM_DEBUG_KMS("%s:out of destination buffer bound\n",
-				__func__);
+			DRM_DEBUG_KMS("out of destination buffer bound\n");
 			return -EINVAL;
 		}
 
 		if ((src_pos->w != dst_pos->w) || (src_pos->h != dst_pos->h)) {
-			DRM_DEBUG_KMS("%s:not support scale feature\n",
-				__func__);
+			DRM_DEBUG_KMS("not support scale feature\n");
 			return -EINVAL;
 		}
 	}
@@ -693,7 +686,7 @@
 		goto err_ippdrv_register;
 	}
 
-	DRM_DEBUG_KMS("%s:ippdrv[0x%x]\n", __func__, (int)ippdrv);
+	DRM_DEBUG_KMS("ippdrv[0x%x]\n", (int)ippdrv);
 
 	platform_set_drvdata(pdev, rot);
 
@@ -752,8 +745,6 @@
 
 static int rotator_clk_crtl(struct rot_context *rot, bool enable)
 {
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (enable) {
 		clk_enable(rot->clock);
 		rot->suspended = false;
@@ -771,8 +762,6 @@
 {
 	struct rot_context *rot = dev_get_drvdata(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (pm_runtime_suspended(dev))
 		return 0;
 
@@ -783,8 +772,6 @@
 {
 	struct rot_context *rot = dev_get_drvdata(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	if (!pm_runtime_suspended(dev))
 		return rotator_clk_crtl(rot, true);
 
@@ -797,8 +784,6 @@
 {
 	struct rot_context *rot = dev_get_drvdata(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	return  rotator_clk_crtl(rot, false);
 }
 
@@ -806,8 +791,6 @@
 {
 	struct rot_context *rot = dev_get_drvdata(dev);
 
-	DRM_DEBUG_KMS("%s\n", __func__);
-
 	return  rotator_clk_crtl(rot, true);
 }
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 24376c1..41cc74d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -89,8 +89,6 @@
 {
 	struct vidi_context *ctx = get_vidi_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * connection request would come from user side
 	 * to do hotplug through specific ioctl.
@@ -105,8 +103,6 @@
 	struct edid *edid;
 	int edid_len;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * the edid data comes from user side and it would be set
 	 * to ctx->raw_edid through specific ioctl.
@@ -128,17 +124,13 @@
 
 static void *vidi_get_panel(struct device *dev)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* TODO. */
 
 	return NULL;
 }
 
-static int vidi_check_timing(struct device *dev, void *timing)
+static int vidi_check_mode(struct device *dev, struct drm_display_mode *mode)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* TODO. */
 
 	return 0;
@@ -146,8 +138,6 @@
 
 static int vidi_display_power_on(struct device *dev, int mode)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* TODO */
 
 	return 0;
@@ -158,7 +148,7 @@
 	.is_connected = vidi_display_is_connected,
 	.get_edid = vidi_get_edid,
 	.get_panel = vidi_get_panel,
-	.check_timing = vidi_check_timing,
+	.check_mode = vidi_check_mode,
 	.power_on = vidi_display_power_on,
 };
 
@@ -166,7 +156,7 @@
 {
 	struct vidi_context *ctx = get_vidi_context(subdrv_dev);
 
-	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+	DRM_DEBUG_KMS("%d\n", mode);
 
 	mutex_lock(&ctx->lock);
 
@@ -196,8 +186,6 @@
 	struct vidi_win_data *win_data;
 	int i;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	for (i = 0; i < WINDOWS_NR; i++) {
 		win_data = &ctx->win_data[i];
 		if (win_data->enabled && (ovl_ops && ovl_ops->commit))
@@ -212,8 +200,6 @@
 {
 	struct vidi_context *ctx = get_vidi_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ctx->suspended)
 		return;
 }
@@ -222,8 +208,6 @@
 {
 	struct vidi_context *ctx = get_vidi_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ctx->suspended)
 		return -EPERM;
 
@@ -246,8 +230,6 @@
 {
 	struct vidi_context *ctx = get_vidi_context(dev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ctx->suspended)
 		return;
 
@@ -271,8 +253,6 @@
 	int win;
 	unsigned long offset;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (!overlay) {
 		dev_err(dev, "overlay is NULL\n");
 		return;
@@ -282,7 +262,7 @@
 	if (win == DEFAULT_ZPOS)
 		win = ctx->default_win;
 
-	if (win < 0 || win > WINDOWS_NR)
+	if (win < 0 || win >= WINDOWS_NR)
 		return;
 
 	offset = overlay->fb_x * (overlay->bpp >> 3);
@@ -324,15 +304,13 @@
 	struct vidi_win_data *win_data;
 	int win = zpos;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (ctx->suspended)
 		return;
 
 	if (win == DEFAULT_ZPOS)
 		win = ctx->default_win;
 
-	if (win < 0 || win > WINDOWS_NR)
+	if (win < 0 || win >= WINDOWS_NR)
 		return;
 
 	win_data = &ctx->win_data[win];
@@ -351,12 +329,10 @@
 	struct vidi_win_data *win_data;
 	int win = zpos;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (win == DEFAULT_ZPOS)
 		win = ctx->default_win;
 
-	if (win < 0 || win > WINDOWS_NR)
+	if (win < 0 || win >= WINDOWS_NR)
 		return;
 
 	win_data = &ctx->win_data[win];
@@ -407,8 +383,6 @@
 
 static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/*
 	 * enable drm irq mode.
 	 * - with irq_enabled = 1, we can use the vblank feature.
@@ -431,8 +405,6 @@
 
 static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 {
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	/* TODO. */
 }
 
@@ -441,11 +413,6 @@
 	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
 	struct device *dev = subdrv->dev;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	if (enable != false && enable != true)
-		return -EINVAL;
-
 	if (enable) {
 		ctx->suspended = false;
 
@@ -483,8 +450,6 @@
 	struct vidi_context *ctx = get_vidi_context(dev);
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	ret = kstrtoint(buf, 0, &ctx->connected);
 	if (ret)
 		return ret;
@@ -522,8 +487,6 @@
 	struct drm_exynos_vidi_connection *vidi = data;
 	int edid_len;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	if (!vidi) {
 		DRM_DEBUG_KMS("user data for vidi is null.\n");
 		return -EINVAL;
@@ -592,8 +555,6 @@
 	struct exynos_drm_subdrv *subdrv;
 	int ret;
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
@@ -625,8 +586,6 @@
 {
 	struct vidi_context *ctx = platform_get_drvdata(pdev);
 
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
 	exynos_drm_subdrv_unregister(&ctx->subdrv);
 
 	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index fd1426d..62ef597 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -83,6 +83,7 @@
 	struct clk			*sclk_pixel;
 	struct clk			*sclk_hdmiphy;
 	struct clk			*hdmiphy;
+	struct clk			*mout_hdmi;
 	struct regulator_bulk_data	*regul_bulk;
 	int				regul_count;
 };
@@ -689,8 +690,6 @@
 	u32 mod;
 	u32 vic;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
 	if (hdata->dvi_mode) {
 		hdmi_reg_writeb(hdata, HDMI_VSI_CON,
@@ -755,8 +754,6 @@
 	struct edid *raw_edid;
 	struct hdmi_context *hdata = ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (!hdata->ddc_port)
 		return ERR_PTR(-ENODEV);
 
@@ -777,8 +774,6 @@
 	const struct hdmiphy_config *confs;
 	int count, i;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (hdata->type == HDMI_TYPE13) {
 		confs = hdmiphy_v13_configs;
 		count = ARRAY_SIZE(hdmiphy_v13_configs);
@@ -796,18 +791,17 @@
 	return -EINVAL;
 }
 
-static int hdmi_check_timing(void *ctx, struct fb_videomode *timing)
+static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
 {
 	struct hdmi_context *hdata = ctx;
 	int ret;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
+		mode->hdisplay, mode->vdisplay, mode->vrefresh,
+		(mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
+		false, mode->clock * 1000);
 
-	DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", timing->xres,
-			timing->yres, timing->refresh,
-			timing->vmode);
-
-	ret = hdmi_find_phy_conf(hdata, timing->pixclock);
+	ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
 	if (ret < 0)
 		return ret;
 	return 0;
@@ -1042,7 +1036,7 @@
 	}
 }
 
-static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
+static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
 {
 	const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
 	const struct hdmi_v13_core_regs *core =
@@ -1118,9 +1112,9 @@
 		hdmi_regs_dump(hdata, "timing apply");
 	}
 
-	clk_disable(hdata->res.sclk_hdmi);
-	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
-	clk_enable(hdata->res.sclk_hdmi);
+	clk_disable_unprepare(hdata->res.sclk_hdmi);
+	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
+	clk_prepare_enable(hdata->res.sclk_hdmi);
 
 	/* enable HDMI and timing generator */
 	hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
@@ -1131,7 +1125,7 @@
 		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
 }
 
-static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
+static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
 {
 	const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
 	const struct hdmi_v14_core_regs *core =
@@ -1285,9 +1279,9 @@
 		hdmi_regs_dump(hdata, "timing apply");
 	}
 
-	clk_disable(hdata->res.sclk_hdmi);
-	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
-	clk_enable(hdata->res.sclk_hdmi);
+	clk_disable_unprepare(hdata->res.sclk_hdmi);
+	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
+	clk_prepare_enable(hdata->res.sclk_hdmi);
 
 	/* enable HDMI and timing generator */
 	hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
@@ -1298,12 +1292,12 @@
 		hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
 }
 
-static void hdmi_timing_apply(struct hdmi_context *hdata)
+static void hdmi_mode_apply(struct hdmi_context *hdata)
 {
 	if (hdata->type == HDMI_TYPE13)
-		hdmi_v13_timing_apply(hdata);
+		hdmi_v13_mode_apply(hdata);
 	else
-		hdmi_v14_timing_apply(hdata);
+		hdmi_v14_mode_apply(hdata);
 }
 
 static void hdmiphy_conf_reset(struct hdmi_context *hdata)
@@ -1311,9 +1305,9 @@
 	u8 buffer[2];
 	u32 reg;
 
-	clk_disable(hdata->res.sclk_hdmi);
-	clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
-	clk_enable(hdata->res.sclk_hdmi);
+	clk_disable_unprepare(hdata->res.sclk_hdmi);
+	clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
+	clk_prepare_enable(hdata->res.sclk_hdmi);
 
 	/* operation mode */
 	buffer[0] = 0x1f;
@@ -1336,8 +1330,6 @@
 
 static void hdmiphy_poweron(struct hdmi_context *hdata)
 {
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (hdata->type == HDMI_TYPE14)
 		hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
 			HDMI_PHY_POWER_OFF_EN);
@@ -1345,8 +1337,6 @@
 
 static void hdmiphy_poweroff(struct hdmi_context *hdata)
 {
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (hdata->type == HDMI_TYPE14)
 		hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
 			HDMI_PHY_POWER_OFF_EN);
@@ -1410,8 +1400,6 @@
 
 static void hdmi_conf_apply(struct hdmi_context *hdata)
 {
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	hdmiphy_conf_reset(hdata);
 	hdmiphy_conf_apply(hdata);
 
@@ -1423,7 +1411,7 @@
 	hdmi_audio_init(hdata);
 
 	/* setting core registers */
-	hdmi_timing_apply(hdata);
+	hdmi_mode_apply(hdata);
 	hdmi_audio_control(hdata, true);
 
 	hdmi_regs_dump(hdata, "start");
@@ -1569,8 +1557,7 @@
 			(m->vsync_start - m->vdisplay) / 2);
 		hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
 		hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
-		hdmi_set_reg(core->v_blank_f0, 2, (m->vtotal +
-			((m->vsync_end - m->vsync_start) * 4) + 5) / 2);
+		hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
 		hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
 		hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
 		hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
@@ -1580,7 +1567,10 @@
 			(m->htotal / 2) + (m->hsync_start - m->hdisplay));
 		hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
 		hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
-		hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
+		hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
+		hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
+		hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
+		hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
 		hdmi_set_reg(tg->vact_st3, 2, 0x0);
 		hdmi_set_reg(tg->vact_st4, 2, 0x0);
 	} else {
@@ -1602,6 +1592,9 @@
 		hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
 		hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
 		hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
+		hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
+		hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
+		hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
 	}
 
 	/* Following values & calculations are same irrespective of mode type */
@@ -1633,22 +1626,19 @@
 	hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
 	hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
 	hdmi_set_reg(tg->vsync, 2, 0x1);
-	hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
 	hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
 	hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
-	hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
 	hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
-	hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
 	hdmi_set_reg(tg->tg_3d, 1, 0x0);
 }
 
-static void hdmi_mode_set(void *ctx, void *mode)
+static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
 {
 	struct hdmi_context *hdata = ctx;
 	struct drm_display_mode *m = mode;
 
-	DRM_DEBUG_KMS("[%s]: xres=%d, yres=%d, refresh=%d, intl=%s\n",
-		__func__, m->hdisplay, m->vdisplay,
+	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
+		m->hdisplay, m->vdisplay,
 		m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
 		"INTERLACED" : "PROGERESSIVE");
 
@@ -1661,8 +1651,6 @@
 static void hdmi_get_max_resol(void *ctx, unsigned int *width,
 					unsigned int *height)
 {
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	*width = MAX_WIDTH;
 	*height = MAX_HEIGHT;
 }
@@ -1671,8 +1659,6 @@
 {
 	struct hdmi_context *hdata = ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mutex_lock(&hdata->hdmi_mutex);
 	if (!hdata->powered) {
 		mutex_unlock(&hdata->hdmi_mutex);
@@ -1687,8 +1673,6 @@
 {
 	struct hdmi_resources *res = &hdata->res;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mutex_lock(&hdata->hdmi_mutex);
 	if (hdata->powered) {
 		mutex_unlock(&hdata->hdmi_mutex);
@@ -1699,10 +1683,12 @@
 
 	mutex_unlock(&hdata->hdmi_mutex);
 
-	regulator_bulk_enable(res->regul_count, res->regul_bulk);
-	clk_enable(res->hdmiphy);
-	clk_enable(res->hdmi);
-	clk_enable(res->sclk_hdmi);
+	if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
+		DRM_DEBUG_KMS("failed to enable regulator bulk\n");
+
+	clk_prepare_enable(res->hdmiphy);
+	clk_prepare_enable(res->hdmi);
+	clk_prepare_enable(res->sclk_hdmi);
 
 	hdmiphy_poweron(hdata);
 }
@@ -1711,8 +1697,6 @@
 {
 	struct hdmi_resources *res = &hdata->res;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mutex_lock(&hdata->hdmi_mutex);
 	if (!hdata->powered)
 		goto out;
@@ -1725,9 +1709,9 @@
 	hdmiphy_conf_reset(hdata);
 	hdmiphy_poweroff(hdata);
 
-	clk_disable(res->sclk_hdmi);
-	clk_disable(res->hdmi);
-	clk_disable(res->hdmiphy);
+	clk_disable_unprepare(res->sclk_hdmi);
+	clk_disable_unprepare(res->hdmi);
+	clk_disable_unprepare(res->hdmiphy);
 	regulator_bulk_disable(res->regul_count, res->regul_bulk);
 
 	mutex_lock(&hdata->hdmi_mutex);
@@ -1742,7 +1726,7 @@
 {
 	struct hdmi_context *hdata = ctx;
 
-	DRM_DEBUG_KMS("[%d] %s mode %d\n", __LINE__, __func__, mode);
+	DRM_DEBUG_KMS("mode %d\n", mode);
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
@@ -1765,7 +1749,7 @@
 	/* display */
 	.is_connected	= hdmi_is_connected,
 	.get_edid	= hdmi_get_edid,
-	.check_timing	= hdmi_check_timing,
+	.check_mode	= hdmi_check_mode,
 
 	/* manager */
 	.mode_set	= hdmi_mode_set,
@@ -1831,8 +1815,13 @@
 		DRM_ERROR("failed to get clock 'hdmiphy'\n");
 		goto fail;
 	}
+	res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
+	if (IS_ERR(res->mout_hdmi)) {
+		DRM_ERROR("failed to get clock 'mout_hdmi'\n");
+		goto fail;
+	}
 
-	clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+	clk_set_parent(res->mout_hdmi, res->sclk_pixel);
 
 	res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
 		sizeof(res->regul_bulk[0]), GFP_KERNEL);
@@ -1877,7 +1866,6 @@
 {
 	struct device_node *np = dev->of_node;
 	struct s5p_hdmi_platform_data *pd;
-	enum of_gpio_flags flags;
 	u32 value;
 
 	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
@@ -1891,7 +1879,7 @@
 		goto err_data;
 	}
 
-	pd->hpd_gpio = of_get_named_gpio_flags(np, "hpd-gpio", 0, &flags);
+	pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
 
 	return pd;
 
@@ -1930,6 +1918,9 @@
 		.compatible = "samsung,exynos5-hdmi",
 		.data	= (void	*)HDMI_TYPE14,
 	}, {
+		.compatible = "samsung,exynos4212-hdmi",
+		.data	= (void	*)HDMI_TYPE14,
+	}, {
 		/* end node */
 	}
 };
@@ -1944,8 +1935,6 @@
 	struct resource *res;
 	int ret;
 
-	DRM_DEBUG_KMS("[%d]\n", __LINE__);
-
 	if (dev->of_node) {
 		pdata = drm_hdmi_dt_parse_pdata(dev);
 		if (IS_ERR(pdata)) {
@@ -2071,8 +2060,6 @@
 {
 	struct device *dev = &pdev->dev;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	pm_runtime_disable(dev);
 
 	/* hdmiphy i2c driver */
@@ -2089,8 +2076,6 @@
 	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
 	struct hdmi_context *hdata = ctx->ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	disable_irq(hdata->irq);
 
 	hdata->hpd = false;
@@ -2098,7 +2083,7 @@
 		drm_helper_hpd_irq_event(ctx->drm_dev);
 
 	if (pm_runtime_suspended(dev)) {
-		DRM_DEBUG_KMS("%s : Already suspended\n", __func__);
+		DRM_DEBUG_KMS("Already suspended\n");
 		return 0;
 	}
 
@@ -2112,14 +2097,12 @@
 	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
 	struct hdmi_context *hdata = ctx->ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	hdata->hpd = gpio_get_value(hdata->hpd_gpio);
 
 	enable_irq(hdata->irq);
 
 	if (!pm_runtime_suspended(dev)) {
-		DRM_DEBUG_KMS("%s : Already resumed\n", __func__);
+		DRM_DEBUG_KMS("Already resumed\n");
 		return 0;
 	}
 
@@ -2134,7 +2117,6 @@
 {
 	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
 	struct hdmi_context *hdata = ctx->ctx;
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
 	hdmi_poweroff(hdata);
 
@@ -2145,7 +2127,6 @@
 {
 	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
 	struct hdmi_context *hdata = ctx->ctx;
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
 	hdmi_poweron(hdata);
 
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
index ea49d13..ef04255 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
@@ -51,6 +51,10 @@
 	{
 		.compatible = "samsung,exynos5-hdmiphy",
 	}, {
+		.compatible = "samsung,exynos4210-hdmiphy",
+	}, {
+		.compatible = "samsung,exynos4212-hdmiphy",
+	}, {
 		/* end node */
 	}
 };
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 7c197d38..42ffb71 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -78,6 +78,7 @@
 enum mixer_version_id {
 	MXR_VER_0_0_0_16,
 	MXR_VER_16_0_33_0,
+	MXR_VER_128_0_0_184,
 };
 
 struct mixer_context {
@@ -283,17 +284,19 @@
 	val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
 				MXR_CFG_SCAN_PROGRASSIVE);
 
-	/* choosing between porper HD and SD mode */
-	if (height <= 480)
-		val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
-	else if (height <= 576)
-		val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
-	else if (height <= 720)
-		val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
-	else if (height <= 1080)
-		val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
-	else
-		val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+	if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
+		/* choosing between proper HD and SD mode */
+		if (height <= 480)
+			val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
+		else if (height <= 576)
+			val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
+		else if (height <= 720)
+			val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+		else if (height <= 1080)
+			val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
+		else
+			val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+	}
 
 	mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
 }
@@ -376,7 +379,7 @@
 	unsigned long flags;
 	struct hdmi_win_data *win_data;
 	unsigned int x_ratio, y_ratio;
-	unsigned int buf_num;
+	unsigned int buf_num = 1;
 	dma_addr_t luma_addr[2], chroma_addr[2];
 	bool tiled_mode = false;
 	bool crcb_mode = false;
@@ -557,6 +560,14 @@
 	/* setup geometry */
 	mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
 
+	/* setup display size */
+	if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
+		win == MIXER_DEFAULT_WIN) {
+		val  = MXR_MXR_RES_HEIGHT(win_data->fb_height);
+		val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
+		mixer_reg_write(res, MXR_RESOLUTION, val);
+	}
+
 	val  = MXR_GRP_WH_WIDTH(win_data->crtc_width);
 	val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
 	val |= MXR_GRP_WH_H_SCALE(x_ratio);
@@ -581,7 +592,8 @@
 	mixer_cfg_layer(ctx, win, true);
 
 	/* layer update mandatory for mixer 16.0.33.0 */
-	if (ctx->mxr_ver == MXR_VER_16_0_33_0)
+	if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
+		ctx->mxr_ver == MXR_VER_128_0_0_184)
 		mixer_layer_update(ctx);
 
 	mixer_run(ctx);
@@ -696,8 +708,6 @@
 	struct mixer_context *mixer_ctx = ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mixer_ctx->pipe = pipe;
 
 	/* enable vsync interrupt */
@@ -712,8 +722,6 @@
 	struct mixer_context *mixer_ctx = ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	/* disable vsync interrupt */
 	mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
@@ -725,8 +733,6 @@
 	struct hdmi_win_data *win_data;
 	int win;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (!overlay) {
 		DRM_ERROR("overlay is NULL\n");
 		return;
@@ -742,7 +748,7 @@
 	if (win == DEFAULT_ZPOS)
 		win = MIXER_DEFAULT_WIN;
 
-	if (win < 0 || win > MIXER_WIN_NR) {
+	if (win < 0 || win >= MIXER_WIN_NR) {
 		DRM_ERROR("mixer window[%d] is wrong\n", win);
 		return;
 	}
@@ -776,7 +782,7 @@
 {
 	struct mixer_context *mixer_ctx = ctx;
 
-	DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
+	DRM_DEBUG_KMS("win: %d\n", win);
 
 	mutex_lock(&mixer_ctx->mixer_mutex);
 	if (!mixer_ctx->powered) {
@@ -799,7 +805,7 @@
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 	unsigned long flags;
 
-	DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
+	DRM_DEBUG_KMS("win: %d\n", win);
 
 	mutex_lock(&mixer_ctx->mixer_mutex);
 	if (!mixer_ctx->powered) {
@@ -820,17 +826,21 @@
 	mixer_ctx->win_data[win].enabled = false;
 }
 
-static int mixer_check_timing(void *ctx, struct fb_videomode *timing)
+static int mixer_check_mode(void *ctx, struct drm_display_mode *mode)
 {
+	struct mixer_context *mixer_ctx = ctx;
 	u32 w, h;
 
-	w = timing->xres;
-	h = timing->yres;
+	w = mode->hdisplay;
+	h = mode->vdisplay;
 
-	DRM_DEBUG_KMS("%s : xres=%d, yres=%d, refresh=%d, intl=%d\n",
-		__func__, timing->xres, timing->yres,
-		timing->refresh, (timing->vmode &
-		FB_VMODE_INTERLACED) ? true : false);
+	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
+		mode->hdisplay, mode->vdisplay, mode->vrefresh,
+		(mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
+
+	if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 ||
+		mixer_ctx->mxr_ver == MXR_VER_128_0_0_184)
+		return 0;
 
 	if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
 		(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
@@ -891,8 +901,6 @@
 {
 	struct mixer_resources *res = &ctx->mixer_res;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mutex_lock(&ctx->mixer_mutex);
 	if (ctx->powered) {
 		mutex_unlock(&ctx->mixer_mutex);
@@ -901,10 +909,10 @@
 	ctx->powered = true;
 	mutex_unlock(&ctx->mixer_mutex);
 
-	clk_enable(res->mixer);
+	clk_prepare_enable(res->mixer);
 	if (ctx->vp_enabled) {
-		clk_enable(res->vp);
-		clk_enable(res->sclk_mixer);
+		clk_prepare_enable(res->vp);
+		clk_prepare_enable(res->sclk_mixer);
 	}
 
 	mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
@@ -917,8 +925,6 @@
 {
 	struct mixer_resources *res = &ctx->mixer_res;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mutex_lock(&ctx->mixer_mutex);
 	if (!ctx->powered)
 		goto out;
@@ -928,10 +934,10 @@
 
 	ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
 
-	clk_disable(res->mixer);
+	clk_disable_unprepare(res->mixer);
 	if (ctx->vp_enabled) {
-		clk_disable(res->vp);
-		clk_disable(res->sclk_mixer);
+		clk_disable_unprepare(res->vp);
+		clk_disable_unprepare(res->sclk_mixer);
 	}
 
 	mutex_lock(&ctx->mixer_mutex);
@@ -945,8 +951,6 @@
 {
 	struct mixer_context *mixer_ctx = ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
 		if (pm_runtime_suspended(mixer_ctx->dev))
@@ -978,7 +982,7 @@
 	.win_disable		= mixer_win_disable,
 
 	/* display */
-	.check_timing		= mixer_check_timing,
+	.check_mode		= mixer_check_mode,
 };
 
 static irqreturn_t mixer_irq_handler(int irq, void *arg)
@@ -1128,12 +1132,17 @@
 	return 0;
 }
 
-static struct mixer_drv_data exynos5_mxr_drv_data = {
+static struct mixer_drv_data exynos5420_mxr_drv_data = {
+	.version = MXR_VER_128_0_0_184,
+	.is_vp_enabled = 0,
+};
+
+static struct mixer_drv_data exynos5250_mxr_drv_data = {
 	.version = MXR_VER_16_0_33_0,
 	.is_vp_enabled = 0,
 };
 
-static struct mixer_drv_data exynos4_mxr_drv_data = {
+static struct mixer_drv_data exynos4210_mxr_drv_data = {
 	.version = MXR_VER_0_0_0_16,
 	.is_vp_enabled = 1,
 };
@@ -1141,10 +1150,10 @@
 static struct platform_device_id mixer_driver_types[] = {
 	{
 		.name		= "s5p-mixer",
-		.driver_data	= (unsigned long)&exynos4_mxr_drv_data,
+		.driver_data	= (unsigned long)&exynos4210_mxr_drv_data,
 	}, {
 		.name		= "exynos5-mixer",
-		.driver_data	= (unsigned long)&exynos5_mxr_drv_data,
+		.driver_data	= (unsigned long)&exynos5250_mxr_drv_data,
 	}, {
 		/* end node */
 	}
@@ -1153,7 +1162,13 @@
 static struct of_device_id mixer_match_types[] = {
 	{
 		.compatible = "samsung,exynos5-mixer",
-		.data	= &exynos5_mxr_drv_data,
+		.data	= &exynos5250_mxr_drv_data,
+	}, {
+		.compatible = "samsung,exynos5250-mixer",
+		.data	= &exynos5250_mxr_drv_data,
+	}, {
+		.compatible = "samsung,exynos5420-mixer",
+		.data	= &exynos5420_mxr_drv_data,
 	}, {
 		/* end node */
 	}
@@ -1186,8 +1201,7 @@
 
 	if (dev->of_node) {
 		const struct of_device_id *match;
-		match = of_match_node(of_match_ptr(mixer_match_types),
-							  dev->of_node);
+		match = of_match_node(mixer_match_types, dev->of_node);
 		drv = (struct mixer_drv_data *)match->data;
 	} else {
 		drv = (struct mixer_drv_data *)
@@ -1251,10 +1265,8 @@
 	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
 	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (pm_runtime_suspended(dev)) {
-		DRM_DEBUG_KMS("%s : Already suspended\n", __func__);
+		DRM_DEBUG_KMS("Already suspended\n");
 		return 0;
 	}
 
@@ -1268,10 +1280,8 @@
 	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
 	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	if (!pm_runtime_suspended(dev)) {
-		DRM_DEBUG_KMS("%s : Already resumed\n", __func__);
+		DRM_DEBUG_KMS("Already resumed\n");
 		return 0;
 	}
 
@@ -1287,8 +1297,6 @@
 	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
 	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mixer_poweroff(ctx);
 
 	return 0;
@@ -1299,8 +1307,6 @@
 	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
 	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
 
-	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
 	mixer_poweron(ctx);
 
 	return 0;
diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h
index 5d8dbc0..4537026 100644
--- a/drivers/gpu/drm/exynos/regs-mixer.h
+++ b/drivers/gpu/drm/exynos/regs-mixer.h
@@ -44,6 +44,9 @@
 #define MXR_CM_COEFF_Y			0x0080
 #define MXR_CM_COEFF_CB			0x0084
 #define MXR_CM_COEFF_CR			0x0088
+#define MXR_MO				0x0304
+#define MXR_RESOLUTION			0x0310
+
 #define MXR_GRAPHIC0_BASE_S		0x2024
 #define MXR_GRAPHIC1_BASE_S		0x2044
 
@@ -119,6 +122,10 @@
 #define MXR_GRP_WH_WIDTH(x)		MXR_MASK_VAL(x, 26, 16)
 #define MXR_GRP_WH_HEIGHT(x)		MXR_MASK_VAL(x, 10, 0)
 
+/* bits for MXR_RESOLUTION */
+#define MXR_MXR_RES_HEIGHT(x)		MXR_MASK_VAL(x, 26, 16)
+#define MXR_MXR_RES_WIDTH(x)		MXR_MASK_VAL(x, 10, 0)
+
 /* bits for MXR_GRAPHICn_SXY */
 #define MXR_GRP_SXY_SX(x)		MXR_MASK_VAL(x, 26, 16)
 #define MXR_GRP_SXY_SY(x)		MXR_MASK_VAL(x, 10, 0)
diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c
index 004ecdf..ada49ed 100644
--- a/drivers/gpu/drm/i810/i810_dma.c
+++ b/drivers/gpu/drm/i810/i810_dma.c
@@ -97,7 +97,7 @@
 	buf = dev_priv->mmap_buffer;
 	buf_priv = buf->dev_private;
 
-	vma->vm_flags |= (VM_IO | VM_DONTCOPY);
+	vma->vm_flags |= VM_DONTCOPY;
 
 	buf_priv->currently_mapped = I810_BUF_MAPPED;
 
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index fd52de7..1c5b397 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1490,6 +1490,14 @@
 	dev_priv->dev = dev;
 	dev_priv->info = info;
 
+	spin_lock_init(&dev_priv->irq_lock);
+	spin_lock_init(&dev_priv->gpu_error.lock);
+	spin_lock_init(&dev_priv->backlight.lock);
+	spin_lock_init(&dev_priv->gt_lock);
+	mutex_init(&dev_priv->dpio_lock);
+	mutex_init(&dev_priv->rps.hw_lock);
+	mutex_init(&dev_priv->modeset_restore_lock);
+
 	i915_dump_device_info(dev_priv);
 
 	INIT_LIST_HEAD(&dev_priv->vm_list);
@@ -1594,6 +1602,7 @@
 	intel_detect_pch(dev);
 
 	intel_irq_init(dev);
+	intel_gt_sanitize(dev);
 	intel_gt_init(dev);
 
 	/* Try to make sure MCHBAR is enabled before poking at it */
@@ -1619,14 +1628,6 @@
 	if (!IS_I945G(dev) && !IS_I945GM(dev))
 		pci_enable_msi(dev->pdev);
 
-	spin_lock_init(&dev_priv->irq_lock);
-	spin_lock_init(&dev_priv->gpu_error.lock);
-	spin_lock_init(&dev_priv->backlight.lock);
-	mutex_init(&dev_priv->dpio_lock);
-
-	mutex_init(&dev_priv->rps.hw_lock);
-	mutex_init(&dev_priv->modeset_restore_lock);
-
 	dev_priv->num_plane = 1;
 	if (IS_VALLEYVIEW(dev))
 		dev_priv->num_plane = 2;
@@ -1656,7 +1657,7 @@
 	if (INTEL_INFO(dev)->num_pipes) {
 		/* Must be done after probing outputs */
 		intel_opregion_init(dev);
-		acpi_video_register();
+		acpi_video_register_with_quirks();
 	}
 
 	if (IS_GEN5(dev))
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index c34086a..5849b0a 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -127,10 +127,10 @@
 MODULE_PARM_DESC(preliminary_hw_support,
 		"Enable preliminary hardware support. (default: false)");
 
-int i915_disable_power_well __read_mostly = 0;
+int i915_disable_power_well __read_mostly = 1;
 module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
 MODULE_PARM_DESC(disable_power_well,
-		 "Disable the power well when possible (default: false)");
+		 "Disable the power well when possible (default: true)");
 
 int i915_enable_ips __read_mostly = 1;
 module_param_named(enable_ips, i915_enable_ips, int, 0600);
@@ -723,7 +723,7 @@
 {
 	int error = 0;
 
-	intel_gt_reset(dev);
+	intel_gt_sanitize(dev);
 
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
 		mutex_lock(&dev->struct_mutex);
@@ -749,7 +749,7 @@
 
 	pci_set_master(dev->pdev);
 
-	intel_gt_reset(dev);
+	intel_gt_sanitize(dev);
 
 	/*
 	 * Platforms with opregion should have sane BIOS, older ones (gen3 and
@@ -1271,21 +1271,21 @@
 
 #define __i915_read(x, y) \
 u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
+	unsigned long irqflags; \
 	u##x val = 0; \
+	spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
 	if (IS_GEN5(dev_priv->dev)) \
 		ilk_dummy_write(dev_priv); \
 	if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-		unsigned long irqflags; \
-		spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
 		if (dev_priv->forcewake_count == 0) \
 			dev_priv->gt.force_wake_get(dev_priv); \
 		val = read##y(dev_priv->regs + reg); \
 		if (dev_priv->forcewake_count == 0) \
 			dev_priv->gt.force_wake_put(dev_priv); \
-		spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
 	} else { \
 		val = read##y(dev_priv->regs + reg); \
 	} \
+	spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
 	trace_i915_reg_rw(false, reg, val, sizeof(val)); \
 	return val; \
 }
@@ -1298,8 +1298,10 @@
 
 #define __i915_write(x, y) \
 void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
+	unsigned long irqflags; \
 	u32 __fifo_ret = 0; \
 	trace_i915_reg_rw(true, reg, val, sizeof(val)); \
+	spin_lock_irqsave(&dev_priv->gt_lock, irqflags); \
 	if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
 		__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
 	} \
@@ -1311,6 +1313,7 @@
 		gen6_gt_check_fifodbg(dev_priv); \
 	} \
 	hsw_unclaimed_reg_check(dev_priv, reg); \
+	spin_unlock_irqrestore(&dev_priv->gt_lock, irqflags); \
 }
 __i915_write(8, b)
 __i915_write(16, w)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index fc32d20..331c00b 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -622,6 +622,7 @@
 #define QUIRK_PIPEA_FORCE (1<<0)
 #define QUIRK_LVDS_SSC_DISABLE (1<<1)
 #define QUIRK_INVERT_BRIGHTNESS (1<<2)
+#define QUIRK_NO_PCH_PWM_ENABLE (1<<3)
 
 struct intel_fbdev;
 struct intel_fbc_work;
@@ -1670,7 +1671,7 @@
 extern void intel_irq_init(struct drm_device *dev);
 extern void intel_hpd_init(struct drm_device *dev);
 extern void intel_gt_init(struct drm_device *dev);
-extern void intel_gt_reset(struct drm_device *dev);
+extern void intel_gt_sanitize(struct drm_device *dev);
 
 void
 i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
@@ -1887,6 +1888,8 @@
 struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
 				struct drm_gem_object *gem_obj, int flags);
 
+void i915_gem_restore_fences(struct drm_device *dev);
+
 /* i915_gem_context.c */
 void i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_fini(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 0a1ddb8..eceab96 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1877,6 +1877,10 @@
 	u32 seqno = intel_ring_get_seqno(ring);
 
 	BUG_ON(ring == NULL);
+	if (obj->ring != ring && obj->last_write_seqno) {
+		/* Keep the seqno relative to the current ring */
+		obj->last_write_seqno = seqno;
+	}
 	obj->ring = ring;
 
 	/* Add a reference if we're newly entering the active list. */
@@ -2243,7 +2247,7 @@
 	}
 }
 
-static void i915_gem_reset_fences(struct drm_device *dev)
+void i915_gem_restore_fences(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int i;
@@ -2251,17 +2255,17 @@
 	for (i = 0; i < dev_priv->num_fence_regs; i++) {
 		struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
 
-		if (reg->obj)
-			i915_gem_object_fence_lost(reg->obj);
-
-		i915_gem_write_fence(dev, i, NULL);
-
-		reg->pin_count = 0;
-		reg->obj = NULL;
-		INIT_LIST_HEAD(&reg->lru_list);
+		/*
+		 * Commit delayed tiling changes if we have an object still
+		 * attached to the fence, otherwise just clear the fence.
+		 */
+		if (reg->obj) {
+			i915_gem_object_update_fence(reg->obj, reg,
+						     reg->obj->tiling_mode);
+		} else {
+			i915_gem_write_fence(dev, i, NULL);
+		}
 	}
-
-	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
 }
 
 void i915_gem_reset(struct drm_device *dev)
@@ -2281,8 +2285,7 @@
 	list_for_each_entry(obj, &vm->inactive_list, mm_list)
 		obj->base.read_domains &= ~I915_GEM_GPU_DOMAINS;
 
-	/* The fence registers are invalidated so clear them out */
-	i915_gem_reset_fences(dev);
+	i915_gem_restore_fences(dev);
 }
 
 /**
@@ -2665,7 +2668,6 @@
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	int fence_reg;
 	int fence_pitch_shift;
-	uint64_t val;
 
 	if (INTEL_INFO(dev)->gen >= 6) {
 		fence_reg = FENCE_REG_SANDYBRIDGE_0;
@@ -2675,8 +2677,23 @@
 		fence_pitch_shift = I965_FENCE_PITCH_SHIFT;
 	}
 
+	fence_reg += reg * 8;
+
+	/* To w/a incoherency with non-atomic 64-bit register updates,
+	 * we split the 64-bit update into two 32-bit writes. In order
+	 * for a partial fence not to be evaluated between writes, we
+	 * precede the update with write to turn off the fence register,
+	 * and only enable the fence as the last step.
+	 *
+	 * For extra levels of paranoia, we make sure each step lands
+	 * before applying the next step.
+	 */
+	I915_WRITE(fence_reg, 0);
+	POSTING_READ(fence_reg);
+
 	if (obj) {
 		u32 size = i915_gem_obj_ggtt_size(obj);
+		uint64_t val;
 
 		val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) &
 				 0xfffff000) << 32;
@@ -2685,12 +2702,16 @@
 		if (obj->tiling_mode == I915_TILING_Y)
 			val |= 1 << I965_FENCE_TILING_Y_SHIFT;
 		val |= I965_FENCE_REG_VALID;
-	} else
-		val = 0;
 
-	fence_reg += reg * 8;
-	I915_WRITE64(fence_reg, val);
-	POSTING_READ(fence_reg);
+		I915_WRITE(fence_reg + 4, val >> 32);
+		POSTING_READ(fence_reg + 4);
+
+		I915_WRITE(fence_reg + 0, val);
+		POSTING_READ(fence_reg);
+	} else {
+		I915_WRITE(fence_reg + 4, 0);
+		POSTING_READ(fence_reg + 4);
+	}
 }
 
 static void i915_write_fence_reg(struct drm_device *dev, int reg,
@@ -2785,6 +2806,10 @@
 	if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj))
 		mb();
 
+	WARN(obj && (!obj->stride || !obj->tiling_mode),
+	     "bogus fence setup with stride: 0x%x, tiling mode: %i\n",
+	     obj->stride, obj->tiling_mode);
+
 	switch (INTEL_INFO(dev)->gen) {
 	case 7:
 	case 6:
@@ -2808,56 +2833,17 @@
 	return fence - dev_priv->fence_regs;
 }
 
-struct write_fence {
-	struct drm_device *dev;
-	struct drm_i915_gem_object *obj;
-	int fence;
-};
-
-static void i915_gem_write_fence__ipi(void *data)
-{
-	struct write_fence *args = data;
-
-	/* Required for SNB+ with LLC */
-	wbinvd();
-
-	/* Required for VLV */
-	i915_gem_write_fence(args->dev, args->fence, args->obj);
-}
-
 static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
 					 struct drm_i915_fence_reg *fence,
 					 bool enable)
 {
 	struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-	struct write_fence args = {
-		.dev = obj->base.dev,
-		.fence = fence_number(dev_priv, fence),
-		.obj = enable ? obj : NULL,
-	};
+	int reg = fence_number(dev_priv, fence);
 
-	/* In order to fully serialize access to the fenced region and
-	 * the update to the fence register we need to take extreme
-	 * measures on SNB+. In theory, the write to the fence register
-	 * flushes all memory transactions before, and coupled with the
-	 * mb() placed around the register write we serialise all memory
-	 * operations with respect to the changes in the tiler. Yet, on
-	 * SNB+ we need to take a step further and emit an explicit wbinvd()
-	 * on each processor in order to manually flush all memory
-	 * transactions before updating the fence register.
-	 *
-	 * However, Valleyview complicates matter. There the wbinvd is
-	 * insufficient and unlike SNB/IVB requires the serialising
-	 * register write. (Note that that register write by itself is
-	 * conversely not sufficient for SNB+.) To compromise, we do both.
-	 */
-	if (INTEL_INFO(args.dev)->gen >= 6)
-		on_each_cpu(i915_gem_write_fence__ipi, &args, 1);
-	else
-		i915_gem_write_fence(args.dev, args.fence, args.obj);
+	i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
 
 	if (enable) {
-		obj->fence_reg = args.fence;
+		obj->fence_reg = reg;
 		fence->obj = obj;
 		list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
 	} else {
@@ -2865,6 +2851,7 @@
 		fence->obj = NULL;
 		list_del_init(&fence->lru_list);
 	}
+	obj->fence_dirty = false;
 }
 
 static int
@@ -2994,7 +2981,6 @@
 		return 0;
 
 	i915_gem_object_update_fence(obj, reg, enable);
-	obj->fence_dirty = false;
 
 	return 0;
 }
@@ -4050,8 +4036,6 @@
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		i915_gem_evict_everything(dev);
 
-	i915_gem_reset_fences(dev);
-
 	del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
 
 	i915_kernel_lost_context(dev);
@@ -4397,7 +4381,8 @@
 		dev_priv->num_fence_regs = 8;
 
 	/* Initialize fence registers to zero */
-	i915_gem_reset_fences(dev);
+	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
+	i915_gem_restore_fences(dev);
 
 	i915_gem_detect_bit_6_swizzle(dev);
 	init_waitqueue_head(&dev_priv->pending_flip_queue);
@@ -4664,7 +4649,7 @@
 	list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
 		if (obj->pages_pin_count == 0)
 			cnt += obj->base.size >> PAGE_SHIFT;
-	list_for_each_entry(obj, &vm->inactive_list, global_list)
+	list_for_each_entry(obj, &vm->inactive_list, mm_list)
 		if (obj->pin_count == 0 && obj->pages_pin_count == 0)
 			cnt += obj->base.size >> PAGE_SHIFT;
 
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 837cf53..4bbde2a 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -146,7 +146,7 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	if (dev_priv->mm.stolen_base == 0)
+	if (!drm_mm_initialized(&dev_priv->mm.stolen))
 		return -ENODEV;
 
 	if (size < dev_priv->fbc.size)
@@ -178,6 +178,9 @@
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
+	if (!drm_mm_initialized(&dev_priv->mm.stolen))
+		return;
+
 	i915_gem_stolen_cleanup_compression(dev);
 	drm_mm_takedown(&dev_priv->mm.stolen);
 }
@@ -302,7 +305,7 @@
 	struct drm_i915_gem_object *obj;
 	struct drm_mm_node *stolen;
 
-	if (dev_priv->mm.stolen_base == 0)
+	if (!drm_mm_initialized(&dev_priv->mm.stolen))
 		return NULL;
 
 	DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
@@ -336,7 +339,7 @@
 	struct i915_vma *vma;
 	int ret;
 
-	if (dev_priv->mm.stolen_base == 0)
+	if (!drm_mm_initialized(&dev_priv->mm.stolen))
 		return NULL;
 
 	DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n",
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 88b9a66..70db618 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -394,6 +394,7 @@
 
 	mutex_lock(&dev->struct_mutex);
 
+	i915_gem_restore_fences(dev);
 	i915_restore_display(dev);
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 4211925..931b4bb 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -301,7 +301,7 @@
 		struct intel_digital_port *intel_dig_port =
 			enc_to_dig_port(encoder);
 
-		intel_dp->DP = intel_dig_port->port_reversal |
+		intel_dp->DP = intel_dig_port->saved_port_bits |
 			       DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
 		intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
 
@@ -1109,7 +1109,8 @@
 		 * enabling the port.
 		 */
 		I915_WRITE(DDI_BUF_CTL(port),
-			   intel_dig_port->port_reversal | DDI_BUF_CTL_ENABLE);
+			   intel_dig_port->saved_port_bits |
+			   DDI_BUF_CTL_ENABLE);
 	} else if (type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
@@ -1349,8 +1350,9 @@
 	intel_encoder->get_config = intel_ddi_get_config;
 
 	intel_dig_port->port = port;
-	intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
-					DDI_BUF_PORT_REVERSAL;
+	intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) &
+					  (DDI_BUF_PORT_REVERSAL |
+					   DDI_A_4_LANES);
 	intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
 
 	intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 32024da..baaefd7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4947,22 +4947,19 @@
 	uint32_t tmp;
 
 	tmp = I915_READ(PFIT_CONTROL);
+	if (!(tmp & PFIT_ENABLE))
+		return;
 
+	/* Check whether the pfit is attached to our pipe. */
 	if (INTEL_INFO(dev)->gen < 4) {
 		if (crtc->pipe != PIPE_B)
 			return;
-
-		/* gen2/3 store dither state in pfit control, needs to match */
-		pipe_config->gmch_pfit.control = tmp & PANEL_8TO6_DITHER_ENABLE;
 	} else {
 		if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT))
 			return;
 	}
 
-	if (!(tmp & PFIT_ENABLE))
-		return;
-
-	pipe_config->gmch_pfit.control = I915_READ(PFIT_CONTROL);
+	pipe_config->gmch_pfit.control = tmp;
 	pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS);
 	if (INTEL_INFO(dev)->gen < 5)
 		pipe_config->gmch_pfit.lvds_border_bits =
@@ -8600,6 +8597,8 @@
 		     pll->active, pll->refcount);
 		WARN(pll->active && !pll->on,
 		     "pll in active use but not on in sw tracking\n");
+		WARN(pll->on && !pll->active,
+		     "pll in on but not on in use in sw tracking\n");
 		WARN(pll->on != active,
 		     "pll on state mismatch (expected %i, found %i)\n",
 		     pll->on, active);
@@ -8824,15 +8823,20 @@
 }
 
 static bool
-is_crtc_connector_off(struct drm_crtc *crtc, struct drm_connector *connectors,
-		      int num_connectors)
+is_crtc_connector_off(struct drm_mode_set *set)
 {
 	int i;
 
-	for (i = 0; i < num_connectors; i++)
-		if (connectors[i].encoder &&
-		    connectors[i].encoder->crtc == crtc &&
-		    connectors[i].dpms != DRM_MODE_DPMS_ON)
+	if (set->num_connectors == 0)
+		return false;
+
+	if (WARN_ON(set->connectors == NULL))
+		return false;
+
+	for (i = 0; i < set->num_connectors; i++)
+		if (set->connectors[i]->encoder &&
+		    set->connectors[i]->encoder->crtc == set->crtc &&
+		    set->connectors[i]->dpms != DRM_MODE_DPMS_ON)
 			return true;
 
 	return false;
@@ -8845,10 +8849,8 @@
 
 	/* We should be able to check here if the fb has the same properties
 	 * and then just flip_or_move it */
-	if (set->connectors != NULL &&
-	    is_crtc_connector_off(set->crtc, *set->connectors,
-				  set->num_connectors)) {
-			config->mode_changed = true;
+	if (is_crtc_connector_off(set)) {
+		config->mode_changed = true;
 	} else if (set->crtc->fb != set->fb) {
 		/* If we have no fb then treat it as a full mode set */
 		if (set->crtc->fb == NULL) {
@@ -9702,6 +9704,17 @@
 	DRM_INFO("applying inverted panel brightness quirk\n");
 }
 
+/*
+ * Some machines (Dell XPS13) suffer broken backlight controls if
+ * BLM_PCH_PWM_ENABLE is set.
+ */
+static void quirk_no_pcm_pwm_enable(struct drm_device *dev)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	dev_priv->quirks |= QUIRK_NO_PCH_PWM_ENABLE;
+	DRM_INFO("applying no-PCH_PWM_ENABLE quirk\n");
+}
+
 struct intel_quirk {
 	int device;
 	int subsystem_vendor;
@@ -9771,6 +9784,11 @@
 
 	/* Acer Aspire 4736Z */
 	{ 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
+
+	/* Dell XPS13 HD Sandy Bridge */
+	{ 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable },
+	/* Dell XPS13 HD and XPS13 FHD Ivy Bridge */
+	{ 0x0166, 0x1028, 0x058b, quirk_no_pcm_pwm_enable },
 };
 
 static void intel_init_quirks(struct drm_device *dev)
@@ -10121,8 +10139,8 @@
 		}
 		pll->refcount = pll->active;
 
-		DRM_DEBUG_KMS("%s hw state readout: refcount %i\n",
-			      pll->name, pll->refcount);
+		DRM_DEBUG_KMS("%s hw state readout: refcount %i, on %i\n",
+			      pll->name, pll->refcount, pll->on);
 	}
 
 	list_for_each_entry(encoder, &dev->mode_config.encoder_list,
@@ -10182,6 +10200,7 @@
 	struct drm_plane *plane;
 	struct intel_crtc *crtc;
 	struct intel_encoder *encoder;
+	int i;
 
 	intel_modeset_readout_hw_state(dev);
 
@@ -10213,6 +10232,18 @@
 		intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
 	}
 
+	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+		struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
+
+		if (!pll->on || pll->active)
+			continue;
+
+		DRM_DEBUG_KMS("%s enabled but not in use, disabling\n", pll->name);
+
+		pll->disable(dev_priv, pll);
+		pll->on = false;
+	}
+
 	if (force_restore) {
 		/*
 		 * We need to use raw interfaces for restoring state to avoid
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1761877..c6996ce 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -75,7 +75,12 @@
 	case DP_LINK_BW_1_62:
 	case DP_LINK_BW_2_7:
 		break;
+	case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */
+		max_link_bw = DP_LINK_BW_2_7;
+		break;
 	default:
+		WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n",
+		     max_link_bw);
 		max_link_bw = DP_LINK_BW_1_62;
 		break;
 	}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 253fc1e..3fbe80b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -506,7 +506,7 @@
 struct intel_digital_port {
 	struct intel_encoder base;
 	enum port port;
-	u32 port_reversal;
+	u32 saved_port_bits;
 	struct intel_dp dp;
 	struct intel_hdmi hdmi;
 };
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 25ea406..2110df2 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -109,6 +109,13 @@
 		flags |= DRM_MODE_FLAG_PVSYNC;
 
 	pipe_config->adjusted_mode.flags |= flags;
+
+	/* gen2/3 store dither state in pfit control, needs to match */
+	if (INTEL_INFO(dev)->gen < 4) {
+		tmp = I915_READ(PFIT_CONTROL);
+
+		pipe_config->gmch_pfit.control |= tmp & PANEL_8TO6_DITHER_ENABLE;
+	}
 }
 
 /* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -297,14 +304,11 @@
 
 		intel_pch_panel_fitting(intel_crtc, pipe_config,
 					intel_connector->panel.fitting_mode);
-		return true;
 	} else {
 		intel_gmch_panel_fitting(intel_crtc, pipe_config,
 					 intel_connector->panel.fitting_mode);
-	}
 
-	drm_mode_set_crtcinfo(adjusted_mode, 0);
-	pipe_config->timings_set = true;
+	}
 
 	/*
 	 * XXX: It would be nice to support lower refresh rates on the
@@ -700,6 +704,22 @@
 			DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"),
 		},
 	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Intel D510MO",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "D510MO"),
+		},
+	},
+	{
+		.callback = intel_no_lvds_dmi_callback,
+		.ident = "Intel D525MW",
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"),
+		},
+	},
 
 	{ }	/* terminating entry */
 };
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 80bea1d..67e2c1f 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -194,6 +194,9 @@
 	    adjusted_mode->vdisplay == mode->vdisplay)
 		goto out;
 
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
+	pipe_config->timings_set = true;
+
 	switch (fitting_mode) {
 	case DRM_MODE_SCALE_CENTER:
 		/*
@@ -580,7 +583,8 @@
 		POSTING_READ(reg);
 		I915_WRITE(reg, tmp | BLM_PWM_ENABLE);
 
-		if (HAS_PCH_SPLIT(dev)) {
+		if (HAS_PCH_SPLIT(dev) &&
+		    !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) {
 			tmp = I915_READ(BLC_PWM_PCH_CTL1);
 			tmp |= BLM_PCH_PWM_ENABLE;
 			tmp &= ~BLM_PCH_OVERRIDE_ENABLE;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index e81d376..74d6c4d 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -5473,7 +5473,7 @@
 	gen6_gt_check_fifodbg(dev_priv);
 }
 
-void intel_gt_reset(struct drm_device *dev)
+void intel_gt_sanitize(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -5484,22 +5484,51 @@
 		if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
 			__gen6_gt_force_wake_mt_reset(dev_priv);
 	}
+
+	/* BIOS often leaves RC6 enabled, but disable it for hw init */
+	if (INTEL_INFO(dev)->gen >= 6)
+		intel_disable_gt_powersave(dev);
 }
 
 void intel_gt_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 
-	spin_lock_init(&dev_priv->gt_lock);
-
-	intel_gt_reset(dev);
-
 	if (IS_VALLEYVIEW(dev)) {
 		dev_priv->gt.force_wake_get = vlv_force_wake_get;
 		dev_priv->gt.force_wake_put = vlv_force_wake_put;
-	} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
+	} else if (IS_HASWELL(dev)) {
 		dev_priv->gt.force_wake_get = __gen6_gt_force_wake_mt_get;
 		dev_priv->gt.force_wake_put = __gen6_gt_force_wake_mt_put;
+	} else if (IS_IVYBRIDGE(dev)) {
+		u32 ecobus;
+
+		/* IVB configs may use multi-threaded forcewake */
+
+		/* A small trick here - if the bios hasn't configured
+		 * MT forcewake, and if the device is in RC6, then
+		 * force_wake_mt_get will not wake the device and the
+		 * ECOBUS read will return zero. Which will be
+		 * (correctly) interpreted by the test below as MT
+		 * forcewake being disabled.
+		 */
+		mutex_lock(&dev->struct_mutex);
+		__gen6_gt_force_wake_mt_get(dev_priv);
+		ecobus = I915_READ_NOTRACE(ECOBUS);
+		__gen6_gt_force_wake_mt_put(dev_priv);
+		mutex_unlock(&dev->struct_mutex);
+
+		if (ecobus & FORCEWAKE_MT_ENABLE) {
+			dev_priv->gt.force_wake_get =
+						__gen6_gt_force_wake_mt_get;
+			dev_priv->gt.force_wake_put =
+						__gen6_gt_force_wake_mt_put;
+		} else {
+			DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n");
+			DRM_INFO("when using vblank-synced partial screen updates.\n");
+			dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get;
+			dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put;
+		}
 	} else if (IS_GEN6(dev)) {
 		dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get;
 		dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 815e303..8527ea0 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -379,6 +379,17 @@
 	return I915_READ(acthd_reg);
 }
 
+static void ring_setup_phys_status_page(struct intel_ring_buffer *ring)
+{
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	u32 addr;
+
+	addr = dev_priv->status_page_dmah->busaddr;
+	if (INTEL_INFO(ring->dev)->gen >= 4)
+		addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0;
+	I915_WRITE(HWS_PGA, addr);
+}
+
 static int init_ring_common(struct intel_ring_buffer *ring)
 {
 	struct drm_device *dev = ring->dev;
@@ -390,6 +401,11 @@
 	if (HAS_FORCE_WAKE(dev))
 		gen6_gt_force_wake_get(dev_priv);
 
+	if (I915_NEED_GFX_HWS(dev))
+		intel_ring_setup_status_page(ring);
+	else
+		ring_setup_phys_status_page(ring);
+
 	/* Stop the ring if it's running. */
 	I915_WRITE_CTL(ring, 0);
 	I915_WRITE_HEAD(ring, 0);
@@ -518,9 +534,6 @@
 	struct pipe_control *pc = ring->private;
 	struct drm_i915_gem_object *obj;
 
-	if (!ring->private)
-		return;
-
 	obj = pc->obj;
 
 	kunmap(sg_page(obj->pages->sgl));
@@ -528,7 +541,6 @@
 	drm_gem_object_unreference(&obj->base);
 
 	kfree(pc);
-	ring->private = NULL;
 }
 
 static int init_render_ring(struct intel_ring_buffer *ring)
@@ -601,7 +613,10 @@
 	if (HAS_BROKEN_CS_TLB(dev))
 		drm_gem_object_unreference(to_gem_object(ring->private));
 
-	cleanup_pipe_control(ring);
+	if (INTEL_INFO(dev)->gen >= 5)
+		cleanup_pipe_control(ring);
+
+	ring->private = NULL;
 }
 
 static void
@@ -1223,7 +1238,6 @@
 	ring->status_page.obj = obj;
 	memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
-	intel_ring_setup_status_page(ring);
 	DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
 			ring->name, ring->status_page.gfx_addr);
 
@@ -1237,10 +1251,9 @@
 	return ret;
 }
 
-static int init_phys_hws_pga(struct intel_ring_buffer *ring)
+static int init_phys_status_page(struct intel_ring_buffer *ring)
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
-	u32 addr;
 
 	if (!dev_priv->status_page_dmah) {
 		dev_priv->status_page_dmah =
@@ -1249,11 +1262,6 @@
 			return -ENOMEM;
 	}
 
-	addr = dev_priv->status_page_dmah->busaddr;
-	if (INTEL_INFO(ring->dev)->gen >= 4)
-		addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0;
-	I915_WRITE(HWS_PGA, addr);
-
 	ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
 	memset(ring->status_page.page_addr, 0, PAGE_SIZE);
 
@@ -1281,7 +1289,7 @@
 			return ret;
 	} else {
 		BUG_ON(ring->id != RCS);
-		ret = init_phys_hws_pga(ring);
+		ret = init_phys_status_page(ring);
 		if (ret)
 			return ret;
 	}
@@ -1893,7 +1901,7 @@
 	}
 
 	if (!I915_NEED_GFX_HWS(dev)) {
-		ret = init_phys_hws_pga(ring);
+		ret = init_phys_status_page(ring);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 998e8b4..d939a1d 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -12,7 +12,6 @@
 nouveau-y += core/core/engine.o
 nouveau-y += core/core/enum.o
 nouveau-y += core/core/event.o
-nouveau-y += core/core/falcon.o
 nouveau-y += core/core/gpuobj.o
 nouveau-y += core/core/handle.o
 nouveau-y += core/core/mm.o
@@ -60,6 +59,8 @@
 nouveau-y += core/subdev/devinit/nv1a.o
 nouveau-y += core/subdev/devinit/nv20.o
 nouveau-y += core/subdev/devinit/nv50.o
+nouveau-y += core/subdev/devinit/nva3.o
+nouveau-y += core/subdev/devinit/nvc0.o
 nouveau-y += core/subdev/fb/base.o
 nouveau-y += core/subdev/fb/nv04.o
 nouveau-y += core/subdev/fb/nv10.o
@@ -78,6 +79,17 @@
 nouveau-y += core/subdev/fb/nv4e.o
 nouveau-y += core/subdev/fb/nv50.o
 nouveau-y += core/subdev/fb/nvc0.o
+nouveau-y += core/subdev/fb/ramnv04.o
+nouveau-y += core/subdev/fb/ramnv10.o
+nouveau-y += core/subdev/fb/ramnv1a.o
+nouveau-y += core/subdev/fb/ramnv20.o
+nouveau-y += core/subdev/fb/ramnv40.o
+nouveau-y += core/subdev/fb/ramnv41.o
+nouveau-y += core/subdev/fb/ramnv44.o
+nouveau-y += core/subdev/fb/ramnv49.o
+nouveau-y += core/subdev/fb/ramnv4e.o
+nouveau-y += core/subdev/fb/ramnv50.o
+nouveau-y += core/subdev/fb/ramnvc0.o
 nouveau-y += core/subdev/gpio/base.o
 nouveau-y += core/subdev/gpio/nv10.o
 nouveau-y += core/subdev/gpio/nv50.o
@@ -129,12 +141,15 @@
 nouveau-y += core/subdev/vm/nv50.o
 nouveau-y += core/subdev/vm/nvc0.o
 
+nouveau-y += core/engine/falcon.o
+nouveau-y += core/engine/xtensa.o
 nouveau-y += core/engine/dmaobj/base.o
 nouveau-y += core/engine/dmaobj/nv04.o
 nouveau-y += core/engine/dmaobj/nv50.o
 nouveau-y += core/engine/dmaobj/nvc0.o
 nouveau-y += core/engine/dmaobj/nvd0.o
 nouveau-y += core/engine/bsp/nv84.o
+nouveau-y += core/engine/bsp/nv98.o
 nouveau-y += core/engine/bsp/nvc0.o
 nouveau-y += core/engine/bsp/nve0.o
 nouveau-y += core/engine/copy/nva3.o
@@ -185,7 +200,13 @@
 nouveau-y += core/engine/graph/ctxnv40.o
 nouveau-y += core/engine/graph/ctxnv50.o
 nouveau-y += core/engine/graph/ctxnvc0.o
-nouveau-y += core/engine/graph/ctxnve0.o
+nouveau-y += core/engine/graph/ctxnvc1.o
+nouveau-y += core/engine/graph/ctxnvc3.o
+nouveau-y += core/engine/graph/ctxnvc8.o
+nouveau-y += core/engine/graph/ctxnvd7.o
+nouveau-y += core/engine/graph/ctxnvd9.o
+nouveau-y += core/engine/graph/ctxnve4.o
+nouveau-y += core/engine/graph/ctxnvf0.o
 nouveau-y += core/engine/graph/nv04.o
 nouveau-y += core/engine/graph/nv10.o
 nouveau-y += core/engine/graph/nv20.o
@@ -197,7 +218,13 @@
 nouveau-y += core/engine/graph/nv40.o
 nouveau-y += core/engine/graph/nv50.o
 nouveau-y += core/engine/graph/nvc0.o
-nouveau-y += core/engine/graph/nve0.o
+nouveau-y += core/engine/graph/nvc1.o
+nouveau-y += core/engine/graph/nvc3.o
+nouveau-y += core/engine/graph/nvc8.o
+nouveau-y += core/engine/graph/nvd7.o
+nouveau-y += core/engine/graph/nvd9.o
+nouveau-y += core/engine/graph/nve4.o
+nouveau-y += core/engine/graph/nvf0.o
 nouveau-y += core/engine/mpeg/nv31.o
 nouveau-y += core/engine/mpeg/nv40.o
 nouveau-y += core/engine/mpeg/nv50.o
@@ -209,6 +236,7 @@
 nouveau-y += core/engine/software/nv50.o
 nouveau-y += core/engine/software/nvc0.o
 nouveau-y += core/engine/vp/nv84.o
+nouveau-y += core/engine/vp/nv98.o
 nouveau-y += core/engine/vp/nvc0.o
 nouveau-y += core/engine/vp/nve0.o
 
diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c
index 0261a11..d829172 100644
--- a/drivers/gpu/drm/nouveau/core/core/mm.c
+++ b/drivers/gpu/drm/nouveau/core/core/mm.c
@@ -208,7 +208,6 @@
 	struct nouveau_mm_node *node;
 
 	if (block) {
-		mutex_init(&mm->mutex);
 		INIT_LIST_HEAD(&mm->nodes);
 		INIT_LIST_HEAD(&mm->free);
 		mm->block_size = block;
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
index 1d9f614..1e8e75c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
@@ -19,24 +19,19 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs, Ilia Mirkin
  */
 
-#include <core/engctx.h>
-#include <core/class.h>
-
+#include <engine/xtensa.h>
 #include <engine/bsp.h>
 
-struct nv84_bsp_priv {
-	struct nouveau_engine base;
-};
-
 /*******************************************************************************
  * BSP object classes
  ******************************************************************************/
 
 static struct nouveau_oclass
 nv84_bsp_sclass[] = {
+	{ 0x74b0, &nouveau_object_ofuncs },
 	{},
 };
 
@@ -48,7 +43,7 @@
 nv84_bsp_cclass = {
 	.handle = NV_ENGCTX(BSP, 0x84),
 	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_engctx_ctor,
+		.ctor = _nouveau_xtensa_engctx_ctor,
 		.dtor = _nouveau_engctx_dtor,
 		.init = _nouveau_engctx_init,
 		.fini = _nouveau_engctx_fini,
@@ -66,10 +61,10 @@
 	      struct nouveau_oclass *oclass, void *data, u32 size,
 	      struct nouveau_object **pobject)
 {
-	struct nv84_bsp_priv *priv;
+	struct nouveau_xtensa *priv;
 	int ret;
 
-	ret = nouveau_engine_create(parent, engine, oclass, true,
+	ret = nouveau_xtensa_create(parent, engine, oclass, 0x103000, true,
 				    "PBSP", "bsp", &priv);
 	*pobject = nv_object(priv);
 	if (ret)
@@ -78,6 +73,8 @@
 	nv_subdev(priv)->unit = 0x04008000;
 	nv_engine(priv)->cclass = &nv84_bsp_cclass;
 	nv_engine(priv)->sclass = nv84_bsp_sclass;
+	priv->fifo_val = 0x1111;
+	priv->unkd28 = 0x90044;
 	return 0;
 }
 
@@ -86,8 +83,10 @@
 	.handle = NV_ENGINE(BSP, 0x84),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nv84_bsp_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = _nouveau_engine_init,
-		.fini = _nouveau_engine_fini,
+		.dtor = _nouveau_xtensa_dtor,
+		.init = _nouveau_xtensa_init,
+		.fini = _nouveau_xtensa_fini,
+		.rd32 = _nouveau_xtensa_rd32,
+		.wr32 = _nouveau_xtensa_wr32,
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
new file mode 100644
index 0000000..8bf92b0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/engctx.h>
+#include <core/class.h>
+
+#include <engine/bsp.h>
+
+struct nv98_bsp_priv {
+	struct nouveau_engine base;
+};
+
+/*******************************************************************************
+ * BSP object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_bsp_sclass[] = {
+	{},
+};
+
+/*******************************************************************************
+ * BSP context
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_bsp_cclass = {
+	.handle = NV_ENGCTX(BSP, 0x98),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = _nouveau_engctx_ctor,
+		.dtor = _nouveau_engctx_dtor,
+		.init = _nouveau_engctx_init,
+		.fini = _nouveau_engctx_fini,
+		.rd32 = _nouveau_engctx_rd32,
+		.wr32 = _nouveau_engctx_wr32,
+	},
+};
+
+/*******************************************************************************
+ * BSP engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	      struct nouveau_oclass *oclass, void *data, u32 size,
+	      struct nouveau_object **pobject)
+{
+	struct nv98_bsp_priv *priv;
+	int ret;
+
+	ret = nouveau_engine_create(parent, engine, oclass, true,
+				    "PBSP", "bsp", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x04008000;
+	nv_engine(priv)->cclass = &nv98_bsp_cclass;
+	nv_engine(priv)->sclass = nv98_bsp_sclass;
+	return 0;
+}
+
+struct nouveau_oclass
+nv98_bsp_oclass = {
+	.handle = NV_ENGINE(BSP, 0x98),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv98_bsp_ctor,
+		.dtor = _nouveau_engine_dtor,
+		.init = _nouveau_engine_init,
+		.fini = _nouveau_engine_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
index 0a5aa6b..ce860de 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
@@ -22,8 +22,7 @@
  * Authors: Maarten Lankhorst
  */
 
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
 #include <engine/bsp.h>
 
 struct nvc0_bsp_priv {
@@ -91,6 +90,7 @@
 		return ret;
 
 	nv_subdev(priv)->unit = 0x00008000;
+	nv_subdev(priv)->intr = nouveau_falcon_intr;
 	nv_engine(priv)->cclass = &nvc0_bsp_cclass;
 	nv_engine(priv)->sclass = nvc0_bsp_sclass;
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
index d4f23bb..ba6aeca 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
@@ -22,8 +22,7 @@
  * Authors: Ben Skeggs
  */
 
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
 #include <engine/bsp.h>
 
 struct nve0_bsp_priv {
@@ -91,6 +90,7 @@
 		return ret;
 
 	nv_subdev(priv)->unit = 0x00008000;
+	nv_subdev(priv)->intr = nouveau_falcon_intr;
 	nv_engine(priv)->cclass = &nve0_bsp_cclass;
 	nv_engine(priv)->sclass = nve0_bsp_sclass;
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
index c92520f..241b272 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
@@ -1,4 +1,4 @@
-static u32 nva3_pcopy_data[] = {
+uint32_t nva3_pcopy_data[] = {
 /* 0x0000: ctx_object */
 	0x00000000,
 /* 0x0004: ctx_dma */
@@ -183,7 +183,7 @@
 	0x00000800,
 };
 
-static u32 nva3_pcopy_code[] = {
+uint32_t nva3_pcopy_code[] = {
 /* 0x0000: main */
 	0x04fe04bd,
 	0x3517f000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
index 0d98c6c..98cc421 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
@@ -1,4 +1,4 @@
-static u32 nvc0_pcopy_data[] = {
+uint32_t nvc0_pcopy_data[] = {
 /* 0x0000: ctx_object */
 	0x00000000,
 /* 0x0004: ctx_query_address_high */
@@ -171,7 +171,7 @@
 	0x00000800,
 };
 
-static u32 nvc0_pcopy_code[] = {
+uint32_t nvc0_pcopy_code[] = {
 /* 0x0000: main */
 	0x04fe04bd,
 	0x3517f000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
index d6dc2a6..f315277 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
@@ -22,16 +22,17 @@
  * Authors: Ben Skeggs
  */
 
-#include <core/client.h>
-#include <core/falcon.h>
-#include <core/class.h>
-#include <core/enum.h>
+#include <engine/falcon.h>
+#include <engine/fifo.h>
+#include <engine/copy.h>
 
 #include <subdev/fb.h>
 #include <subdev/vm.h>
 
-#include <engine/fifo.h>
-#include <engine/copy.h>
+#include <core/client.h>
+#include <core/class.h>
+#include <core/enum.h>
+
 
 #include "fuc/nva3.fuc.h"
 
@@ -117,13 +118,6 @@
 }
 
 static int
-nva3_copy_tlb_flush(struct nouveau_engine *engine)
-{
-	nv50_vm_flush_engine(&engine->base, 0x0d);
-	return 0;
-}
-
-static int
 nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	       struct nouveau_oclass *oclass, void *data, u32 size,
 	       struct nouveau_object **pobject)
@@ -142,7 +136,6 @@
 	nv_subdev(priv)->intr = nva3_copy_intr;
 	nv_engine(priv)->cclass = &nva3_copy_cclass;
 	nv_engine(priv)->sclass = nva3_copy_sclass;
-	nv_engine(priv)->tlb_flush = nva3_copy_tlb_flush;
 	nv_falcon(priv)->code.data = nva3_pcopy_code;
 	nv_falcon(priv)->code.size = sizeof(nva3_pcopy_code);
 	nv_falcon(priv)->data.data = nva3_pcopy_data;
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
index b3ed273..993df09 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
@@ -22,13 +22,15 @@
  * Authors: Ben Skeggs
  */
 
-#include <core/falcon.h>
-#include <core/class.h>
-#include <core/enum.h>
-
+#include <engine/falcon.h>
 #include <engine/fifo.h>
 #include <engine/copy.h>
 
+#include <core/class.h>
+#include <core/enum.h>
+#include <core/class.h>
+#include <core/enum.h>
+
 #include "fuc/nvc0.fuc.h"
 
 struct nvc0_copy_priv {
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
index dbbe9e8..30f1ef1 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
@@ -67,6 +67,19 @@
  * PCOPY engine/subdev functions
  ******************************************************************************/
 
+static void
+nve0_copy_intr(struct nouveau_subdev *subdev)
+{
+	const int ce = nv_subidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
+	struct nve0_copy_priv *priv = (void *)subdev;
+	u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000));
+
+	if (stat) {
+		nv_warn(priv, "unhandled intr 0x%08x\n", stat);
+		nv_wr32(priv, 0x104908 + (ce * 0x1000), stat);
+	}
+}
+
 static int
 nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 		struct nouveau_oclass *oclass, void *data, u32 size,
@@ -85,6 +98,7 @@
 		return ret;
 
 	nv_subdev(priv)->unit = 0x00000040;
+	nv_subdev(priv)->intr = nve0_copy_intr;
 	nv_engine(priv)->cclass = &nve0_copy_cclass;
 	nv_engine(priv)->sclass = nve0_copy_sclass;
 	return 0;
@@ -108,6 +122,28 @@
 		return ret;
 
 	nv_subdev(priv)->unit = 0x00000080;
+	nv_subdev(priv)->intr = nve0_copy_intr;
+	nv_engine(priv)->cclass = &nve0_copy_cclass;
+	nv_engine(priv)->sclass = nve0_copy_sclass;
+	return 0;
+}
+
+static int
+nve0_copy2_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nve0_copy_priv *priv;
+	int ret;
+
+	ret = nouveau_engine_create(parent, engine, oclass, true,
+				    "PCE2", "copy2", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00200000;
+	nv_subdev(priv)->intr = nve0_copy_intr;
 	nv_engine(priv)->cclass = &nve0_copy_cclass;
 	nv_engine(priv)->sclass = nve0_copy_sclass;
 	return 0;
@@ -134,3 +170,14 @@
 		.fini = _nouveau_engine_fini,
 	},
 };
+
+struct nouveau_oclass
+nve0_copy2_oclass = {
+	.handle = NV_ENGINE(COPY2, 0xe0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nve0_copy2_ctor,
+		.dtor = _nouveau_engine_dtor,
+		.init = _nouveau_engine_init,
+		.fini = _nouveau_engine_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
index 09962e4..38676c7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
@@ -1,4 +1,4 @@
-static uint32_t nv98_pcrypt_data[] = {
+uint32_t nv98_pcrypt_data[] = {
 /* 0x0000: ctx_dma */
 /* 0x0000: ctx_dma_query */
 	0x00000000,
@@ -150,7 +150,7 @@
 	0x00000000,
 };
 
-static uint32_t nv98_pcrypt_code[] = {
+uint32_t nv98_pcrypt_code[] = {
 	0x17f004bd,
 	0x0010fe35,
 	0xf10004fe,
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
index 5bc021f..2551daf 100644
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
@@ -141,13 +141,6 @@
 }
 
 static int
-nv84_crypt_tlb_flush(struct nouveau_engine *engine)
-{
-	nv50_vm_flush_engine(&engine->base, 0x0a);
-	return 0;
-}
-
-static int
 nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	       struct nouveau_oclass *oclass, void *data, u32 size,
 	       struct nouveau_object **pobject)
@@ -165,7 +158,6 @@
 	nv_subdev(priv)->intr = nv84_crypt_intr;
 	nv_engine(priv)->cclass = &nv84_crypt_cclass;
 	nv_engine(priv)->sclass = nv84_crypt_sclass;
-	nv_engine(priv)->tlb_flush = nv84_crypt_tlb_flush;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
index 8bf8955..c708237 100644
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
+++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
@@ -27,11 +27,11 @@
 #include <core/enum.h>
 #include <core/class.h>
 #include <core/engctx.h>
-#include <core/falcon.h>
 
 #include <subdev/timer.h>
 #include <subdev/fb.h>
 
+#include <engine/falcon.h>
 #include <engine/fifo.h>
 #include <engine/crypt.h>
 
@@ -119,13 +119,6 @@
 }
 
 static int
-nv98_crypt_tlb_flush(struct nouveau_engine *engine)
-{
-	nv50_vm_flush_engine(&engine->base, 0x0a);
-	return 0;
-}
-
-static int
 nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	       struct nouveau_oclass *oclass, void *data, u32 size,
 	       struct nouveau_object **pobject)
@@ -143,7 +136,6 @@
 	nv_subdev(priv)->intr = nv98_crypt_intr;
 	nv_engine(priv)->cclass = &nv98_crypt_cclass;
 	nv_engine(priv)->sclass = nv98_crypt_sclass;
-	nv_engine(priv)->tlb_flush = nv98_crypt_tlb_flush;
 	nv_falcon(priv)->code.data = nv98_pcrypt_code;
 	nv_falcon(priv)->code.size = sizeof(nv98_pcrypt_code);
 	nv_falcon(priv)->data.data = nv98_pcrypt_data;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
index 5e8c3de..ffc18b8 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
@@ -227,9 +227,9 @@
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
 		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
 		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
 		break;
@@ -279,9 +279,9 @@
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
 		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
 		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
 		break;
@@ -305,9 +305,9 @@
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
 		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
 		device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
 		break;
@@ -319,7 +319,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -332,8 +332,8 @@
 		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
 		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv84_mpeg_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
 		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
@@ -346,7 +346,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -358,8 +358,8 @@
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
 		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
 		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
@@ -372,7 +372,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -384,8 +384,8 @@
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
 		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
 		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
@@ -398,7 +398,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nv98_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nv50_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -410,8 +410,8 @@
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nv84_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nv50_software_oclass;
 		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
-		device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
-		device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
+		device->oclass[NVDEV_ENGINE_VP     ] = &nv98_vp_oclass;
+		device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
 		device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
index a36e64e..418f51f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
@@ -62,7 +62,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -75,7 +75,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvc0_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -91,7 +91,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -104,7 +104,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -120,7 +120,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -133,7 +133,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -148,7 +148,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -161,7 +161,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -177,7 +177,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -190,7 +190,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -206,7 +206,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -219,7 +219,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvc1_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -234,7 +234,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -247,7 +247,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvc8_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -263,7 +263,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -276,7 +276,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvd9_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -291,7 +291,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -304,7 +304,7 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nvc0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nvc0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvd7_graph_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
index a354e40..7aca187 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
@@ -62,7 +62,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -75,10 +75,11 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nve0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
 		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
 		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -91,7 +92,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -104,10 +105,11 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nve0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
 		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
 		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -120,7 +122,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -133,10 +135,11 @@
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nve0_graph_oclass;
+		device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
 		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
 		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
+		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
@@ -149,7 +152,7 @@
 		device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
 		device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
 		device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+		device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
 		device->oclass[NVDEV_SUBDEV_MC     ] = &nvc0_mc_oclass;
 		device->oclass[NVDEV_SUBDEV_BUS    ] = &nvc0_bus_oclass;
 		device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
@@ -160,16 +163,14 @@
 		device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
 		device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
 		device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-#if 0
 		device->oclass[NVDEV_ENGINE_FIFO   ] = &nve0_fifo_oclass;
 		device->oclass[NVDEV_ENGINE_SW     ] = &nvc0_software_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nve0_graph_oclass;
-#endif
+		device->oclass[NVDEV_ENGINE_GR     ] =  nvf0_graph_oclass;
 		device->oclass[NVDEV_ENGINE_DISP   ] = &nvf0_disp_oclass;
-#if 0
 		device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
 		device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
 		device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
+#if 0
 		device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
 		device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
 		device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
index f065fc2..db8c6fd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
@@ -55,6 +55,10 @@
 	nv_wr32(priv, 0x61c510 + soff, 0x00000000);
 	nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001);
 
+	nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
+	nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
+	nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
+
 	/* ??? */
 	nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
 	nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 6a38402..7ffe2f3 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -34,9 +34,9 @@
 #include <subdev/bios/disp.h>
 #include <subdev/bios/init.h>
 #include <subdev/bios/pll.h>
+#include <subdev/devinit.h>
 #include <subdev/timer.h>
 #include <subdev/fb.h>
-#include <subdev/clock.h>
 
 #include "nv50.h"
 
@@ -987,10 +987,10 @@
 static void
 nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
 {
-	struct nouveau_clock *clk = nouveau_clock(priv);
+	struct nouveau_devinit *devinit = nouveau_devinit(priv);
 	u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
 	if (pclk)
-		clk->pll_set(clk, PLL_VPLL0 + head, pclk);
+		devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
 }
 
 static void
@@ -1107,6 +1107,7 @@
 	u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
 	u32 hval, hreg = 0x614200 + (head * 0x800);
 	u32 oval, oreg;
+	u32 mask;
 	u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
 	if (conf != ~0) {
 		if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
@@ -1133,6 +1134,7 @@
 			oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
 			oval = 0x00000000;
 			hval = 0x00000000;
+			mask = 0xffffffff;
 		} else
 		if (!outp.location) {
 			if (outp.type == DCB_OUTPUT_DP)
@@ -1140,14 +1142,16 @@
 			oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
 			oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
 			hval = 0x00000000;
+			mask = 0x00000707;
 		} else {
 			oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800;
 			oval = 0x00000001;
 			hval = 0x00000001;
+			mask = 0x00000707;
 		}
 
 		nv_mask(priv, hreg, 0x0000000f, hval);
-		nv_mask(priv, oreg, 0x00000707, oval);
+		nv_mask(priv, oreg, mask, oval);
 	}
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 019eacd8..52dd7a1 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -29,15 +29,14 @@
 
 #include <engine/disp.h>
 
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/clock.h>
-
 #include <subdev/bios.h>
 #include <subdev/bios/dcb.h>
 #include <subdev/bios/disp.h>
 #include <subdev/bios/init.h>
 #include <subdev/bios/pll.h>
+#include <subdev/devinit.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
 
 #include "nv50.h"
 
@@ -738,10 +737,10 @@
 static void
 nvd0_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head)
 {
-	struct nouveau_clock *clk = nouveau_clock(priv);
+	struct nouveau_devinit *devinit = nouveau_devinit(priv);
 	u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
 	if (pclk)
-		clk->pll_set(clk, PLL_VPLL0 + head, pclk);
+		devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
 	nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
 }
 
@@ -959,6 +958,9 @@
 	int heads = nv_rd32(parent, 0x022448);
 	int ret;
 
+	if (nv_rd32(parent, 0x022500) & 0x00000001)
+		return -ENODEV;
+
 	ret = nouveau_disp_create(parent, engine, oclass, heads,
 				  "PDISP", "display", &priv);
 	*pobject = nv_object(priv);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
index 20725b3..fb1fe6a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
@@ -54,6 +54,9 @@
 	int heads = nv_rd32(parent, 0x022448);
 	int ret;
 
+	if (nv_rd32(parent, 0x022500) & 0x00000001)
+		return -ENODEV;
+
 	ret = nouveau_disp_create(parent, engine, oclass, heads,
 				  "PDISP", "display", &priv);
 	*pobject = nv_object(priv);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
index a488c36..42aa6b9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
@@ -54,6 +54,9 @@
 	int heads = nv_rd32(parent, 0x022448);
 	int ret;
 
+	if (nv_rd32(parent, 0x022500) & 0x00000001)
+		return -ENODEV;
+
 	ret = nouveau_disp_create(parent, engine, oclass, heads,
 				  "PDISP", "display", &priv);
 	*pobject = nv_object(priv);
diff --git a/drivers/gpu/drm/nouveau/core/core/falcon.c b/drivers/gpu/drm/nouveau/core/engine/falcon.c
similarity index 93%
rename from drivers/gpu/drm/nouveau/core/core/falcon.c
rename to drivers/gpu/drm/nouveau/core/engine/falcon.c
index e05c157..e03fc8e 100644
--- a/drivers/gpu/drm/nouveau/core/core/falcon.c
+++ b/drivers/gpu/drm/nouveau/core/engine/falcon.c
@@ -20,10 +20,28 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
 #include <subdev/timer.h>
 
+void
+nouveau_falcon_intr(struct nouveau_subdev *subdev)
+{
+	struct nouveau_falcon *falcon = (void *)subdev;
+	u32 dispatch = nv_ro32(falcon, 0x01c);
+	u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
+
+	if (intr & 0x00000010) {
+		nv_debug(falcon, "ucode halted\n");
+		nv_wo32(falcon, 0x004, 0x00000010);
+		intr &= ~0x00000010;
+	}
+
+	if (intr)  {
+		nv_error(falcon, "unhandled intr 0x%08x\n", intr);
+		nv_wo32(falcon, 0x004, intr);
+	}
+}
+
 u32
 _nouveau_falcon_rd32(struct nouveau_object *object, u64 addr)
 {
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
index 2b1f917..5c7433d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
@@ -320,7 +320,7 @@
 		break;
 	default:
 		nv_wr32(priv, 0x002230, 0x00000000);
-		nv_wr32(priv, 0x002220, ((pfb->ram.size - 512 * 1024 +
+		nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 +
 					 priv->ramfc->addr) >> 16) |
 					0x00030000);
 		break;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
index 35b94bd..7f53196 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
@@ -56,7 +56,9 @@
 	switch (nv_engidx(object->engine)) {
 	case NVDEV_ENGINE_SW   : return 0;
 	case NVDEV_ENGINE_GR   : addr = 0x0020; break;
+	case NVDEV_ENGINE_VP   : addr = 0x0040; break;
 	case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+	case NVDEV_ENGINE_BSP  : addr = 0x0080; break;
 	case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
 	case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
 	default:
@@ -89,7 +91,9 @@
 	switch (nv_engidx(object->engine)) {
 	case NVDEV_ENGINE_SW   : return 0;
 	case NVDEV_ENGINE_GR   : engn = 0; addr = 0x0020; break;
+	case NVDEV_ENGINE_VP   : engn = 3; addr = 0x0040; break;
 	case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
+	case NVDEV_ENGINE_BSP  : engn = 5; addr = 0x0080; break;
 	case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break;
 	case NVDEV_ENGINE_COPY0: engn = 2; addr = 0x00c0; break;
 	default:
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index 56192a7..09644fa 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -44,7 +44,8 @@
 	u64 subdev;
 	u64 mask;
 } fifo_engine[] = {
-	_(NVDEV_ENGINE_GR      , (1ULL << NVDEV_ENGINE_SW)),
+	_(NVDEV_ENGINE_GR      , (1ULL << NVDEV_ENGINE_SW) |
+				 (1ULL << NVDEV_ENGINE_COPY2)),
 	_(NVDEV_ENGINE_VP      , 0),
 	_(NVDEV_ENGINE_PPP     , 0),
 	_(NVDEV_ENGINE_BSP     , 0),
@@ -96,18 +97,6 @@
 
 	mutex_lock(&nv_subdev(priv)->mutex);
 	cur = engn->playlist[engn->cur_playlist];
-	if (unlikely(cur == NULL)) {
-		int ret = nouveau_gpuobj_new(nv_object(priv), NULL,
-					     0x8000, 0x1000, 0, &cur);
-		if (ret) {
-			mutex_unlock(&nv_subdev(priv)->mutex);
-			nv_error(priv, "playlist alloc failed\n");
-			return;
-		}
-
-		engn->playlist[engn->cur_playlist] = cur;
-	}
-
 	engn->cur_playlist = !engn->cur_playlist;
 
 	for (i = 0, p = 0; i < priv->base.max; i++) {
@@ -138,10 +127,12 @@
 	int ret;
 
 	switch (nv_engidx(object->engine)) {
-	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   :
+	case NVDEV_ENGINE_SW   :
 	case NVDEV_ENGINE_COPY0:
-	case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
+	case NVDEV_ENGINE_COPY1:
+	case NVDEV_ENGINE_COPY2:
+		return 0;
+	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
 	case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
 	case NVDEV_ENGINE_VP   : addr = 0x0250; break;
 	case NVDEV_ENGINE_PPP  : addr = 0x0260; break;
@@ -176,9 +167,10 @@
 
 	switch (nv_engidx(object->engine)) {
 	case NVDEV_ENGINE_SW   : return 0;
-	case NVDEV_ENGINE_GR   :
 	case NVDEV_ENGINE_COPY0:
-	case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
+	case NVDEV_ENGINE_COPY1:
+	case NVDEV_ENGINE_COPY2: addr = 0x0000; break;
+	case NVDEV_ENGINE_GR   : addr = 0x0210; break;
 	case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
 	case NVDEV_ENGINE_VP   : addr = 0x0250; break;
 	case NVDEV_ENGINE_PPP  : addr = 0x0260; break;
@@ -194,9 +186,12 @@
 			return -EBUSY;
 	}
 
-	nv_wo32(base, addr + 0x00, 0x00000000);
-	nv_wo32(base, addr + 0x04, 0x00000000);
-	bar->flush(bar);
+	if (addr) {
+		nv_wo32(base, addr + 0x00, 0x00000000);
+		nv_wo32(base, addr + 0x04, 0x00000000);
+		bar->flush(bar);
+	}
+
 	return 0;
 }
 
@@ -226,8 +221,10 @@
 		}
 	}
 
-	if (i == FIFO_ENGINE_NR)
+	if (i == FIFO_ENGINE_NR) {
+		nv_error(priv, "unsupported engines 0x%08x\n", args->engine);
 		return -ENODEV;
+	}
 
 	ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
 					  priv->user.bar.offset, 0x200,
@@ -592,13 +589,25 @@
 	       struct nouveau_object **pobject)
 {
 	struct nve0_fifo_priv *priv;
-	int ret;
+	int ret, i;
 
 	ret = nouveau_fifo_create(parent, engine, oclass, 0, 4095, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
+	for (i = 0; i < FIFO_ENGINE_NR; i++) {
+		ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+					 0, &priv->engine[i].playlist[0]);
+		if (ret)
+			return ret;
+
+		ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+					 0, &priv->engine[i].playlist[1]);
+		if (ret)
+			return ret;
+	}
+
 	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 4096 * 0x200, 0x1000,
 				 NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
 	if (ret)
@@ -629,7 +638,7 @@
 	nouveau_gpuobj_unmap(&priv->user.bar);
 	nouveau_gpuobj_ref(NULL, &priv->user.mem);
 
-	for (i = 0; i < ARRAY_SIZE(priv->engine); i++) {
+	for (i = 0; i < FIFO_ENGINE_NR; i++) {
 		nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
 		nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
 	}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
index 4cc6269..64dca26 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
@@ -24,28 +24,1077 @@
 
 #include "nvc0.h"
 
+struct nvc0_graph_init
+nvc0_grctx_init_icmd[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000b2,  40, 0x01, 0x00000000 },
+	{ 0x000210,   8, 0x01, 0x00000040 },
+	{ 0x000218,   8, 0x01, 0x0000c080 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00001fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x003fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x0005e0,   5, 0x01, 0x00000022 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   1, 0x01, 0x00000001 },
+	{ 0x000639,   1, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x00000c48 },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00300008 },
+	{ 0x000841,   1, 0x01, 0x04000080 },
+	{ 0x000842,   1, 0x01, 0x00300008 },
+	{ 0x000843,   1, 0x01, 0x04000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x000944,   1, 0x01, 0x00000022 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000014 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_9097[] = {
+	{ 0x000800,   8, 0x40, 0x00000000 },
+	{ 0x000804,   8, 0x40, 0x00000000 },
+	{ 0x000808,   8, 0x40, 0x00000400 },
+	{ 0x00080c,   8, 0x40, 0x00000300 },
+	{ 0x000810,   1, 0x04, 0x000000cf },
+	{ 0x000850,   7, 0x40, 0x00000000 },
+	{ 0x000814,   8, 0x40, 0x00000040 },
+	{ 0x000818,   8, 0x40, 0x00000001 },
+	{ 0x00081c,   8, 0x40, 0x00000000 },
+	{ 0x000820,   8, 0x40, 0x00000000 },
+	{ 0x002700,   8, 0x20, 0x00000000 },
+	{ 0x002704,   8, 0x20, 0x00000000 },
+	{ 0x002708,   8, 0x20, 0x00000000 },
+	{ 0x00270c,   8, 0x20, 0x00000000 },
+	{ 0x002710,   8, 0x20, 0x00014000 },
+	{ 0x002714,   8, 0x20, 0x00000040 },
+	{ 0x001c00,  16, 0x10, 0x00000000 },
+	{ 0x001c04,  16, 0x10, 0x00000000 },
+	{ 0x001c08,  16, 0x10, 0x00000000 },
+	{ 0x001c0c,  16, 0x10, 0x00000000 },
+	{ 0x001d00,  16, 0x10, 0x00000000 },
+	{ 0x001d04,  16, 0x10, 0x00000000 },
+	{ 0x001d08,  16, 0x10, 0x00000000 },
+	{ 0x001d0c,  16, 0x10, 0x00000000 },
+	{ 0x001f00,  16, 0x08, 0x00000000 },
+	{ 0x001f04,  16, 0x08, 0x00000000 },
+	{ 0x001f80,  16, 0x08, 0x00000000 },
+	{ 0x001f84,  16, 0x08, 0x00000000 },
+	{ 0x002200,   5, 0x10, 0x00000022 },
+	{ 0x002000,   1, 0x04, 0x00000000 },
+	{ 0x002040,   1, 0x04, 0x00000011 },
+	{ 0x002080,   1, 0x04, 0x00000020 },
+	{ 0x0020c0,   1, 0x04, 0x00000030 },
+	{ 0x002100,   1, 0x04, 0x00000040 },
+	{ 0x002140,   1, 0x04, 0x00000051 },
+	{ 0x00200c,   6, 0x40, 0x00000001 },
+	{ 0x002010,   1, 0x04, 0x00000000 },
+	{ 0x002050,   1, 0x04, 0x00000000 },
+	{ 0x002090,   1, 0x04, 0x00000001 },
+	{ 0x0020d0,   1, 0x04, 0x00000002 },
+	{ 0x002110,   1, 0x04, 0x00000003 },
+	{ 0x002150,   1, 0x04, 0x00000004 },
+	{ 0x000380,   4, 0x20, 0x00000000 },
+	{ 0x000384,   4, 0x20, 0x00000000 },
+	{ 0x000388,   4, 0x20, 0x00000000 },
+	{ 0x00038c,   4, 0x20, 0x00000000 },
+	{ 0x000700,   4, 0x10, 0x00000000 },
+	{ 0x000704,   4, 0x10, 0x00000000 },
+	{ 0x000708,   4, 0x10, 0x00000000 },
+	{ 0x002800, 128, 0x04, 0x00000000 },
+	{ 0x000a00,  16, 0x20, 0x00000000 },
+	{ 0x000a04,  16, 0x20, 0x00000000 },
+	{ 0x000a08,  16, 0x20, 0x00000000 },
+	{ 0x000a0c,  16, 0x20, 0x00000000 },
+	{ 0x000a10,  16, 0x20, 0x00000000 },
+	{ 0x000a14,  16, 0x20, 0x00000000 },
+	{ 0x000c00,  16, 0x10, 0x00000000 },
+	{ 0x000c04,  16, 0x10, 0x00000000 },
+	{ 0x000c08,  16, 0x10, 0x00000000 },
+	{ 0x000c0c,  16, 0x10, 0x3f800000 },
+	{ 0x000d00,   8, 0x08, 0xffff0000 },
+	{ 0x000d04,   8, 0x08, 0xffff0000 },
+	{ 0x000e00,  16, 0x10, 0x00000000 },
+	{ 0x000e04,  16, 0x10, 0xffff0000 },
+	{ 0x000e08,  16, 0x10, 0xffff0000 },
+	{ 0x000d40,   4, 0x08, 0x00000000 },
+	{ 0x000d44,   4, 0x08, 0x00000000 },
+	{ 0x001e00,   8, 0x20, 0x00000001 },
+	{ 0x001e04,   8, 0x20, 0x00000001 },
+	{ 0x001e08,   8, 0x20, 0x00000002 },
+	{ 0x001e0c,   8, 0x20, 0x00000001 },
+	{ 0x001e10,   8, 0x20, 0x00000001 },
+	{ 0x001e14,   8, 0x20, 0x00000002 },
+	{ 0x001e18,   8, 0x20, 0x00000001 },
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x001514,   1, 0x04, 0x00000000 },
+	{ 0x000d68,   1, 0x04, 0x0000ffff },
+	{ 0x00121c,   1, 0x04, 0x0fac6881 },
+	{ 0x000fac,   1, 0x04, 0x00000001 },
+	{ 0x001538,   1, 0x04, 0x00000001 },
+	{ 0x000fe0,   2, 0x04, 0x00000000 },
+	{ 0x000fe8,   1, 0x04, 0x00000014 },
+	{ 0x000fec,   1, 0x04, 0x00000040 },
+	{ 0x000ff0,   1, 0x04, 0x00000000 },
+	{ 0x00179c,   1, 0x04, 0x00000000 },
+	{ 0x001228,   1, 0x04, 0x00000400 },
+	{ 0x00122c,   1, 0x04, 0x00000300 },
+	{ 0x001230,   1, 0x04, 0x00010001 },
+	{ 0x0007f8,   1, 0x04, 0x00000000 },
+	{ 0x0015b4,   1, 0x04, 0x00000001 },
+	{ 0x0015cc,   1, 0x04, 0x00000000 },
+	{ 0x001534,   1, 0x04, 0x00000000 },
+	{ 0x000fb0,   1, 0x04, 0x00000000 },
+	{ 0x0015d0,   1, 0x04, 0x00000000 },
+	{ 0x00153c,   1, 0x04, 0x00000000 },
+	{ 0x0016b4,   1, 0x04, 0x00000003 },
+	{ 0x000fbc,   4, 0x04, 0x0000ffff },
+	{ 0x000df8,   2, 0x04, 0x00000000 },
+	{ 0x001948,   1, 0x04, 0x00000000 },
+	{ 0x001970,   1, 0x04, 0x00000001 },
+	{ 0x00161c,   1, 0x04, 0x000009f0 },
+	{ 0x000dcc,   1, 0x04, 0x00000010 },
+	{ 0x00163c,   1, 0x04, 0x00000000 },
+	{ 0x0015e4,   1, 0x04, 0x00000000 },
+	{ 0x001160,  32, 0x04, 0x25e00040 },
+	{ 0x001880,  32, 0x04, 0x00000000 },
+	{ 0x000f84,   2, 0x04, 0x00000000 },
+	{ 0x0017c8,   2, 0x04, 0x00000000 },
+	{ 0x0017d0,   1, 0x04, 0x000000ff },
+	{ 0x0017d4,   1, 0x04, 0xffffffff },
+	{ 0x0017d8,   1, 0x04, 0x00000002 },
+	{ 0x0017dc,   1, 0x04, 0x00000000 },
+	{ 0x0015f4,   2, 0x04, 0x00000000 },
+	{ 0x001434,   2, 0x04, 0x00000000 },
+	{ 0x000d74,   1, 0x04, 0x00000000 },
+	{ 0x000dec,   1, 0x04, 0x00000001 },
+	{ 0x0013a4,   1, 0x04, 0x00000000 },
+	{ 0x001318,   1, 0x04, 0x00000001 },
+	{ 0x001644,   1, 0x04, 0x00000000 },
+	{ 0x000748,   1, 0x04, 0x00000000 },
+	{ 0x000de8,   1, 0x04, 0x00000000 },
+	{ 0x001648,   1, 0x04, 0x00000000 },
+	{ 0x0012a4,   1, 0x04, 0x00000000 },
+	{ 0x001120,   4, 0x04, 0x00000000 },
+	{ 0x001118,   1, 0x04, 0x00000000 },
+	{ 0x00164c,   1, 0x04, 0x00000000 },
+	{ 0x001658,   1, 0x04, 0x00000000 },
+	{ 0x001910,   1, 0x04, 0x00000290 },
+	{ 0x001518,   1, 0x04, 0x00000000 },
+	{ 0x00165c,   1, 0x04, 0x00000001 },
+	{ 0x001520,   1, 0x04, 0x00000000 },
+	{ 0x001604,   1, 0x04, 0x00000000 },
+	{ 0x001570,   1, 0x04, 0x00000000 },
+	{ 0x0013b0,   2, 0x04, 0x3f800000 },
+	{ 0x00020c,   1, 0x04, 0x00000000 },
+	{ 0x001670,   1, 0x04, 0x30201000 },
+	{ 0x001674,   1, 0x04, 0x70605040 },
+	{ 0x001678,   1, 0x04, 0xb8a89888 },
+	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+	{ 0x00166c,   1, 0x04, 0x00000000 },
+	{ 0x001680,   1, 0x04, 0x00ffff00 },
+	{ 0x0012d0,   1, 0x04, 0x00000003 },
+	{ 0x0012d4,   1, 0x04, 0x00000002 },
+	{ 0x001684,   2, 0x04, 0x00000000 },
+	{ 0x000dac,   2, 0x04, 0x00001b02 },
+	{ 0x000db4,   1, 0x04, 0x00000000 },
+	{ 0x00168c,   1, 0x04, 0x00000000 },
+	{ 0x0015bc,   1, 0x04, 0x00000000 },
+	{ 0x00156c,   1, 0x04, 0x00000000 },
+	{ 0x00187c,   1, 0x04, 0x00000000 },
+	{ 0x001110,   1, 0x04, 0x00000001 },
+	{ 0x000dc0,   3, 0x04, 0x00000000 },
+	{ 0x001234,   1, 0x04, 0x00000000 },
+	{ 0x001690,   1, 0x04, 0x00000000 },
+	{ 0x0012ac,   1, 0x04, 0x00000001 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x001000,   1, 0x04, 0x00000010 },
+	{ 0x0010fc,   1, 0x04, 0x00000000 },
+	{ 0x001290,   1, 0x04, 0x00000000 },
+	{ 0x000218,   1, 0x04, 0x00000010 },
+	{ 0x0012d8,   1, 0x04, 0x00000000 },
+	{ 0x0012dc,   1, 0x04, 0x00000010 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x00155c,   2, 0x04, 0x00000000 },
+	{ 0x001564,   1, 0x04, 0x00001fff },
+	{ 0x001574,   2, 0x04, 0x00000000 },
+	{ 0x00157c,   1, 0x04, 0x003fffff },
+	{ 0x001354,   1, 0x04, 0x00000000 },
+	{ 0x001664,   1, 0x04, 0x00000000 },
+	{ 0x001610,   1, 0x04, 0x00000012 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x00162c,   1, 0x04, 0x00000003 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000324,   6, 0x04, 0x3f800000 },
+	{ 0x000750,   1, 0x04, 0x00000000 },
+	{ 0x000760,   1, 0x04, 0x39291909 },
+	{ 0x000764,   1, 0x04, 0x79695949 },
+	{ 0x000768,   1, 0x04, 0xb9a99989 },
+	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x000770,   1, 0x04, 0x30201000 },
+	{ 0x000774,   1, 0x04, 0x70605040 },
+	{ 0x000778,   1, 0x04, 0x00009080 },
+	{ 0x000780,   1, 0x04, 0x39291909 },
+	{ 0x000784,   1, 0x04, 0x79695949 },
+	{ 0x000788,   1, 0x04, 0xb9a99989 },
+	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x0007d0,   1, 0x04, 0x30201000 },
+	{ 0x0007d4,   1, 0x04, 0x70605040 },
+	{ 0x0007d8,   1, 0x04, 0x00009080 },
+	{ 0x00037c,   1, 0x04, 0x00000001 },
+	{ 0x000740,   2, 0x04, 0x00000000 },
+	{ 0x002600,   1, 0x04, 0x00000000 },
+	{ 0x001918,   1, 0x04, 0x00000000 },
+	{ 0x00191c,   1, 0x04, 0x00000900 },
+	{ 0x001920,   1, 0x04, 0x00000405 },
+	{ 0x001308,   1, 0x04, 0x00000001 },
+	{ 0x001924,   1, 0x04, 0x00000000 },
+	{ 0x0013ac,   1, 0x04, 0x00000000 },
+	{ 0x00192c,   1, 0x04, 0x00000001 },
+	{ 0x00193c,   1, 0x04, 0x00002c1c },
+	{ 0x000d7c,   1, 0x04, 0x00000000 },
+	{ 0x000f8c,   1, 0x04, 0x00000000 },
+	{ 0x0002c0,   1, 0x04, 0x00000001 },
+	{ 0x001510,   1, 0x04, 0x00000000 },
+	{ 0x001940,   1, 0x04, 0x00000000 },
+	{ 0x000ff4,   2, 0x04, 0x00000000 },
+	{ 0x00194c,   2, 0x04, 0x00000000 },
+	{ 0x001968,   1, 0x04, 0x00000000 },
+	{ 0x001590,   1, 0x04, 0x0000003f },
+	{ 0x0007e8,   4, 0x04, 0x00000000 },
+	{ 0x00196c,   1, 0x04, 0x00000011 },
+	{ 0x00197c,   1, 0x04, 0x00000000 },
+	{ 0x000fcc,   2, 0x04, 0x00000000 },
+	{ 0x0002d8,   1, 0x04, 0x00000040 },
+	{ 0x001980,   1, 0x04, 0x00000080 },
+	{ 0x001504,   1, 0x04, 0x00000080 },
+	{ 0x001984,   1, 0x04, 0x00000000 },
+	{ 0x000300,   1, 0x04, 0x00000001 },
+	{ 0x0013a8,   1, 0x04, 0x00000000 },
+	{ 0x0012ec,   1, 0x04, 0x00000000 },
+	{ 0x001310,   1, 0x04, 0x00000000 },
+	{ 0x001314,   1, 0x04, 0x00000001 },
+	{ 0x001380,   1, 0x04, 0x00000000 },
+	{ 0x001384,   4, 0x04, 0x00000001 },
+	{ 0x001394,   1, 0x04, 0x00000000 },
+	{ 0x00139c,   1, 0x04, 0x00000000 },
+	{ 0x001398,   1, 0x04, 0x00000000 },
+	{ 0x001594,   1, 0x04, 0x00000000 },
+	{ 0x001598,   4, 0x04, 0x00000001 },
+	{ 0x000f54,   3, 0x04, 0x00000000 },
+	{ 0x0019bc,   1, 0x04, 0x00000000 },
+	{ 0x000f9c,   2, 0x04, 0x00000000 },
+	{ 0x0012cc,   1, 0x04, 0x00000000 },
+	{ 0x0012e8,   1, 0x04, 0x00000000 },
+	{ 0x00130c,   1, 0x04, 0x00000001 },
+	{ 0x001360,   8, 0x04, 0x00000000 },
+	{ 0x00133c,   2, 0x04, 0x00000001 },
+	{ 0x001344,   1, 0x04, 0x00000002 },
+	{ 0x001348,   2, 0x04, 0x00000001 },
+	{ 0x001350,   1, 0x04, 0x00000002 },
+	{ 0x001358,   1, 0x04, 0x00000001 },
+	{ 0x0012e4,   1, 0x04, 0x00000000 },
+	{ 0x00131c,   1, 0x04, 0x00000000 },
+	{ 0x001320,   3, 0x04, 0x00000000 },
+	{ 0x0019c0,   1, 0x04, 0x00000000 },
+	{ 0x001140,   1, 0x04, 0x00000000 },
+	{ 0x0019c4,   1, 0x04, 0x00000000 },
+	{ 0x0019c8,   1, 0x04, 0x00001500 },
+	{ 0x00135c,   1, 0x04, 0x00000000 },
+	{ 0x000f90,   1, 0x04, 0x00000000 },
+	{ 0x0019e0,   8, 0x04, 0x00000001 },
+	{ 0x0019cc,   1, 0x04, 0x00000001 },
+	{ 0x0015b8,   1, 0x04, 0x00000000 },
+	{ 0x001a00,   1, 0x04, 0x00001111 },
+	{ 0x001a04,   7, 0x04, 0x00000000 },
+	{ 0x000d6c,   2, 0x04, 0xffff0000 },
+	{ 0x0010f8,   1, 0x04, 0x00001010 },
+	{ 0x000d80,   5, 0x04, 0x00000000 },
+	{ 0x000da0,   1, 0x04, 0x00000000 },
+	{ 0x001508,   1, 0x04, 0x80000000 },
+	{ 0x00150c,   1, 0x04, 0x40000000 },
+	{ 0x001668,   1, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000008 },
+	{ 0x000d9c,   1, 0x04, 0x00000001 },
+	{ 0x0007dc,   1, 0x04, 0x00000000 },
+	{ 0x00074c,   1, 0x04, 0x00000055 },
+	{ 0x001420,   1, 0x04, 0x00000003 },
+	{ 0x0017bc,   2, 0x04, 0x00000000 },
+	{ 0x0017c4,   1, 0x04, 0x00000001 },
+	{ 0x001008,   1, 0x04, 0x00000008 },
+	{ 0x00100c,   1, 0x04, 0x00000040 },
+	{ 0x001010,   1, 0x04, 0x0000012c },
+	{ 0x000d60,   1, 0x04, 0x00000040 },
+	{ 0x00075c,   1, 0x04, 0x00000003 },
+	{ 0x001018,   1, 0x04, 0x00000020 },
+	{ 0x00101c,   1, 0x04, 0x00000001 },
+	{ 0x001020,   1, 0x04, 0x00000020 },
+	{ 0x001024,   1, 0x04, 0x00000001 },
+	{ 0x001444,   3, 0x04, 0x00000000 },
+	{ 0x000360,   1, 0x04, 0x20164010 },
+	{ 0x000364,   1, 0x04, 0x00000020 },
+	{ 0x000368,   1, 0x04, 0x00000000 },
+	{ 0x000de4,   1, 0x04, 0x00000000 },
+	{ 0x000204,   1, 0x04, 0x00000006 },
+	{ 0x000208,   1, 0x04, 0x00000000 },
+	{ 0x0002cc,   1, 0x04, 0x003fffff },
+	{ 0x0002d0,   1, 0x04, 0x00000c48 },
+	{ 0x001220,   1, 0x04, 0x00000005 },
+	{ 0x000fdc,   1, 0x04, 0x00000000 },
+	{ 0x000f98,   1, 0x04, 0x00300008 },
+	{ 0x001284,   1, 0x04, 0x04000080 },
+	{ 0x001450,   1, 0x04, 0x00300008 },
+	{ 0x001454,   1, 0x04, 0x04000080 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_902d[] = {
+	{ 0x000200,   1, 0x04, 0x000000cf },
+	{ 0x000204,   1, 0x04, 0x00000001 },
+	{ 0x000208,   1, 0x04, 0x00000020 },
+	{ 0x00020c,   1, 0x04, 0x00000001 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000214,   1, 0x04, 0x00000080 },
+	{ 0x000218,   2, 0x04, 0x00000100 },
+	{ 0x000220,   2, 0x04, 0x00000000 },
+	{ 0x000230,   1, 0x04, 0x000000cf },
+	{ 0x000234,   1, 0x04, 0x00000001 },
+	{ 0x000238,   1, 0x04, 0x00000020 },
+	{ 0x00023c,   1, 0x04, 0x00000001 },
+	{ 0x000244,   1, 0x04, 0x00000080 },
+	{ 0x000248,   2, 0x04, 0x00000100 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_9039[] = {
+	{ 0x00030c,   3, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000238,   2, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_90c0[] = {
+	{ 0x00270c,   8, 0x20, 0x00000000 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x000758,   1, 0x04, 0x00000100 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x000204,   3, 0x04, 0x00000000 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{ 0x00024c,   1, 0x04, 0x00000000 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x001664,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_base[] = {
+	{ 0x400204,   2, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk40xx[] = {
+	{ 0x404004,  10, 0x04, 0x00000000 },
+	{ 0x404044,   1, 0x04, 0x00000000 },
+	{ 0x404094,   1, 0x04, 0x00000000 },
+	{ 0x404098,  12, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf0000087 },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404130,   1, 0x04, 0x00000000 },
+	{ 0x404134,   1, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x404168,   1, 0x04, 0x00000000 },
+	{ 0x404174,   1, 0x04, 0x00000000 },
+	{ 0x404178,   2, 0x04, 0x00000000 },
+	{ 0x404200,   8, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk44xx[] = {
+	{ 0x404404,  14, 0x04, 0x00000000 },
+	{ 0x404460,   2, 0x04, 0x00000000 },
+	{ 0x404468,   1, 0x04, 0x00ffffff },
+	{ 0x40446c,   1, 0x04, 0x00000000 },
+	{ 0x404480,   1, 0x04, 0x00000001 },
+	{ 0x404498,   1, 0x04, 0x00000001 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk46xx[] = {
+	{ 0x404604,   1, 0x04, 0x00000015 },
+	{ 0x404608,   1, 0x04, 0x00000000 },
+	{ 0x40460c,   1, 0x04, 0x00002e00 },
+	{ 0x404610,   1, 0x04, 0x00000100 },
+	{ 0x404618,   8, 0x04, 0x00000000 },
+	{ 0x404638,   1, 0x04, 0x00000004 },
+	{ 0x40463c,   8, 0x04, 0x00000000 },
+	{ 0x40465c,   1, 0x04, 0x007f0100 },
+	{ 0x404660,   7, 0x04, 0x00000000 },
+	{ 0x40467c,   1, 0x04, 0x00000002 },
+	{ 0x404680,   8, 0x04, 0x00000000 },
+	{ 0x4046a0,   1, 0x04, 0x007f0080 },
+	{ 0x4046a4,  18, 0x04, 0x00000000 },
+	{ 0x4046f0,   2, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk47xx[] = {
+	{ 0x404700,  13, 0x04, 0x00000000 },
+	{ 0x404734,   1, 0x04, 0x00000100 },
+	{ 0x404738,   8, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk58xx[] = {
+	{ 0x405800,   1, 0x04, 0x078000bf },
+	{ 0x405830,   1, 0x04, 0x02180000 },
+	{ 0x405834,   2, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk60xx[] = {
+	{ 0x406020,   1, 0x04, 0x000103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk64xx[] = {
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   2, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk78xx[] = {
+	{ 0x407804,   1, 0x04, 0x00000023 },
+	{ 0x40780c,   1, 0x04, 0x0a418820 },
+	{ 0x407810,   1, 0x04, 0x062080e6 },
+	{ 0x407814,   1, 0x04, 0x020398a4 },
+	{ 0x407818,   1, 0x04, 0x0e629062 },
+	{ 0x40781c,   1, 0x04, 0x0a418820 },
+	{ 0x407820,   1, 0x04, 0x000000e6 },
+	{ 0x4078bc,   1, 0x04, 0x00000103 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk80xx[] = {
+	{ 0x408000,   2, 0x04, 0x00000000 },
+	{ 0x408008,   1, 0x04, 0x00000018 },
+	{ 0x40800c,   2, 0x04, 0x00000000 },
+	{ 0x408014,   1, 0x04, 0x00000069 },
+	{ 0x408018,   1, 0x04, 0xe100e100 },
+	{ 0x408064,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_rop[] = {
+	{ 0x408800,   1, 0x04, 0x02802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x0003e00d },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x02000001 },
+	{ 0x408908,   1, 0x04, 0x00c80929 },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_gpc_0[] = {
+	{ 0x418380,   1, 0x04, 0x00000016 },
+	{ 0x418400,   1, 0x04, 0x38004e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x00200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{ 0x418600,   1, 0x04, 0x0000001f },
+	{ 0x418684,   1, 0x04, 0x0000000f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   1, 0x04, 0x00000000 },
+	{ 0x41870c,   1, 0x04, 0x07c80000 },
+	{ 0x418710,   1, 0x04, 0x00000000 },
+	{ 0x418800,   1, 0x04, 0x0006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x00000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x00100000 },
+	{ 0x41891c,   1, 0x04, 0x00ff00ff },
+	{ 0x418924,   1, 0x04, 0x00000000 },
+	{ 0x418928,   1, 0x04, 0x00ffff00 },
+	{ 0x41892c,   1, 0x04, 0x0000ff00 },
+	{ 0x418b00,   1, 0x04, 0x00000000 },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{ 0x419000,   1, 0x04, 0x00000780 },
+	{ 0x419004,   2, 0x04, 0x00000000 },
+	{ 0x419014,   1, 0x04, 0x00000004 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_gpc_1[] = {
+	{ 0x418a00,   3, 0x04, 0x00000000 },
+	{ 0x418a0c,   1, 0x04, 0x00010000 },
+	{ 0x418a10,   3, 0x04, 0x00000000 },
+	{ 0x418a20,   3, 0x04, 0x00000000 },
+	{ 0x418a2c,   1, 0x04, 0x00010000 },
+	{ 0x418a30,   3, 0x04, 0x00000000 },
+	{ 0x418a40,   3, 0x04, 0x00000000 },
+	{ 0x418a4c,   1, 0x04, 0x00010000 },
+	{ 0x418a50,   3, 0x04, 0x00000000 },
+	{ 0x418a60,   3, 0x04, 0x00000000 },
+	{ 0x418a6c,   1, 0x04, 0x00010000 },
+	{ 0x418a70,   3, 0x04, 0x00000000 },
+	{ 0x418a80,   3, 0x04, 0x00000000 },
+	{ 0x418a8c,   1, 0x04, 0x00010000 },
+	{ 0x418a90,   3, 0x04, 0x00000000 },
+	{ 0x418aa0,   3, 0x04, 0x00000000 },
+	{ 0x418aac,   1, 0x04, 0x00010000 },
+	{ 0x418ab0,   3, 0x04, 0x00000000 },
+	{ 0x418ac0,   3, 0x04, 0x00000000 },
+	{ 0x418acc,   1, 0x04, 0x00010000 },
+	{ 0x418ad0,   3, 0x04, 0x00000000 },
+	{ 0x418ae0,   3, 0x04, 0x00000000 },
+	{ 0x418aec,   1, 0x04, 0x00010000 },
+	{ 0x418af0,   3, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_tpc[] = {
+	{ 0x419818,   1, 0x04, 0x00000000 },
+	{ 0x41983c,   1, 0x04, 0x00038bc7 },
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x0000012a },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419b00,   1, 0x04, 0x0a418820 },
+	{ 0x419b04,   1, 0x04, 0x062080e6 },
+	{ 0x419b08,   1, 0x04, 0x020398a4 },
+	{ 0x419b0c,   1, 0x04, 0x0e629062 },
+	{ 0x419b10,   1, 0x04, 0x0a418820 },
+	{ 0x419b14,   1, 0x04, 0x000000e6 },
+	{ 0x419bd0,   1, 0x04, 0x00900103 },
+	{ 0x419be0,   1, 0x04, 0x00000001 },
+	{ 0x419be4,   1, 0x04, 0x00000000 },
+	{ 0x419c00,   1, 0x04, 0x00000002 },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x00060048 },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000183 },
+	{ 0x419d20,   1, 0x04, 0x02180000 },
+	{ 0x419d24,   1, 0x04, 0x00001fff },
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419f50,   2, 0x04, 0x00000000 },
+	{}
+};
+
 void
-nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data)
+nvc0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
-	nv_wr32(priv, 0x400204, data);
-	nv_wr32(priv, 0x400200, icmd);
-	while (nv_rd32(priv, 0x400700) & 2) {}
+	int gpc, tpc;
+	u32 offset;
+
+	mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+
+	mmio_list(0x408004, 0x00000000,  8, 0);
+	mmio_list(0x408008, 0x80000018,  0, 0);
+	mmio_list(0x40800c, 0x00000000,  8, 1);
+	mmio_list(0x408010, 0x80000000,  0, 0);
+	mmio_list(0x418810, 0x80000000, 12, 2);
+	mmio_list(0x419848, 0x10000000, 12, 2);
+	mmio_list(0x419004, 0x00000000,  8, 1);
+	mmio_list(0x419008, 0x00000000,  0, 0);
+	mmio_list(0x418808, 0x00000000,  8, 0);
+	mmio_list(0x41880c, 0x80000018,  0, 0);
+
+	mmio_list(0x405830, 0x02180000, 0, 0);
+
+	for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			u32 addr = TPC_UNIT(gpc, tpc, 0x0520);
+			mmio_list(addr, 0x02180000 | offset, 0, 0);
+			offset += 0x0324;
+		}
+	}
+}
+
+void
+nvc0_grctx_generate_unkn(struct nvc0_graph_priv *priv)
+{
+}
+
+void
+nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *priv)
+{
+	int gpc, tpc, id;
+
+	for (tpc = 0, id = 0; tpc < 4; tpc++) {
+		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+			if (tpc < priv->tpc_nr[gpc]) {
+				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
+				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
+				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
+				id++;
+			}
+
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
+		}
+	}
+}
+
+void
+nvc0_grctx_generate_r406028(struct nvc0_graph_priv *priv)
+{
+	u32 tmp[GPC_MAX / 8] = {}, i = 0;
+	for (i = 0; i < priv->gpc_nr; i++)
+		tmp[i / 8] |= priv->tpc_nr[i] << ((i % 8) * 4);
+	for (i = 0; i < 4; i++) {
+		nv_wr32(priv, 0x406028 + (i * 4), tmp[i]);
+		nv_wr32(priv, 0x405870 + (i * 4), tmp[i]);
+	}
+}
+
+void
+nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *priv)
+{
+	u8  tpcnr[GPC_MAX], data[TPC_MAX];
+	int gpc, tpc, i;
+
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	memset(data, 0x1f, sizeof(data));
+
+	gpc = -1;
+	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpcnr[gpc]--;
+		data[tpc] = gpc;
+	}
+
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
+}
+
+void
+nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *priv)
+{
+	u32 data[6] = {}, data2[2] = {};
+	u8  tpcnr[GPC_MAX];
+	u8  shift, ntpcv;
+	int gpc, tpc, i;
+
+	/* calculate first set of magics */
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+	gpc = -1;
+	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpcnr[gpc]--;
+
+		data[tpc / 6] |= gpc << ((tpc % 6) * 5);
+	}
+
+	for (; tpc < 32; tpc++)
+		data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+
+	/* and the second... */
+	shift = 0;
+	ntpcv = priv->tpc_total;
+	while (!(ntpcv & (1 << 4))) {
+		ntpcv <<= 1;
+		shift++;
+	}
+
+	data2[0]  = (ntpcv << 16);
+	data2[0] |= (shift << 21);
+	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+	for (i = 1; i < 7; i++)
+		data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+	/* GPC_BROADCAST */
+	nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
+
+	/* GPC_BROADCAST.TP_BROADCAST */
+	nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr | data2[0]);
+	nv_wr32(priv, 0x419be4, data2[1]);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
+
+	/* UNK78xx */
+	nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x40780c + (i * 4), data[i]);
+}
+
+void
+nvc0_grctx_generate_r406800(struct nvc0_graph_priv *priv)
+{
+	u64 tpc_mask = 0, tpc_set = 0;
+	u8  tpcnr[GPC_MAX];
+	int gpc, tpc;
+	int i, a, b;
+
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++)
+		tpc_mask |= ((1ULL << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
+
+	for (i = 0, gpc = -1, b = -1; i < 32; i++) {
+		a = (i * (priv->tpc_total - 1)) / 32;
+		if (a != b) {
+			b = a;
+			do {
+				gpc = (gpc + 1) % priv->gpc_nr;
+			} while (!tpcnr[gpc]);
+			tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+			tpc_set |= 1 << ((gpc * 8) + tpc);
+		}
+
+		nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set));
+		nv_wr32(priv, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask));
+		if (priv->gpc_nr > 4) {
+			nv_wr32(priv, 0x406804 + (i * 0x20), upper_32_bits(tpc_set));
+			nv_wr32(priv, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask));
+		}
+	}
+}
+
+void
+nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+	int i;
+
+	nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+
+	for (i = 0; oclass->hub[i]; i++)
+		nvc0_graph_mmio(priv, oclass->hub[i]);
+	for (i = 0; oclass->gpc[i]; i++)
+		nvc0_graph_mmio(priv, oclass->gpc[i]);
+
+	nv_wr32(priv, 0x404154, 0x00000000);
+
+	oclass->mods(priv, info);
+	oclass->unkn(priv);
+
+	nvc0_grctx_generate_tpcid(priv);
+	nvc0_grctx_generate_r406028(priv);
+	nvc0_grctx_generate_r4060a8(priv);
+	nvc0_grctx_generate_r418bb8(priv);
+	nvc0_grctx_generate_r406800(priv);
+
+	nvc0_graph_icmd(priv, oclass->icmd);
+	nv_wr32(priv, 0x404154, 0x00000400);
+	nvc0_graph_mthd(priv, oclass->mthd);
+	nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
 }
 
 int
-nvc0_grctx_init(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+nvc0_grctx_generate(struct nvc0_graph_priv *priv)
 {
+	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
 	struct nouveau_bar *bar = nouveau_bar(priv);
 	struct nouveau_gpuobj *chan;
-	u32 size = (0x80000 + priv->size + 4095) & ~4095;
+	struct nvc0_grctx info;
 	int ret, i;
 
 	/* allocate memory to for a "channel", which we'll use to generate
 	 * the default context values
 	 */
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, size, 0x1000,
-				 NVOBJ_FLAG_ZERO_ALLOC, &info->chan);
-	chan = info->chan;
+	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x80000 + priv->size,
+				 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan);
 	if (ret) {
 		nv_error(priv, "failed to allocate channel memory, %d\n", ret);
 		return ret;
@@ -62,7 +1111,7 @@
 	nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8);
 
 	/* identity-map the whole "channel" into its own vm */
-	for (i = 0; i < size / 4096; i++) {
+	for (i = 0; i < chan->size / 4096; i++) {
 		u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1;
 		nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr));
 		nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr));
@@ -79,12 +1128,13 @@
 	nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
 
 	/* setup default state for mmio list construction */
-	info->data = priv->mmio_data;
-	info->mmio = priv->mmio_list;
-	info->addr = 0x2000 + (i * 8);
-	info->priv = priv;
-	info->buffer_nr = 0;
+	info.priv = priv;
+	info.data = priv->mmio_data;
+	info.mmio = priv->mmio_list;
+	info.addr = 0x2000 + (i * 8);
+	info.buffer_nr = 0;
 
+	/* make channel current */
 	if (priv->firmware) {
 		nv_wr32(priv, 0x409840, 0x00000030);
 		nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
@@ -97,58 +1147,15 @@
 		nv_wo32(chan, 0x80028, 0);
 		nv_wo32(chan, 0x8002c, 0);
 		bar->flush(bar);
-		return 0;
+	} else {
+		nv_wr32(priv, 0x409840, 0x80000000);
+		nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
+		nv_wr32(priv, 0x409504, 0x00000001);
+		if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000))
+			nv_error(priv, "HUB_SET_CHAN timeout\n");
 	}
 
-	/* HUB_FUC(SET_CHAN) */
-	nv_wr32(priv, 0x409840, 0x80000000);
-	nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
-	nv_wr32(priv, 0x409504, 0x00000001);
-	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
-		nv_error(priv, "HUB_SET_CHAN timeout\n");
-		nvc0_graph_ctxctl_debug(priv);
-		nouveau_gpuobj_ref(NULL, &info->chan);
-		return -EBUSY;
-	}
-
-	return 0;
-}
-
-void
-nvc0_grctx_data(struct nvc0_grctx *info, u32 size, u32 align, u32 access)
-{
-	info->buffer[info->buffer_nr]  = info->addr;
-	info->buffer[info->buffer_nr] +=  (align - 1);
-	info->buffer[info->buffer_nr] &= ~(align - 1);
-	info->addr = info->buffer[info->buffer_nr++] + size;
-
-	info->data->size = size;
-	info->data->align = align;
-	info->data->access = access;
-	info->data++;
-}
-
-void
-nvc0_grctx_mmio(struct nvc0_grctx *info, u32 addr, u32 data, u32 shift, u32 buf)
-{
-	struct nvc0_graph_priv *priv = info->priv;
-
-	info->mmio->addr = addr;
-	info->mmio->data = data;
-	info->mmio->shift = shift;
-	info->mmio->buffer = buf;
-	info->mmio++;
-
-	if (shift)
-		data |= info->buffer[buf] >> shift;
-	nv_wr32(priv, addr, data);
-}
-
-int
-nvc0_grctx_fini(struct nvc0_grctx *info)
-{
-	struct nvc0_graph_priv *priv = info->priv;
-	int i;
+	oclass->main(priv, &info);
 
 	/* trigger a context unload by unsetting the "next channel valid" bit
 	 * and faking a context switch interrupt
@@ -157,2882 +1164,80 @@
 	nv_wr32(priv, 0x409000, 0x00000100);
 	if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) {
 		nv_error(priv, "grctx template channel unload timeout\n");
-		return -EBUSY;
+		ret = -EBUSY;
+		goto done;
 	}
 
 	priv->data = kmalloc(priv->size, GFP_KERNEL);
 	if (priv->data) {
 		for (i = 0; i < priv->size; i += 4)
-			priv->data[i / 4] = nv_ro32(info->chan, 0x80000 + i);
-	}
-
-	nouveau_gpuobj_ref(NULL, &info->chan);
-	return priv->data ? 0 : -ENOMEM;
-}
-
-static void
-nvc0_grctx_generate_9097(struct nvc0_graph_priv *priv)
-{
-	u32 fermi = nvc0_graph_class(priv);
-	u32 mthd;
-
-	nv_mthd(priv, 0x9097, 0x0800, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0840, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0880, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x08c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0900, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0940, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0980, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x09c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0804, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0844, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0884, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x08c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0904, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0944, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0984, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x09c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0808, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x0848, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x0888, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x08c8, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x0908, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x0948, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x0988, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x09c8, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x080c, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x084c, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x088c, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x08cc, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x090c, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x094c, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x098c, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x09cc, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x0810, 0x000000cf);
-	nv_mthd(priv, 0x9097, 0x0850, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0890, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x08d0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0910, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0950, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0990, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x09d0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0814, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x0854, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x0894, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x08d4, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x0914, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x0954, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x0994, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x09d4, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x0818, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0858, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0898, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x08d8, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0918, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0958, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0998, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x09d8, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x081c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x085c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x089c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x08dc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x091c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x095c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x099c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x09dc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0820, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0860, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x08a0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x08e0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0920, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0960, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x09a0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x09e0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2700, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2720, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2740, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2760, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2780, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27a0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27e0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2704, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2724, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2744, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2764, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2784, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27a4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27e4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2708, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2728, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2748, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2768, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2788, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27a8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27c8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27e8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x270c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x272c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x274c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x276c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x278c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27ac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27cc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x27ec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2710, 0x00014000);
-	nv_mthd(priv, 0x9097, 0x2730, 0x00014000);
-	nv_mthd(priv, 0x9097, 0x2750, 0x00014000);
-	nv_mthd(priv, 0x9097, 0x2770, 0x00014000);
-	nv_mthd(priv, 0x9097, 0x2790, 0x00014000);
-	nv_mthd(priv, 0x9097, 0x27b0, 0x00014000);
-	nv_mthd(priv, 0x9097, 0x27d0, 0x00014000);
-	nv_mthd(priv, 0x9097, 0x27f0, 0x00014000);
-	nv_mthd(priv, 0x9097, 0x2714, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x2734, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x2754, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x2774, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x2794, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x27b4, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x27d4, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x27f4, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x1c00, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c10, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c20, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c30, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c40, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c50, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c60, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c70, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c80, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ca0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cb0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cc0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cd0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ce0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cf0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c04, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c14, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c24, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c34, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c44, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c54, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c64, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c74, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c84, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c94, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ca4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cb4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cc4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cd4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ce4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cf4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c08, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c18, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c28, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c38, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c48, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c58, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c68, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c78, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c88, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c98, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ca8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cb8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cc8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cd8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ce8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cf8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c0c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c1c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c2c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c3c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c4c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c5c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c6c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c7c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c8c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1c9c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cbc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ccc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cdc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1cfc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d00, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d10, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d20, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d30, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d40, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d50, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d60, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d70, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d80, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1da0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1db0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dc0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dd0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1de0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1df0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d04, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d14, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d24, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d34, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d44, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d54, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d64, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d74, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d84, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d94, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1da4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1db4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dc4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dd4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1de4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1df4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d08, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d18, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d28, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d38, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d48, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d58, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d68, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d78, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d88, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d98, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1da8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1db8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dc8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dd8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1de8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1df8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d0c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d1c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d2c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d3c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d4c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d5c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d6c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d7c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d8c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1d9c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dbc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dcc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ddc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1dfc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f00, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f08, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f10, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f18, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f20, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f28, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f30, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f38, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f40, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f48, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f50, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f58, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f60, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f68, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f70, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f78, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f04, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f0c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f14, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f1c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f24, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f2c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f34, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f3c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f44, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f4c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f54, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f5c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f64, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f6c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f74, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f7c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f80, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f88, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f98, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fa0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fa8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fb0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fb8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fc0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fc8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fd0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fd8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fe0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fe8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ff0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ff8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f84, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f8c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f94, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1f9c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fa4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fb4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fbc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fc4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fcc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fd4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fdc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fe4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1fec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ff4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1ffc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2200, 0x00000022);
-	nv_mthd(priv, 0x9097, 0x2210, 0x00000022);
-	nv_mthd(priv, 0x9097, 0x2220, 0x00000022);
-	nv_mthd(priv, 0x9097, 0x2230, 0x00000022);
-	nv_mthd(priv, 0x9097, 0x2240, 0x00000022);
-	nv_mthd(priv, 0x9097, 0x2000, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2040, 0x00000011);
-	nv_mthd(priv, 0x9097, 0x2080, 0x00000020);
-	nv_mthd(priv, 0x9097, 0x20c0, 0x00000030);
-	nv_mthd(priv, 0x9097, 0x2100, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x2140, 0x00000051);
-	nv_mthd(priv, 0x9097, 0x200c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x204c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x208c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x20cc, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x210c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x214c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x2010, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2050, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2090, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x20d0, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x2110, 0x00000003);
-	nv_mthd(priv, 0x9097, 0x2150, 0x00000004);
-	nv_mthd(priv, 0x9097, 0x0380, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03a0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03e0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0384, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03a4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03e4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0388, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03a8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03c8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03e8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x038c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03ac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03cc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x03ec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0700, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0710, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0720, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0730, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0704, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0714, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0724, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0734, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0708, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0718, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0728, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0738, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2800, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2804, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2808, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x280c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2810, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2814, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2818, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x281c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2820, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2824, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2828, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x282c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2830, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2834, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2838, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x283c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2840, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2844, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2848, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x284c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2850, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2854, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2858, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x285c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2860, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2864, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2868, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x286c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2870, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2874, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2878, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x287c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2880, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2884, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2888, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x288c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2890, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2894, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2898, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x289c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28a0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28a4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28a8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28ac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28b0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28b4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28b8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28bc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28c8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28cc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28d0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28d4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28d8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28dc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28e0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28e4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28e8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28ec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28f0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28f4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28f8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x28fc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2900, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2904, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2908, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x290c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2910, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2914, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2918, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x291c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2920, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2924, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2928, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x292c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2930, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2934, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2938, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x293c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2940, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2944, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2948, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x294c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2950, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2954, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2958, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x295c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2960, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2964, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2968, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x296c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2970, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2974, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2978, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x297c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2980, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2984, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2988, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x298c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2990, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2994, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2998, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x299c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29a0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29a4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29a8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29ac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29b0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29b4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29b8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29bc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29c8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29cc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29d0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29d4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29d8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29dc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29e0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29e4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29e8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29ec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29f0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29f4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29f8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x29fc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a00, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a20, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a40, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a60, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a80, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0aa0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ac0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ae0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b00, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b20, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b40, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b60, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b80, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ba0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bc0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0be0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a04, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a24, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a44, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a64, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a84, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0aa4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ac4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ae4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b04, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b24, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b44, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b64, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b84, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ba4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bc4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0be4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a08, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a28, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a48, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a68, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a88, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0aa8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ac8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ae8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b08, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b28, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b48, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b68, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b88, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ba8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bc8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0be8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a0c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a2c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a4c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a6c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a8c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0aac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0acc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0aec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b0c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b2c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b4c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b6c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b8c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bcc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a10, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a30, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a50, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a70, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ab0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ad0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0af0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b10, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b30, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b50, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b70, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bb0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bd0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bf0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a14, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a34, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a54, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a74, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0a94, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ab4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ad4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0af4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b14, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b34, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b54, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b74, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0b94, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bb4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bd4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0bf4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c00, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c10, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c20, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c30, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c40, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c50, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c60, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c70, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c80, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ca0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cb0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cc0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cd0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ce0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cf0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c04, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c14, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c24, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c34, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c44, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c54, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c64, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c74, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c84, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c94, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ca4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cb4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cc4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cd4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ce4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cf4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c08, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c18, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c28, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c38, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c48, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c58, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c68, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c78, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c88, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c98, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ca8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cb8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cc8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cd8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ce8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0cf8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0c0c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c1c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c2c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c3c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c4c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c5c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c6c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c7c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c8c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0c9c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0cac, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0cbc, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0ccc, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0cdc, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0cec, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0cfc, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0d00, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d08, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d10, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d18, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d20, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d28, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d30, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d38, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d04, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d0c, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d14, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d1c, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d24, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d2c, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d34, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d3c, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e00, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e10, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e20, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e30, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e40, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e50, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e60, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e70, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e80, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ea0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0eb0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ec0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ed0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ee0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ef0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0e04, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e14, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e24, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e34, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e44, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e54, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e64, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e74, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e84, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e94, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ea4, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0eb4, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ec4, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ed4, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ee4, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ef4, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e08, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e18, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e28, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e38, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e48, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e58, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e68, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e78, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e88, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0e98, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ea8, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0eb8, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ec8, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ed8, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ee8, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0ef8, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d40, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d48, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d50, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d58, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d44, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d4c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d54, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d5c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1e00, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e20, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e40, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e60, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e80, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ea0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ec0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ee0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e04, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e24, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e44, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e64, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e84, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ea4, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ec4, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ee4, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e08, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e28, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e48, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e68, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e88, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1ea8, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1ec8, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1ee8, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e0c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e2c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e4c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e6c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e8c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1eac, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ecc, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1eec, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e10, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e30, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e50, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e70, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e90, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1eb0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ed0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ef0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e14, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e34, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e54, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e74, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e94, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1eb4, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1ed4, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1ef4, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1e18, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e38, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e58, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e78, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1e98, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1eb8, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ed8, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1ef8, 0x00000001);
-	if (fermi == 0x9097) {
-		for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4)
-			nv_mthd(priv, 0x9097, mthd, 0x00000000);
-	}
-	nv_mthd(priv, 0x9097, 0x030c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1944, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1514, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d68, 0x0000ffff);
-	nv_mthd(priv, 0x9097, 0x121c, 0x0fac6881);
-	nv_mthd(priv, 0x9097, 0x0fac, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1538, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0fe0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0fe4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0fe8, 0x00000014);
-	nv_mthd(priv, 0x9097, 0x0fec, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x0ff0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x179c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1228, 0x00000400);
-	nv_mthd(priv, 0x9097, 0x122c, 0x00000300);
-	nv_mthd(priv, 0x9097, 0x1230, 0x00010001);
-	nv_mthd(priv, 0x9097, 0x07f8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x15b4, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x15cc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1534, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0fb0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x15d0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x153c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x16b4, 0x00000003);
-	nv_mthd(priv, 0x9097, 0x0fbc, 0x0000ffff);
-	nv_mthd(priv, 0x9097, 0x0fc0, 0x0000ffff);
-	nv_mthd(priv, 0x9097, 0x0fc4, 0x0000ffff);
-	nv_mthd(priv, 0x9097, 0x0fc8, 0x0000ffff);
-	nv_mthd(priv, 0x9097, 0x0df8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0dfc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1948, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1970, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x161c, 0x000009f0);
-	nv_mthd(priv, 0x9097, 0x0dcc, 0x00000010);
-	nv_mthd(priv, 0x9097, 0x163c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x15e4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1160, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1164, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1168, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x116c, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1170, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1174, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1178, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x117c, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1180, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1184, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1188, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x118c, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1190, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1194, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1198, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x119c, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11a0, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11a4, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11a8, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11ac, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11b0, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11b4, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11b8, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11bc, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11c0, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11c4, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11c8, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11cc, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11d0, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11d4, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11d8, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x11dc, 0x25e00040);
-	nv_mthd(priv, 0x9097, 0x1880, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1884, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1888, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x188c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1890, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1894, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1898, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x189c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18a0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18a4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18a8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18ac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18b0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18b4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18b8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18bc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18c8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18cc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18d0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18d4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18d8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18dc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18e0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18e4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18e8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18ec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18f0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18f4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18f8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x18fc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0f84, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0f88, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x17c8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x17cc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x17d0, 0x000000ff);
-	nv_mthd(priv, 0x9097, 0x17d4, 0xffffffff);
-	nv_mthd(priv, 0x9097, 0x17d8, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x17dc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x15f4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x15f8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1434, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1438, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d74, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0dec, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x13a4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1318, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1644, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0748, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0de8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1648, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x12a4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1120, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1124, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1128, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x112c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1118, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x164c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1658, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1910, 0x00000290);
-	nv_mthd(priv, 0x9097, 0x1518, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x165c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1520, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1604, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1570, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x13b0, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x13b4, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x020c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1670, 0x30201000);
-	nv_mthd(priv, 0x9097, 0x1674, 0x70605040);
-	nv_mthd(priv, 0x9097, 0x1678, 0xb8a89888);
-	nv_mthd(priv, 0x9097, 0x167c, 0xf8e8d8c8);
-	nv_mthd(priv, 0x9097, 0x166c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1680, 0x00ffff00);
-	nv_mthd(priv, 0x9097, 0x12d0, 0x00000003);
-	nv_mthd(priv, 0x9097, 0x12d4, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1684, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1688, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0dac, 0x00001b02);
-	nv_mthd(priv, 0x9097, 0x0db0, 0x00001b02);
-	nv_mthd(priv, 0x9097, 0x0db4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x168c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x15bc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x156c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x187c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1110, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0dc0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0dc4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0dc8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1234, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1690, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x12ac, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x02c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0790, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0794, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0798, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x079c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x07a0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x077c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1000, 0x00000010);
-	nv_mthd(priv, 0x9097, 0x10fc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1290, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0218, 0x00000010);
-	nv_mthd(priv, 0x9097, 0x12d8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x12dc, 0x00000010);
-	nv_mthd(priv, 0x9097, 0x0d94, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x155c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1560, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1564, 0x00001fff);
-	nv_mthd(priv, 0x9097, 0x1574, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1578, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x157c, 0x003fffff);
-	nv_mthd(priv, 0x9097, 0x1354, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1664, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1610, 0x00000012);
-	nv_mthd(priv, 0x9097, 0x1608, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x160c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x162c, 0x00000003);
-	nv_mthd(priv, 0x9097, 0x0210, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0320, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0324, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0328, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x032c, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0330, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0334, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0338, 0x3f800000);
-	nv_mthd(priv, 0x9097, 0x0750, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0760, 0x39291909);
-	nv_mthd(priv, 0x9097, 0x0764, 0x79695949);
-	nv_mthd(priv, 0x9097, 0x0768, 0xb9a99989);
-	nv_mthd(priv, 0x9097, 0x076c, 0xf9e9d9c9);
-	nv_mthd(priv, 0x9097, 0x0770, 0x30201000);
-	nv_mthd(priv, 0x9097, 0x0774, 0x70605040);
-	nv_mthd(priv, 0x9097, 0x0778, 0x00009080);
-	nv_mthd(priv, 0x9097, 0x0780, 0x39291909);
-	nv_mthd(priv, 0x9097, 0x0784, 0x79695949);
-	nv_mthd(priv, 0x9097, 0x0788, 0xb9a99989);
-	nv_mthd(priv, 0x9097, 0x078c, 0xf9e9d9c9);
-	nv_mthd(priv, 0x9097, 0x07d0, 0x30201000);
-	nv_mthd(priv, 0x9097, 0x07d4, 0x70605040);
-	nv_mthd(priv, 0x9097, 0x07d8, 0x00009080);
-	nv_mthd(priv, 0x9097, 0x037c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0740, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0744, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x2600, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1918, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x191c, 0x00000900);
-	nv_mthd(priv, 0x9097, 0x1920, 0x00000405);
-	nv_mthd(priv, 0x9097, 0x1308, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1924, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x13ac, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x192c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x193c, 0x00002c1c);
-	nv_mthd(priv, 0x9097, 0x0d7c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0f8c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x02c0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1510, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1940, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ff4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0ff8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x194c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1950, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1968, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1590, 0x0000003f);
-	nv_mthd(priv, 0x9097, 0x07e8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x07ec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x07f0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x07f4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x196c, 0x00000011);
-	nv_mthd(priv, 0x9097, 0x197c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0fcc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0fd0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x02d8, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x1980, 0x00000080);
-	nv_mthd(priv, 0x9097, 0x1504, 0x00000080);
-	nv_mthd(priv, 0x9097, 0x1984, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0300, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x13a8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x12ec, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1310, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1314, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1380, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1384, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1388, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x138c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1390, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1394, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x139c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1398, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1594, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1598, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x159c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x15a0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x15a4, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x0f54, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0f58, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0f5c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x19bc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0f9c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0fa0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x12cc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x12e8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x130c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1360, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1364, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1368, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x136c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1370, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1374, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1378, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x137c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x133c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1340, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1344, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1348, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x134c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1350, 0x00000002);
-	nv_mthd(priv, 0x9097, 0x1358, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x12e4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x131c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1320, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1324, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1328, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x19c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1140, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x19c4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x19c8, 0x00001500);
-	nv_mthd(priv, 0x9097, 0x135c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0f90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x19e0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x19e4, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x19e8, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x19ec, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x19f0, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x19f4, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x19f8, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x19fc, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x19cc, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x15b8, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1a00, 0x00001111);
-	nv_mthd(priv, 0x9097, 0x1a04, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1a08, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1a0c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1a10, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1a14, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1a18, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1a1c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d6c, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x0d70, 0xffff0000);
-	nv_mthd(priv, 0x9097, 0x10f8, 0x00001010);
-	nv_mthd(priv, 0x9097, 0x0d80, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d84, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d88, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d8c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0d90, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0da0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1508, 0x80000000);
-	nv_mthd(priv, 0x9097, 0x150c, 0x40000000);
-	nv_mthd(priv, 0x9097, 0x1668, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0318, 0x00000008);
-	nv_mthd(priv, 0x9097, 0x031c, 0x00000008);
-	nv_mthd(priv, 0x9097, 0x0d9c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x07dc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x074c, 0x00000055);
-	nv_mthd(priv, 0x9097, 0x1420, 0x00000003);
-	nv_mthd(priv, 0x9097, 0x17bc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x17c0, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x17c4, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1008, 0x00000008);
-	nv_mthd(priv, 0x9097, 0x100c, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x1010, 0x0000012c);
-	nv_mthd(priv, 0x9097, 0x0d60, 0x00000040);
-	nv_mthd(priv, 0x9097, 0x075c, 0x00000003);
-	nv_mthd(priv, 0x9097, 0x1018, 0x00000020);
-	nv_mthd(priv, 0x9097, 0x101c, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1020, 0x00000020);
-	nv_mthd(priv, 0x9097, 0x1024, 0x00000001);
-	nv_mthd(priv, 0x9097, 0x1444, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x1448, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x144c, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0360, 0x20164010);
-	nv_mthd(priv, 0x9097, 0x0364, 0x00000020);
-	nv_mthd(priv, 0x9097, 0x0368, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0de4, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0204, 0x00000006);
-	nv_mthd(priv, 0x9097, 0x0208, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x02cc, 0x003fffff);
-	nv_mthd(priv, 0x9097, 0x02d0, 0x00000c48);
-	nv_mthd(priv, 0x9097, 0x1220, 0x00000005);
-	nv_mthd(priv, 0x9097, 0x0fdc, 0x00000000);
-	nv_mthd(priv, 0x9097, 0x0f98, 0x00300008);
-	nv_mthd(priv, 0x9097, 0x1284, 0x04000080);
-	nv_mthd(priv, 0x9097, 0x1450, 0x00300008);
-	nv_mthd(priv, 0x9097, 0x1454, 0x04000080);
-	nv_mthd(priv, 0x9097, 0x0214, 0x00000000);
-	/* in trace, right after 0x90c0, not here */
-	nv_mthd(priv, 0x9097, 0x3410, 0x80002006);
-}
-
-static void
-nvc0_grctx_generate_9197(struct nvc0_graph_priv *priv)
-{
-	u32 fermi = nvc0_graph_class(priv);
-	u32 mthd;
-
-	if (fermi == 0x9197) {
-		for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4)
-			nv_mthd(priv, 0x9197, mthd, 0x00000000);
-	}
-	nv_mthd(priv, 0x9197, 0x02e4, 0x0000b001);
-}
-
-static void
-nvc0_grctx_generate_9297(struct nvc0_graph_priv *priv)
-{
-	u32 fermi = nvc0_graph_class(priv);
-	u32 mthd;
-
-	if (fermi == 0x9297) {
-		for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4)
-			nv_mthd(priv, 0x9297, mthd, 0x00000000);
-	}
-	nv_mthd(priv, 0x9297, 0x036c, 0x00000000);
-	nv_mthd(priv, 0x9297, 0x0370, 0x00000000);
-	nv_mthd(priv, 0x9297, 0x07a4, 0x00000000);
-	nv_mthd(priv, 0x9297, 0x07a8, 0x00000000);
-	nv_mthd(priv, 0x9297, 0x0374, 0x00000000);
-	nv_mthd(priv, 0x9297, 0x0378, 0x00000020);
-}
-
-static void
-nvc0_grctx_generate_902d(struct nvc0_graph_priv *priv)
-{
-	nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
-	nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
-	nv_mthd(priv, 0x902d, 0x0208, 0x00000020);
-	nv_mthd(priv, 0x902d, 0x020c, 0x00000001);
-	nv_mthd(priv, 0x902d, 0x0210, 0x00000000);
-	nv_mthd(priv, 0x902d, 0x0214, 0x00000080);
-	nv_mthd(priv, 0x902d, 0x0218, 0x00000100);
-	nv_mthd(priv, 0x902d, 0x021c, 0x00000100);
-	nv_mthd(priv, 0x902d, 0x0220, 0x00000000);
-	nv_mthd(priv, 0x902d, 0x0224, 0x00000000);
-	nv_mthd(priv, 0x902d, 0x0230, 0x000000cf);
-	nv_mthd(priv, 0x902d, 0x0234, 0x00000001);
-	nv_mthd(priv, 0x902d, 0x0238, 0x00000020);
-	nv_mthd(priv, 0x902d, 0x023c, 0x00000001);
-	nv_mthd(priv, 0x902d, 0x0244, 0x00000080);
-	nv_mthd(priv, 0x902d, 0x0248, 0x00000100);
-	nv_mthd(priv, 0x902d, 0x024c, 0x00000100);
-}
-
-static void
-nvc0_grctx_generate_9039(struct nvc0_graph_priv *priv)
-{
-	nv_mthd(priv, 0x9039, 0x030c, 0x00000000);
-	nv_mthd(priv, 0x9039, 0x0310, 0x00000000);
-	nv_mthd(priv, 0x9039, 0x0314, 0x00000000);
-	nv_mthd(priv, 0x9039, 0x0320, 0x00000000);
-	nv_mthd(priv, 0x9039, 0x0238, 0x00000000);
-	nv_mthd(priv, 0x9039, 0x023c, 0x00000000);
-	nv_mthd(priv, 0x9039, 0x0318, 0x00000000);
-	nv_mthd(priv, 0x9039, 0x031c, 0x00000000);
-}
-
-static void
-nvc0_grctx_generate_90c0(struct nvc0_graph_priv *priv)
-{
-	int i;
-
-	for (i = 0; nv_device(priv)->chipset >= 0xd0 && i < 4; i++) {
-		nv_mthd(priv, 0x90c0, 0x2700 + (i * 0x40), 0x00000000);
-		nv_mthd(priv, 0x90c0, 0x2720 + (i * 0x40), 0x00000000);
-		nv_mthd(priv, 0x90c0, 0x2704 + (i * 0x40), 0x00000000);
-		nv_mthd(priv, 0x90c0, 0x2724 + (i * 0x40), 0x00000000);
-		nv_mthd(priv, 0x90c0, 0x2708 + (i * 0x40), 0x00000000);
-		nv_mthd(priv, 0x90c0, 0x2728 + (i * 0x40), 0x00000000);
-	}
-	nv_mthd(priv, 0x90c0, 0x270c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x272c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x274c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x276c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x278c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x27ac, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x27cc, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x27ec, 0x00000000);
-	for (i = 0; nv_device(priv)->chipset >= 0xd0 && i < 4; i++) {
-		nv_mthd(priv, 0x90c0, 0x2710 + (i * 0x40), 0x00014000);
-		nv_mthd(priv, 0x90c0, 0x2730 + (i * 0x40), 0x00014000);
-		nv_mthd(priv, 0x90c0, 0x2714 + (i * 0x40), 0x00000040);
-		nv_mthd(priv, 0x90c0, 0x2734 + (i * 0x40), 0x00000040);
-	}
-	nv_mthd(priv, 0x90c0, 0x030c, 0x00000001);
-	nv_mthd(priv, 0x90c0, 0x1944, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x0758, 0x00000100);
-	nv_mthd(priv, 0x90c0, 0x02c4, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x0790, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x0794, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x0798, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x079c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x07a0, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x077c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x0204, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x0208, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x020c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x0214, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x024c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x0d94, 0x00000001);
-	nv_mthd(priv, 0x90c0, 0x1608, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x160c, 0x00000000);
-	nv_mthd(priv, 0x90c0, 0x1664, 0x00000000);
-}
-
-static void
-nvc0_grctx_generate_dispatch(struct nvc0_graph_priv *priv)
-{
-	int i;
-
-	nv_wr32(priv, 0x404004, 0x00000000);
-	nv_wr32(priv, 0x404008, 0x00000000);
-	nv_wr32(priv, 0x40400c, 0x00000000);
-	nv_wr32(priv, 0x404010, 0x00000000);
-	nv_wr32(priv, 0x404014, 0x00000000);
-	nv_wr32(priv, 0x404018, 0x00000000);
-	nv_wr32(priv, 0x40401c, 0x00000000);
-	nv_wr32(priv, 0x404020, 0x00000000);
-	nv_wr32(priv, 0x404024, 0x00000000);
-	nv_wr32(priv, 0x404028, 0x00000000);
-	nv_wr32(priv, 0x40402c, 0x00000000);
-	nv_wr32(priv, 0x404044, 0x00000000);
-	nv_wr32(priv, 0x404094, 0x00000000);
-	nv_wr32(priv, 0x404098, 0x00000000);
-	nv_wr32(priv, 0x40409c, 0x00000000);
-	nv_wr32(priv, 0x4040a0, 0x00000000);
-	nv_wr32(priv, 0x4040a4, 0x00000000);
-	nv_wr32(priv, 0x4040a8, 0x00000000);
-	nv_wr32(priv, 0x4040ac, 0x00000000);
-	nv_wr32(priv, 0x4040b0, 0x00000000);
-	nv_wr32(priv, 0x4040b4, 0x00000000);
-	nv_wr32(priv, 0x4040b8, 0x00000000);
-	nv_wr32(priv, 0x4040bc, 0x00000000);
-	nv_wr32(priv, 0x4040c0, 0x00000000);
-	nv_wr32(priv, 0x4040c4, 0x00000000);
-	nv_wr32(priv, 0x4040c8, 0xf0000087);
-	nv_wr32(priv, 0x4040d4, 0x00000000);
-	nv_wr32(priv, 0x4040d8, 0x00000000);
-	nv_wr32(priv, 0x4040dc, 0x00000000);
-	nv_wr32(priv, 0x4040e0, 0x00000000);
-	nv_wr32(priv, 0x4040e4, 0x00000000);
-	nv_wr32(priv, 0x4040e8, 0x00001000);
-	nv_wr32(priv, 0x4040f8, 0x00000000);
-	nv_wr32(priv, 0x404130, 0x00000000);
-	nv_wr32(priv, 0x404134, 0x00000000);
-	nv_wr32(priv, 0x404138, 0x20000040);
-	nv_wr32(priv, 0x404150, 0x0000002e);
-	nv_wr32(priv, 0x404154, 0x00000400);
-	nv_wr32(priv, 0x404158, 0x00000200);
-	nv_wr32(priv, 0x404164, 0x00000055);
-	nv_wr32(priv, 0x404168, 0x00000000);
-	nv_wr32(priv, 0x404174, 0x00000000);
-	nv_wr32(priv, 0x404178, 0x00000000);
-	nv_wr32(priv, 0x40417c, 0x00000000);
-	for (i = 0; i < 8; i++)
-		nv_wr32(priv, 0x404200 + (i * 4), 0x00000000); /* subc */
-}
-
-static void
-nvc0_grctx_generate_macro(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x404404, 0x00000000);
-	nv_wr32(priv, 0x404408, 0x00000000);
-	nv_wr32(priv, 0x40440c, 0x00000000);
-	nv_wr32(priv, 0x404410, 0x00000000);
-	nv_wr32(priv, 0x404414, 0x00000000);
-	nv_wr32(priv, 0x404418, 0x00000000);
-	nv_wr32(priv, 0x40441c, 0x00000000);
-	nv_wr32(priv, 0x404420, 0x00000000);
-	nv_wr32(priv, 0x404424, 0x00000000);
-	nv_wr32(priv, 0x404428, 0x00000000);
-	nv_wr32(priv, 0x40442c, 0x00000000);
-	nv_wr32(priv, 0x404430, 0x00000000);
-	nv_wr32(priv, 0x404434, 0x00000000);
-	nv_wr32(priv, 0x404438, 0x00000000);
-	nv_wr32(priv, 0x404460, 0x00000000);
-	nv_wr32(priv, 0x404464, 0x00000000);
-	nv_wr32(priv, 0x404468, 0x00ffffff);
-	nv_wr32(priv, 0x40446c, 0x00000000);
-	nv_wr32(priv, 0x404480, 0x00000001);
-	nv_wr32(priv, 0x404498, 0x00000001);
-}
-
-static void
-nvc0_grctx_generate_m2mf(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x404604, 0x00000015);
-	nv_wr32(priv, 0x404608, 0x00000000);
-	nv_wr32(priv, 0x40460c, 0x00002e00);
-	nv_wr32(priv, 0x404610, 0x00000100);
-	nv_wr32(priv, 0x404618, 0x00000000);
-	nv_wr32(priv, 0x40461c, 0x00000000);
-	nv_wr32(priv, 0x404620, 0x00000000);
-	nv_wr32(priv, 0x404624, 0x00000000);
-	nv_wr32(priv, 0x404628, 0x00000000);
-	nv_wr32(priv, 0x40462c, 0x00000000);
-	nv_wr32(priv, 0x404630, 0x00000000);
-	nv_wr32(priv, 0x404634, 0x00000000);
-	nv_wr32(priv, 0x404638, 0x00000004);
-	nv_wr32(priv, 0x40463c, 0x00000000);
-	nv_wr32(priv, 0x404640, 0x00000000);
-	nv_wr32(priv, 0x404644, 0x00000000);
-	nv_wr32(priv, 0x404648, 0x00000000);
-	nv_wr32(priv, 0x40464c, 0x00000000);
-	nv_wr32(priv, 0x404650, 0x00000000);
-	nv_wr32(priv, 0x404654, 0x00000000);
-	nv_wr32(priv, 0x404658, 0x00000000);
-	nv_wr32(priv, 0x40465c, 0x007f0100);
-	nv_wr32(priv, 0x404660, 0x00000000);
-	nv_wr32(priv, 0x404664, 0x00000000);
-	nv_wr32(priv, 0x404668, 0x00000000);
-	nv_wr32(priv, 0x40466c, 0x00000000);
-	nv_wr32(priv, 0x404670, 0x00000000);
-	nv_wr32(priv, 0x404674, 0x00000000);
-	nv_wr32(priv, 0x404678, 0x00000000);
-	nv_wr32(priv, 0x40467c, 0x00000002);
-	nv_wr32(priv, 0x404680, 0x00000000);
-	nv_wr32(priv, 0x404684, 0x00000000);
-	nv_wr32(priv, 0x404688, 0x00000000);
-	nv_wr32(priv, 0x40468c, 0x00000000);
-	nv_wr32(priv, 0x404690, 0x00000000);
-	nv_wr32(priv, 0x404694, 0x00000000);
-	nv_wr32(priv, 0x404698, 0x00000000);
-	nv_wr32(priv, 0x40469c, 0x00000000);
-	nv_wr32(priv, 0x4046a0, 0x007f0080);
-	nv_wr32(priv, 0x4046a4, 0x00000000);
-	nv_wr32(priv, 0x4046a8, 0x00000000);
-	nv_wr32(priv, 0x4046ac, 0x00000000);
-	nv_wr32(priv, 0x4046b0, 0x00000000);
-	nv_wr32(priv, 0x4046b4, 0x00000000);
-	nv_wr32(priv, 0x4046b8, 0x00000000);
-	nv_wr32(priv, 0x4046bc, 0x00000000);
-	nv_wr32(priv, 0x4046c0, 0x00000000);
-	nv_wr32(priv, 0x4046c4, 0x00000000);
-	nv_wr32(priv, 0x4046c8, 0x00000000);
-	nv_wr32(priv, 0x4046cc, 0x00000000);
-	nv_wr32(priv, 0x4046d0, 0x00000000);
-	nv_wr32(priv, 0x4046d4, 0x00000000);
-	nv_wr32(priv, 0x4046d8, 0x00000000);
-	nv_wr32(priv, 0x4046dc, 0x00000000);
-	nv_wr32(priv, 0x4046e0, 0x00000000);
-	nv_wr32(priv, 0x4046e4, 0x00000000);
-	nv_wr32(priv, 0x4046e8, 0x00000000);
-	nv_wr32(priv, 0x4046f0, 0x00000000);
-	nv_wr32(priv, 0x4046f4, 0x00000000);
-}
-
-static void
-nvc0_grctx_generate_unk47xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x404700, 0x00000000);
-	nv_wr32(priv, 0x404704, 0x00000000);
-	nv_wr32(priv, 0x404708, 0x00000000);
-	nv_wr32(priv, 0x40470c, 0x00000000);
-	nv_wr32(priv, 0x404710, 0x00000000);
-	nv_wr32(priv, 0x404714, 0x00000000);
-	nv_wr32(priv, 0x404718, 0x00000000);
-	nv_wr32(priv, 0x40471c, 0x00000000);
-	nv_wr32(priv, 0x404720, 0x00000000);
-	nv_wr32(priv, 0x404724, 0x00000000);
-	nv_wr32(priv, 0x404728, 0x00000000);
-	nv_wr32(priv, 0x40472c, 0x00000000);
-	nv_wr32(priv, 0x404730, 0x00000000);
-	nv_wr32(priv, 0x404734, 0x00000100);
-	nv_wr32(priv, 0x404738, 0x00000000);
-	nv_wr32(priv, 0x40473c, 0x00000000);
-	nv_wr32(priv, 0x404740, 0x00000000);
-	nv_wr32(priv, 0x404744, 0x00000000);
-	nv_wr32(priv, 0x404748, 0x00000000);
-	nv_wr32(priv, 0x40474c, 0x00000000);
-	nv_wr32(priv, 0x404750, 0x00000000);
-	nv_wr32(priv, 0x404754, 0x00000000);
-}
-
-static void
-nvc0_grctx_generate_shaders(struct nvc0_graph_priv *priv)
-{
-
-	if (nv_device(priv)->chipset >= 0xd0) {
-		nv_wr32(priv, 0x405800, 0x0f8000bf);
-		nv_wr32(priv, 0x405830, 0x02180218);
-		nv_wr32(priv, 0x405834, 0x08000000);
-	} else
-	if (nv_device(priv)->chipset == 0xc1) {
-		nv_wr32(priv, 0x405800, 0x0f8000bf);
-		nv_wr32(priv, 0x405830, 0x02180218);
-		nv_wr32(priv, 0x405834, 0x00000000);
+			priv->data[i / 4] = nv_ro32(chan, 0x80000 + i);
+		ret = 0;
 	} else {
-		nv_wr32(priv, 0x405800, 0x078000bf);
-		nv_wr32(priv, 0x405830, 0x02180000);
-		nv_wr32(priv, 0x405834, 0x00000000);
+		ret = -ENOMEM;
 	}
-	nv_wr32(priv, 0x405838, 0x00000000);
-	nv_wr32(priv, 0x405854, 0x00000000);
-	nv_wr32(priv, 0x405870, 0x00000001);
-	nv_wr32(priv, 0x405874, 0x00000001);
-	nv_wr32(priv, 0x405878, 0x00000001);
-	nv_wr32(priv, 0x40587c, 0x00000001);
-	nv_wr32(priv, 0x405a00, 0x00000000);
-	nv_wr32(priv, 0x405a04, 0x00000000);
-	nv_wr32(priv, 0x405a18, 0x00000000);
+
+done:
+	nouveau_gpuobj_ref(NULL, &chan);
+	return ret;
 }
 
-static void
-nvc0_grctx_generate_unk60xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x406020, 0x000103c1);
-	nv_wr32(priv, 0x406028, 0x00000001);
-	nv_wr32(priv, 0x40602c, 0x00000001);
-	nv_wr32(priv, 0x406030, 0x00000001);
-	nv_wr32(priv, 0x406034, 0x00000001);
-}
+struct nvc0_graph_init *
+nvc0_grctx_init_hub[] = {
+	nvc0_grctx_init_base,
+	nvc0_grctx_init_unk40xx,
+	nvc0_grctx_init_unk44xx,
+	nvc0_grctx_init_unk46xx,
+	nvc0_grctx_init_unk47xx,
+	nvc0_grctx_init_unk58xx,
+	nvc0_grctx_init_unk60xx,
+	nvc0_grctx_init_unk64xx,
+	nvc0_grctx_init_unk78xx,
+	nvc0_grctx_init_unk80xx,
+	nvc0_grctx_init_rop,
+	NULL
+};
 
-static void
-nvc0_grctx_generate_unk64xx(struct nvc0_graph_priv *priv)
-{
+static struct nvc0_graph_init *
+nvc0_grctx_init_gpc[] = {
+	nvc0_grctx_init_gpc_0,
+	nvc0_grctx_init_gpc_1,
+	nvc0_grctx_init_tpc,
+	NULL
+};
 
-	nv_wr32(priv, 0x4064a8, 0x00000000);
-	nv_wr32(priv, 0x4064ac, 0x00003fff);
-	nv_wr32(priv, 0x4064b4, 0x00000000);
-	nv_wr32(priv, 0x4064b8, 0x00000000);
-	if (nv_device(priv)->chipset >= 0xd0)
-		nv_wr32(priv, 0x4064bc, 0x00000000);
-	if (nv_device(priv)->chipset == 0xc1 ||
-	    nv_device(priv)->chipset >= 0xd0) {
-		nv_wr32(priv, 0x4064c0, 0x80140078);
-		nv_wr32(priv, 0x4064c4, 0x0086ffff);
-	}
-}
+struct nvc0_graph_init
+nvc0_grctx_init_mthd_magic[] = {
+	{ 0x3410, 1, 0x04, 0x00000000 },
+	{}
+};
 
-static void
-nvc0_grctx_generate_tpbus(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x407804, 0x00000023);
-	nv_wr32(priv, 0x40780c, 0x0a418820);
-	nv_wr32(priv, 0x407810, 0x062080e6);
-	nv_wr32(priv, 0x407814, 0x020398a4);
-	nv_wr32(priv, 0x407818, 0x0e629062);
-	nv_wr32(priv, 0x40781c, 0x0a418820);
-	nv_wr32(priv, 0x407820, 0x000000e6);
-	nv_wr32(priv, 0x4078bc, 0x00000103);
-}
+struct nvc0_graph_mthd
+nvc0_grctx_init_mthd[] = {
+	{ 0x9097, nvc0_grctx_init_9097, },
+	{ 0x902d, nvc0_grctx_init_902d, },
+	{ 0x9039, nvc0_grctx_init_9039, },
+	{ 0x90c0, nvc0_grctx_init_90c0, },
+	{ 0x902d, nvc0_grctx_init_mthd_magic, },
+	{}
+};
 
-static void
-nvc0_grctx_generate_ccache(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x408000, 0x00000000);
-	nv_wr32(priv, 0x408004, 0x00000000);
-	nv_wr32(priv, 0x408008, 0x00000018);
-	nv_wr32(priv, 0x40800c, 0x00000000);
-	nv_wr32(priv, 0x408010, 0x00000000);
-	nv_wr32(priv, 0x408014, 0x00000069);
-	nv_wr32(priv, 0x408018, 0xe100e100);
-	nv_wr32(priv, 0x408064, 0x00000000);
-}
-
-static void
-nvc0_grctx_generate_rop(struct nvc0_graph_priv *priv)
-{
-	int chipset = nv_device(priv)->chipset;
-
-	/* ROPC_BROADCAST */
-	nv_wr32(priv, 0x408800, 0x02802a3c);
-	nv_wr32(priv, 0x408804, 0x00000040);
-	if (chipset >= 0xd0) {
-		nv_wr32(priv, 0x408808, 0x1043e005);
-		nv_wr32(priv, 0x408900, 0x3080b801);
-		nv_wr32(priv, 0x408904, 0x1043e005);
-		nv_wr32(priv, 0x408908, 0x00c8102f);
-	} else
-	if (chipset == 0xc1) {
-		nv_wr32(priv, 0x408808, 0x1003e005);
-		nv_wr32(priv, 0x408900, 0x3080b801);
-		nv_wr32(priv, 0x408904, 0x62000001);
-		nv_wr32(priv, 0x408908, 0x00c80929);
-	} else {
-		nv_wr32(priv, 0x408808, 0x0003e00d);
-		nv_wr32(priv, 0x408900, 0x3080b801);
-		nv_wr32(priv, 0x408904, 0x02000001);
-		nv_wr32(priv, 0x408908, 0x00c80929);
-	}
-	nv_wr32(priv, 0x40890c, 0x00000000);
-	nv_wr32(priv, 0x408980, 0x0000011d);
-}
-
-static void
-nvc0_grctx_generate_gpc(struct nvc0_graph_priv *priv)
-{
-	int chipset = nv_device(priv)->chipset;
-	int i;
-
-	/* GPC_BROADCAST */
-	nv_wr32(priv, 0x418380, 0x00000016);
-	nv_wr32(priv, 0x418400, 0x38004e00);
-	nv_wr32(priv, 0x418404, 0x71e0ffff);
-	nv_wr32(priv, 0x418408, 0x00000000);
-	nv_wr32(priv, 0x41840c, 0x00001008);
-	nv_wr32(priv, 0x418410, 0x0fff0fff);
-	nv_wr32(priv, 0x418414, chipset < 0xd0 ? 0x00200fff : 0x02200fff);
-	nv_wr32(priv, 0x418450, 0x00000000);
-	nv_wr32(priv, 0x418454, 0x00000000);
-	nv_wr32(priv, 0x418458, 0x00000000);
-	nv_wr32(priv, 0x41845c, 0x00000000);
-	nv_wr32(priv, 0x418460, 0x00000000);
-	nv_wr32(priv, 0x418464, 0x00000000);
-	nv_wr32(priv, 0x418468, 0x00000001);
-	nv_wr32(priv, 0x41846c, 0x00000000);
-	nv_wr32(priv, 0x418470, 0x00000000);
-	nv_wr32(priv, 0x418600, 0x0000001f);
-	nv_wr32(priv, 0x418684, 0x0000000f);
-	nv_wr32(priv, 0x418700, 0x00000002);
-	nv_wr32(priv, 0x418704, 0x00000080);
-	nv_wr32(priv, 0x418708, 0x00000000);
-	nv_wr32(priv, 0x41870c, chipset < 0xd0 ? 0x07c80000 : 0x00000000);
-	nv_wr32(priv, 0x418710, 0x00000000);
-	nv_wr32(priv, 0x418800, chipset < 0xd0 ? 0x0006860a : 0x7006860a);
-	nv_wr32(priv, 0x418808, 0x00000000);
-	nv_wr32(priv, 0x41880c, 0x00000000);
-	nv_wr32(priv, 0x418810, 0x00000000);
-	nv_wr32(priv, 0x418828, 0x00008442);
-	if (chipset == 0xc1 || chipset >= 0xd0)
-		nv_wr32(priv, 0x418830, 0x10000001);
-	else
-		nv_wr32(priv, 0x418830, 0x00000001);
-	nv_wr32(priv, 0x4188d8, 0x00000008);
-	nv_wr32(priv, 0x4188e0, 0x01000000);
-	nv_wr32(priv, 0x4188e8, 0x00000000);
-	nv_wr32(priv, 0x4188ec, 0x00000000);
-	nv_wr32(priv, 0x4188f0, 0x00000000);
-	nv_wr32(priv, 0x4188f4, 0x00000000);
-	nv_wr32(priv, 0x4188f8, 0x00000000);
-	if (chipset >= 0xd0)
-		nv_wr32(priv, 0x4188fc, 0x20100008);
-	else if (chipset == 0xc1)
-		nv_wr32(priv, 0x4188fc, 0x00100018);
-	else
-		nv_wr32(priv, 0x4188fc, 0x00100000);
-	nv_wr32(priv, 0x41891c, 0x00ff00ff);
-	nv_wr32(priv, 0x418924, 0x00000000);
-	nv_wr32(priv, 0x418928, 0x00ffff00);
-	nv_wr32(priv, 0x41892c, 0x0000ff00);
-	for (i = 0; i < 8; i++) {
-		nv_wr32(priv, 0x418a00 + (i * 0x20), 0x00000000);
-		nv_wr32(priv, 0x418a04 + (i * 0x20), 0x00000000);
-		nv_wr32(priv, 0x418a08 + (i * 0x20), 0x00000000);
-		nv_wr32(priv, 0x418a0c + (i * 0x20), 0x00010000);
-		nv_wr32(priv, 0x418a10 + (i * 0x20), 0x00000000);
-		nv_wr32(priv, 0x418a14 + (i * 0x20), 0x00000000);
-		nv_wr32(priv, 0x418a18 + (i * 0x20), 0x00000000);
-	}
-	nv_wr32(priv, 0x418b00, chipset < 0xd0 ? 0x00000000 : 0x00000006);
-	nv_wr32(priv, 0x418b08, 0x0a418820);
-	nv_wr32(priv, 0x418b0c, 0x062080e6);
-	nv_wr32(priv, 0x418b10, 0x020398a4);
-	nv_wr32(priv, 0x418b14, 0x0e629062);
-	nv_wr32(priv, 0x418b18, 0x0a418820);
-	nv_wr32(priv, 0x418b1c, 0x000000e6);
-	nv_wr32(priv, 0x418bb8, 0x00000103);
-	nv_wr32(priv, 0x418c08, 0x00000001);
-	nv_wr32(priv, 0x418c10, 0x00000000);
-	nv_wr32(priv, 0x418c14, 0x00000000);
-	nv_wr32(priv, 0x418c18, 0x00000000);
-	nv_wr32(priv, 0x418c1c, 0x00000000);
-	nv_wr32(priv, 0x418c20, 0x00000000);
-	nv_wr32(priv, 0x418c24, 0x00000000);
-	nv_wr32(priv, 0x418c28, 0x00000000);
-	nv_wr32(priv, 0x418c2c, 0x00000000);
-	if (chipset == 0xc1 || chipset >= 0xd0)
-		nv_wr32(priv, 0x418c6c, 0x00000001);
-	nv_wr32(priv, 0x418c80, 0x20200004);
-	nv_wr32(priv, 0x418c8c, 0x00000001);
-	nv_wr32(priv, 0x419000, 0x00000780);
-	nv_wr32(priv, 0x419004, 0x00000000);
-	nv_wr32(priv, 0x419008, 0x00000000);
-	nv_wr32(priv, 0x419014, 0x00000004);
-}
-
-static void
-nvc0_grctx_generate_tp(struct nvc0_graph_priv *priv)
-{
-	int chipset = nv_device(priv)->chipset;
-
-	/* GPC_BROADCAST.TP_BROADCAST */
-	nv_wr32(priv, 0x419818, 0x00000000);
-	nv_wr32(priv, 0x41983c, 0x00038bc7);
-	nv_wr32(priv, 0x419848, 0x00000000);
-	if (chipset == 0xc1 || chipset >= 0xd0)
-		nv_wr32(priv, 0x419864, 0x00000129);
-	else
-		nv_wr32(priv, 0x419864, 0x0000012a);
-	nv_wr32(priv, 0x419888, 0x00000000);
-	nv_wr32(priv, 0x419a00, 0x000001f0);
-	nv_wr32(priv, 0x419a04, 0x00000001);
-	nv_wr32(priv, 0x419a08, 0x00000023);
-	nv_wr32(priv, 0x419a0c, 0x00020000);
-	nv_wr32(priv, 0x419a10, 0x00000000);
-	nv_wr32(priv, 0x419a14, 0x00000200);
-	nv_wr32(priv, 0x419a1c, 0x00000000);
-	nv_wr32(priv, 0x419a20, 0x00000800);
-	if (chipset >= 0xd0)
-		nv_wr32(priv, 0x00419ac4, 0x0017f440);
-	else if (chipset != 0xc0 && chipset != 0xc8)
-		nv_wr32(priv, 0x00419ac4, 0x0007f440);
-	nv_wr32(priv, 0x419b00, 0x0a418820);
-	nv_wr32(priv, 0x419b04, 0x062080e6);
-	nv_wr32(priv, 0x419b08, 0x020398a4);
-	nv_wr32(priv, 0x419b0c, 0x0e629062);
-	nv_wr32(priv, 0x419b10, 0x0a418820);
-	nv_wr32(priv, 0x419b14, 0x000000e6);
-	nv_wr32(priv, 0x419bd0, 0x00900103);
-	if (chipset == 0xc1 || chipset >= 0xd0)
-		nv_wr32(priv, 0x419be0, 0x00400001);
-	else
-		nv_wr32(priv, 0x419be0, 0x00000001);
-	nv_wr32(priv, 0x419be4, 0x00000000);
-	nv_wr32(priv, 0x419c00, chipset < 0xd0 ? 0x00000002 : 0x0000000a);
-	nv_wr32(priv, 0x419c04, 0x00000006);
-	nv_wr32(priv, 0x419c08, 0x00000002);
-	nv_wr32(priv, 0x419c20, 0x00000000);
-	if (nv_device(priv)->chipset >= 0xd0) {
-		nv_wr32(priv, 0x419c24, 0x00084210);
-		nv_wr32(priv, 0x419c28, 0x3cf3cf3c);
-		nv_wr32(priv, 0x419cb0, 0x00020048);
-	} else
-	if (chipset == 0xce || chipset == 0xcf) {
-		nv_wr32(priv, 0x419cb0, 0x00020048);
-	} else {
-		nv_wr32(priv, 0x419cb0, 0x00060048);
-	}
-	nv_wr32(priv, 0x419ce8, 0x00000000);
-	nv_wr32(priv, 0x419cf4, 0x00000183);
-	if (chipset == 0xc1 || chipset >= 0xd0)
-		nv_wr32(priv, 0x419d20, 0x12180000);
-	else
-		nv_wr32(priv, 0x419d20, 0x02180000);
-	nv_wr32(priv, 0x419d24, 0x00001fff);
-	if (chipset == 0xc1 || chipset >= 0xd0)
-		nv_wr32(priv, 0x419d44, 0x02180218);
-	nv_wr32(priv, 0x419e04, 0x00000000);
-	nv_wr32(priv, 0x419e08, 0x00000000);
-	nv_wr32(priv, 0x419e0c, 0x00000000);
-	nv_wr32(priv, 0x419e10, 0x00000002);
-	nv_wr32(priv, 0x419e44, 0x001beff2);
-	nv_wr32(priv, 0x419e48, 0x00000000);
-	nv_wr32(priv, 0x419e4c, 0x0000000f);
-	nv_wr32(priv, 0x419e50, 0x00000000);
-	nv_wr32(priv, 0x419e54, 0x00000000);
-	nv_wr32(priv, 0x419e58, 0x00000000);
-	nv_wr32(priv, 0x419e5c, 0x00000000);
-	nv_wr32(priv, 0x419e60, 0x00000000);
-	nv_wr32(priv, 0x419e64, 0x00000000);
-	nv_wr32(priv, 0x419e68, 0x00000000);
-	nv_wr32(priv, 0x419e6c, 0x00000000);
-	nv_wr32(priv, 0x419e70, 0x00000000);
-	nv_wr32(priv, 0x419e74, 0x00000000);
-	nv_wr32(priv, 0x419e78, 0x00000000);
-	nv_wr32(priv, 0x419e7c, 0x00000000);
-	nv_wr32(priv, 0x419e80, 0x00000000);
-	nv_wr32(priv, 0x419e84, 0x00000000);
-	nv_wr32(priv, 0x419e88, 0x00000000);
-	nv_wr32(priv, 0x419e8c, 0x00000000);
-	nv_wr32(priv, 0x419e90, 0x00000000);
-	nv_wr32(priv, 0x419e98, 0x00000000);
-	if (chipset != 0xc0 && chipset != 0xc8)
-		nv_wr32(priv, 0x419ee0, 0x00011110);
-	nv_wr32(priv, 0x419f50, 0x00000000);
-	nv_wr32(priv, 0x419f54, 0x00000000);
-	if (chipset != 0xc0 && chipset != 0xc8)
-		nv_wr32(priv, 0x419f58, 0x00000000);
-}
-
-int
-nvc0_grctx_generate(struct nvc0_graph_priv *priv)
-{
-	struct nvc0_grctx info;
-	int ret, i, gpc, tpc, id;
-	u32 fermi = nvc0_graph_class(priv);
-	u32 r000260, tmp;
-
-	ret = nvc0_grctx_init(priv, &info);
-	if (ret)
-		return ret;
-
-	r000260 = nv_rd32(priv, 0x000260);
-	nv_wr32(priv, 0x000260, r000260 & ~1);
-	nv_wr32(priv, 0x400208, 0x00000000);
-
-	nvc0_grctx_generate_dispatch(priv);
-	nvc0_grctx_generate_macro(priv);
-	nvc0_grctx_generate_m2mf(priv);
-	nvc0_grctx_generate_unk47xx(priv);
-	nvc0_grctx_generate_shaders(priv);
-	nvc0_grctx_generate_unk60xx(priv);
-	nvc0_grctx_generate_unk64xx(priv);
-	nvc0_grctx_generate_tpbus(priv);
-	nvc0_grctx_generate_ccache(priv);
-	nvc0_grctx_generate_rop(priv);
-	nvc0_grctx_generate_gpc(priv);
-	nvc0_grctx_generate_tp(priv);
-
-	nv_wr32(priv, 0x404154, 0x00000000);
-
-	/* generate per-context mmio list data */
-	mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
-	mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
-	mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
-	mmio_list(0x408004, 0x00000000,  8, 0);
-	mmio_list(0x408008, 0x80000018,  0, 0);
-	mmio_list(0x40800c, 0x00000000,  8, 1);
-	mmio_list(0x408010, 0x80000000,  0, 0);
-	mmio_list(0x418810, 0x80000000, 12, 2);
-	mmio_list(0x419848, 0x10000000, 12, 2);
-	mmio_list(0x419004, 0x00000000,  8, 1);
-	mmio_list(0x419008, 0x00000000,  0, 0);
-	mmio_list(0x418808, 0x00000000,  8, 0);
-	mmio_list(0x41880c, 0x80000018,  0, 0);
-	if (nv_device(priv)->chipset != 0xc1) {
-		tmp = 0x02180000;
-		mmio_list(0x405830, tmp, 0, 0);
-		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-			for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-				u32 reg = TPC_UNIT(gpc, tpc, 0x0520);
-				mmio_list(reg, tmp, 0, 0);
-				tmp += 0x0324;
-			}
-		}
-	} else {
-		tmp = 0x02180000;
-		mmio_list(0x405830, 0x00000218 | tmp, 0, 0);
-		mmio_list(0x4064c4, 0x0086ffff, 0, 0);
-		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-			for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-				u32 reg = TPC_UNIT(gpc, tpc, 0x0520);
-				mmio_list(reg, 0x10000000 | tmp, 0, 0);
-				tmp += 0x0324;
-			}
-			for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-				u32 reg = TPC_UNIT(gpc, tpc, 0x0544);
-				mmio_list(reg, tmp, 0, 0);
-				tmp += 0x0324;
-			}
-		}
-	}
-
-	for (tpc = 0, id = 0; tpc < 4; tpc++) {
-		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-			if (tpc < priv->tpc_nr[gpc]) {
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
-				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
-				id++;
-			}
-
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
-		}
-	}
-
-	tmp = 0;
-	for (i = 0; i < priv->gpc_nr; i++)
-		tmp |= priv->tpc_nr[i] << (i * 4);
-	nv_wr32(priv, 0x406028, tmp);
-	nv_wr32(priv, 0x405870, tmp);
-
-	nv_wr32(priv, 0x40602c, 0x00000000);
-	nv_wr32(priv, 0x405874, 0x00000000);
-	nv_wr32(priv, 0x406030, 0x00000000);
-	nv_wr32(priv, 0x405878, 0x00000000);
-	nv_wr32(priv, 0x406034, 0x00000000);
-	nv_wr32(priv, 0x40587c, 0x00000000);
-
-	if (1) {
-		u8 tpcnr[GPC_MAX], data[TPC_MAX];
-
-		memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-		memset(data, 0x1f, sizeof(data));
-
-		gpc = -1;
-		for (tpc = 0; tpc < priv->tpc_total; tpc++) {
-			do {
-				gpc = (gpc + 1) % priv->gpc_nr;
-			} while (!tpcnr[gpc]);
-			tpcnr[gpc]--;
-			data[tpc] = gpc;
-		}
-
-		for (i = 0; i < 4; i++)
-			nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
-	}
-
-	if (1) {
-		u32 data[6] = {}, data2[2] = {};
-		u8 tpcnr[GPC_MAX];
-		u8 shift, ntpcv;
-
-		/* calculate first set of magics */
-		memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-
-		gpc = -1;
-		for (tpc = 0; tpc < priv->tpc_total; tpc++) {
-			do {
-				gpc = (gpc + 1) % priv->gpc_nr;
-			} while (!tpcnr[gpc]);
-			tpcnr[gpc]--;
-
-			data[tpc / 6] |= gpc << ((tpc % 6) * 5);
-		}
-
-		for (; tpc < 32; tpc++)
-			data[tpc / 6] |= 7 << ((tpc % 6) * 5);
-
-		/* and the second... */
-		shift = 0;
-		ntpcv = priv->tpc_total;
-		while (!(ntpcv & (1 << 4))) {
-			ntpcv <<= 1;
-			shift++;
-		}
-
-		data2[0]  = (ntpcv << 16);
-		data2[0] |= (shift << 21);
-		data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
-		for (i = 1; i < 7; i++)
-			data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-
-		/* GPC_BROADCAST */
-		nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
-					priv->magic_not_rop_nr);
-		for (i = 0; i < 6; i++)
-			nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
-
-		/* GPC_BROADCAST.TP_BROADCAST */
-		nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
-				       priv->magic_not_rop_nr |
-				       data2[0]);
-		nv_wr32(priv, 0x419be4, data2[1]);
-		for (i = 0; i < 6; i++)
-			nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
-
-		/* UNK78xx */
-		nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
-					priv->magic_not_rop_nr);
-		for (i = 0; i < 6; i++)
-			nv_wr32(priv, 0x40780c + (i * 4), data[i]);
-	}
-
-	if (1) {
-		u32 tpc_mask = 0, tpc_set = 0;
-		u8  tpcnr[GPC_MAX], a, b;
-
-		memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-		for (gpc = 0; gpc < priv->gpc_nr; gpc++)
-			tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
-
-		for (i = 0, gpc = -1, b = -1; i < 32; i++) {
-			a = (i * (priv->tpc_total - 1)) / 32;
-			if (a != b) {
-				b = a;
-				do {
-					gpc = (gpc + 1) % priv->gpc_nr;
-				} while (!tpcnr[gpc]);
-				tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-				tpc_set |= 1 << ((gpc * 8) + tpc);
-			}
-
-			nv_wr32(priv, 0x406800 + (i * 0x20), tpc_set);
-			nv_wr32(priv, 0x406c00 + (i * 0x20), tpc_set ^ tpc_mask);
-		}
-	}
-
-	nv_wr32(priv, 0x400208, 0x80000000);
-
-	nv_icmd(priv, 0x00001000, 0x00000004);
-	nv_icmd(priv, 0x000000a9, 0x0000ffff);
-	nv_icmd(priv, 0x00000038, 0x0fac6881);
-	nv_icmd(priv, 0x0000003d, 0x00000001);
-	nv_icmd(priv, 0x000000e8, 0x00000400);
-	nv_icmd(priv, 0x000000e9, 0x00000400);
-	nv_icmd(priv, 0x000000ea, 0x00000400);
-	nv_icmd(priv, 0x000000eb, 0x00000400);
-	nv_icmd(priv, 0x000000ec, 0x00000400);
-	nv_icmd(priv, 0x000000ed, 0x00000400);
-	nv_icmd(priv, 0x000000ee, 0x00000400);
-	nv_icmd(priv, 0x000000ef, 0x00000400);
-	nv_icmd(priv, 0x00000078, 0x00000300);
-	nv_icmd(priv, 0x00000079, 0x00000300);
-	nv_icmd(priv, 0x0000007a, 0x00000300);
-	nv_icmd(priv, 0x0000007b, 0x00000300);
-	nv_icmd(priv, 0x0000007c, 0x00000300);
-	nv_icmd(priv, 0x0000007d, 0x00000300);
-	nv_icmd(priv, 0x0000007e, 0x00000300);
-	nv_icmd(priv, 0x0000007f, 0x00000300);
-	nv_icmd(priv, 0x00000050, 0x00000011);
-	nv_icmd(priv, 0x00000058, 0x00000008);
-	nv_icmd(priv, 0x00000059, 0x00000008);
-	nv_icmd(priv, 0x0000005a, 0x00000008);
-	nv_icmd(priv, 0x0000005b, 0x00000008);
-	nv_icmd(priv, 0x0000005c, 0x00000008);
-	nv_icmd(priv, 0x0000005d, 0x00000008);
-	nv_icmd(priv, 0x0000005e, 0x00000008);
-	nv_icmd(priv, 0x0000005f, 0x00000008);
-	nv_icmd(priv, 0x00000208, 0x00000001);
-	nv_icmd(priv, 0x00000209, 0x00000001);
-	nv_icmd(priv, 0x0000020a, 0x00000001);
-	nv_icmd(priv, 0x0000020b, 0x00000001);
-	nv_icmd(priv, 0x0000020c, 0x00000001);
-	nv_icmd(priv, 0x0000020d, 0x00000001);
-	nv_icmd(priv, 0x0000020e, 0x00000001);
-	nv_icmd(priv, 0x0000020f, 0x00000001);
-	nv_icmd(priv, 0x00000081, 0x00000001);
-	nv_icmd(priv, 0x00000085, 0x00000004);
-	nv_icmd(priv, 0x00000088, 0x00000400);
-	nv_icmd(priv, 0x00000090, 0x00000300);
-	nv_icmd(priv, 0x00000098, 0x00001001);
-	nv_icmd(priv, 0x000000e3, 0x00000001);
-	nv_icmd(priv, 0x000000da, 0x00000001);
-	nv_icmd(priv, 0x000000f8, 0x00000003);
-	nv_icmd(priv, 0x000000fa, 0x00000001);
-	nv_icmd(priv, 0x0000009f, 0x0000ffff);
-	nv_icmd(priv, 0x000000a0, 0x0000ffff);
-	nv_icmd(priv, 0x000000a1, 0x0000ffff);
-	nv_icmd(priv, 0x000000a2, 0x0000ffff);
-	nv_icmd(priv, 0x000000b1, 0x00000001);
-	nv_icmd(priv, 0x000000b2, 0x00000000);
-	nv_icmd(priv, 0x000000b3, 0x00000000);
-	nv_icmd(priv, 0x000000b4, 0x00000000);
-	nv_icmd(priv, 0x000000b5, 0x00000000);
-	nv_icmd(priv, 0x000000b6, 0x00000000);
-	nv_icmd(priv, 0x000000b7, 0x00000000);
-	nv_icmd(priv, 0x000000b8, 0x00000000);
-	nv_icmd(priv, 0x000000b9, 0x00000000);
-	nv_icmd(priv, 0x000000ba, 0x00000000);
-	nv_icmd(priv, 0x000000bb, 0x00000000);
-	nv_icmd(priv, 0x000000bc, 0x00000000);
-	nv_icmd(priv, 0x000000bd, 0x00000000);
-	nv_icmd(priv, 0x000000be, 0x00000000);
-	nv_icmd(priv, 0x000000bf, 0x00000000);
-	nv_icmd(priv, 0x000000c0, 0x00000000);
-	nv_icmd(priv, 0x000000c1, 0x00000000);
-	nv_icmd(priv, 0x000000c2, 0x00000000);
-	nv_icmd(priv, 0x000000c3, 0x00000000);
-	nv_icmd(priv, 0x000000c4, 0x00000000);
-	nv_icmd(priv, 0x000000c5, 0x00000000);
-	nv_icmd(priv, 0x000000c6, 0x00000000);
-	nv_icmd(priv, 0x000000c7, 0x00000000);
-	nv_icmd(priv, 0x000000c8, 0x00000000);
-	nv_icmd(priv, 0x000000c9, 0x00000000);
-	nv_icmd(priv, 0x000000ca, 0x00000000);
-	nv_icmd(priv, 0x000000cb, 0x00000000);
-	nv_icmd(priv, 0x000000cc, 0x00000000);
-	nv_icmd(priv, 0x000000cd, 0x00000000);
-	nv_icmd(priv, 0x000000ce, 0x00000000);
-	nv_icmd(priv, 0x000000cf, 0x00000000);
-	nv_icmd(priv, 0x000000d0, 0x00000000);
-	nv_icmd(priv, 0x000000d1, 0x00000000);
-	nv_icmd(priv, 0x000000d2, 0x00000000);
-	nv_icmd(priv, 0x000000d3, 0x00000000);
-	nv_icmd(priv, 0x000000d4, 0x00000000);
-	nv_icmd(priv, 0x000000d5, 0x00000000);
-	nv_icmd(priv, 0x000000d6, 0x00000000);
-	nv_icmd(priv, 0x000000d7, 0x00000000);
-	nv_icmd(priv, 0x000000d8, 0x00000000);
-	nv_icmd(priv, 0x000000d9, 0x00000000);
-	nv_icmd(priv, 0x00000210, 0x00000040);
-	nv_icmd(priv, 0x00000211, 0x00000040);
-	nv_icmd(priv, 0x00000212, 0x00000040);
-	nv_icmd(priv, 0x00000213, 0x00000040);
-	nv_icmd(priv, 0x00000214, 0x00000040);
-	nv_icmd(priv, 0x00000215, 0x00000040);
-	nv_icmd(priv, 0x00000216, 0x00000040);
-	nv_icmd(priv, 0x00000217, 0x00000040);
-	if (nv_device(priv)->chipset >= 0xd0) {
-		for (i = 0x0400; i <= 0x0417; i++)
-			nv_icmd(priv, i, 0x00000040);
-	}
-	nv_icmd(priv, 0x00000218, 0x0000c080);
-	nv_icmd(priv, 0x00000219, 0x0000c080);
-	nv_icmd(priv, 0x0000021a, 0x0000c080);
-	nv_icmd(priv, 0x0000021b, 0x0000c080);
-	nv_icmd(priv, 0x0000021c, 0x0000c080);
-	nv_icmd(priv, 0x0000021d, 0x0000c080);
-	nv_icmd(priv, 0x0000021e, 0x0000c080);
-	nv_icmd(priv, 0x0000021f, 0x0000c080);
-	if (nv_device(priv)->chipset >= 0xd0) {
-		for (i = 0x0440; i <= 0x0457; i++)
-			nv_icmd(priv, i, 0x0000c080);
-	}
-	nv_icmd(priv, 0x000000ad, 0x0000013e);
-	nv_icmd(priv, 0x000000e1, 0x00000010);
-	nv_icmd(priv, 0x00000290, 0x00000000);
-	nv_icmd(priv, 0x00000291, 0x00000000);
-	nv_icmd(priv, 0x00000292, 0x00000000);
-	nv_icmd(priv, 0x00000293, 0x00000000);
-	nv_icmd(priv, 0x00000294, 0x00000000);
-	nv_icmd(priv, 0x00000295, 0x00000000);
-	nv_icmd(priv, 0x00000296, 0x00000000);
-	nv_icmd(priv, 0x00000297, 0x00000000);
-	nv_icmd(priv, 0x00000298, 0x00000000);
-	nv_icmd(priv, 0x00000299, 0x00000000);
-	nv_icmd(priv, 0x0000029a, 0x00000000);
-	nv_icmd(priv, 0x0000029b, 0x00000000);
-	nv_icmd(priv, 0x0000029c, 0x00000000);
-	nv_icmd(priv, 0x0000029d, 0x00000000);
-	nv_icmd(priv, 0x0000029e, 0x00000000);
-	nv_icmd(priv, 0x0000029f, 0x00000000);
-	nv_icmd(priv, 0x000003b0, 0x00000000);
-	nv_icmd(priv, 0x000003b1, 0x00000000);
-	nv_icmd(priv, 0x000003b2, 0x00000000);
-	nv_icmd(priv, 0x000003b3, 0x00000000);
-	nv_icmd(priv, 0x000003b4, 0x00000000);
-	nv_icmd(priv, 0x000003b5, 0x00000000);
-	nv_icmd(priv, 0x000003b6, 0x00000000);
-	nv_icmd(priv, 0x000003b7, 0x00000000);
-	nv_icmd(priv, 0x000003b8, 0x00000000);
-	nv_icmd(priv, 0x000003b9, 0x00000000);
-	nv_icmd(priv, 0x000003ba, 0x00000000);
-	nv_icmd(priv, 0x000003bb, 0x00000000);
-	nv_icmd(priv, 0x000003bc, 0x00000000);
-	nv_icmd(priv, 0x000003bd, 0x00000000);
-	nv_icmd(priv, 0x000003be, 0x00000000);
-	nv_icmd(priv, 0x000003bf, 0x00000000);
-	nv_icmd(priv, 0x000002a0, 0x00000000);
-	nv_icmd(priv, 0x000002a1, 0x00000000);
-	nv_icmd(priv, 0x000002a2, 0x00000000);
-	nv_icmd(priv, 0x000002a3, 0x00000000);
-	nv_icmd(priv, 0x000002a4, 0x00000000);
-	nv_icmd(priv, 0x000002a5, 0x00000000);
-	nv_icmd(priv, 0x000002a6, 0x00000000);
-	nv_icmd(priv, 0x000002a7, 0x00000000);
-	nv_icmd(priv, 0x000002a8, 0x00000000);
-	nv_icmd(priv, 0x000002a9, 0x00000000);
-	nv_icmd(priv, 0x000002aa, 0x00000000);
-	nv_icmd(priv, 0x000002ab, 0x00000000);
-	nv_icmd(priv, 0x000002ac, 0x00000000);
-	nv_icmd(priv, 0x000002ad, 0x00000000);
-	nv_icmd(priv, 0x000002ae, 0x00000000);
-	nv_icmd(priv, 0x000002af, 0x00000000);
-	nv_icmd(priv, 0x00000420, 0x00000000);
-	nv_icmd(priv, 0x00000421, 0x00000000);
-	nv_icmd(priv, 0x00000422, 0x00000000);
-	nv_icmd(priv, 0x00000423, 0x00000000);
-	nv_icmd(priv, 0x00000424, 0x00000000);
-	nv_icmd(priv, 0x00000425, 0x00000000);
-	nv_icmd(priv, 0x00000426, 0x00000000);
-	nv_icmd(priv, 0x00000427, 0x00000000);
-	nv_icmd(priv, 0x00000428, 0x00000000);
-	nv_icmd(priv, 0x00000429, 0x00000000);
-	nv_icmd(priv, 0x0000042a, 0x00000000);
-	nv_icmd(priv, 0x0000042b, 0x00000000);
-	nv_icmd(priv, 0x0000042c, 0x00000000);
-	nv_icmd(priv, 0x0000042d, 0x00000000);
-	nv_icmd(priv, 0x0000042e, 0x00000000);
-	nv_icmd(priv, 0x0000042f, 0x00000000);
-	nv_icmd(priv, 0x000002b0, 0x00000000);
-	nv_icmd(priv, 0x000002b1, 0x00000000);
-	nv_icmd(priv, 0x000002b2, 0x00000000);
-	nv_icmd(priv, 0x000002b3, 0x00000000);
-	nv_icmd(priv, 0x000002b4, 0x00000000);
-	nv_icmd(priv, 0x000002b5, 0x00000000);
-	nv_icmd(priv, 0x000002b6, 0x00000000);
-	nv_icmd(priv, 0x000002b7, 0x00000000);
-	nv_icmd(priv, 0x000002b8, 0x00000000);
-	nv_icmd(priv, 0x000002b9, 0x00000000);
-	nv_icmd(priv, 0x000002ba, 0x00000000);
-	nv_icmd(priv, 0x000002bb, 0x00000000);
-	nv_icmd(priv, 0x000002bc, 0x00000000);
-	nv_icmd(priv, 0x000002bd, 0x00000000);
-	nv_icmd(priv, 0x000002be, 0x00000000);
-	nv_icmd(priv, 0x000002bf, 0x00000000);
-	nv_icmd(priv, 0x00000430, 0x00000000);
-	nv_icmd(priv, 0x00000431, 0x00000000);
-	nv_icmd(priv, 0x00000432, 0x00000000);
-	nv_icmd(priv, 0x00000433, 0x00000000);
-	nv_icmd(priv, 0x00000434, 0x00000000);
-	nv_icmd(priv, 0x00000435, 0x00000000);
-	nv_icmd(priv, 0x00000436, 0x00000000);
-	nv_icmd(priv, 0x00000437, 0x00000000);
-	nv_icmd(priv, 0x00000438, 0x00000000);
-	nv_icmd(priv, 0x00000439, 0x00000000);
-	nv_icmd(priv, 0x0000043a, 0x00000000);
-	nv_icmd(priv, 0x0000043b, 0x00000000);
-	nv_icmd(priv, 0x0000043c, 0x00000000);
-	nv_icmd(priv, 0x0000043d, 0x00000000);
-	nv_icmd(priv, 0x0000043e, 0x00000000);
-	nv_icmd(priv, 0x0000043f, 0x00000000);
-	nv_icmd(priv, 0x000002c0, 0x00000000);
-	nv_icmd(priv, 0x000002c1, 0x00000000);
-	nv_icmd(priv, 0x000002c2, 0x00000000);
-	nv_icmd(priv, 0x000002c3, 0x00000000);
-	nv_icmd(priv, 0x000002c4, 0x00000000);
-	nv_icmd(priv, 0x000002c5, 0x00000000);
-	nv_icmd(priv, 0x000002c6, 0x00000000);
-	nv_icmd(priv, 0x000002c7, 0x00000000);
-	nv_icmd(priv, 0x000002c8, 0x00000000);
-	nv_icmd(priv, 0x000002c9, 0x00000000);
-	nv_icmd(priv, 0x000002ca, 0x00000000);
-	nv_icmd(priv, 0x000002cb, 0x00000000);
-	nv_icmd(priv, 0x000002cc, 0x00000000);
-	nv_icmd(priv, 0x000002cd, 0x00000000);
-	nv_icmd(priv, 0x000002ce, 0x00000000);
-	nv_icmd(priv, 0x000002cf, 0x00000000);
-	nv_icmd(priv, 0x000004d0, 0x00000000);
-	nv_icmd(priv, 0x000004d1, 0x00000000);
-	nv_icmd(priv, 0x000004d2, 0x00000000);
-	nv_icmd(priv, 0x000004d3, 0x00000000);
-	nv_icmd(priv, 0x000004d4, 0x00000000);
-	nv_icmd(priv, 0x000004d5, 0x00000000);
-	nv_icmd(priv, 0x000004d6, 0x00000000);
-	nv_icmd(priv, 0x000004d7, 0x00000000);
-	nv_icmd(priv, 0x000004d8, 0x00000000);
-	nv_icmd(priv, 0x000004d9, 0x00000000);
-	nv_icmd(priv, 0x000004da, 0x00000000);
-	nv_icmd(priv, 0x000004db, 0x00000000);
-	nv_icmd(priv, 0x000004dc, 0x00000000);
-	nv_icmd(priv, 0x000004dd, 0x00000000);
-	nv_icmd(priv, 0x000004de, 0x00000000);
-	nv_icmd(priv, 0x000004df, 0x00000000);
-	nv_icmd(priv, 0x00000720, 0x00000000);
-	nv_icmd(priv, 0x00000721, 0x00000000);
-	nv_icmd(priv, 0x00000722, 0x00000000);
-	nv_icmd(priv, 0x00000723, 0x00000000);
-	nv_icmd(priv, 0x00000724, 0x00000000);
-	nv_icmd(priv, 0x00000725, 0x00000000);
-	nv_icmd(priv, 0x00000726, 0x00000000);
-	nv_icmd(priv, 0x00000727, 0x00000000);
-	nv_icmd(priv, 0x00000728, 0x00000000);
-	nv_icmd(priv, 0x00000729, 0x00000000);
-	nv_icmd(priv, 0x0000072a, 0x00000000);
-	nv_icmd(priv, 0x0000072b, 0x00000000);
-	nv_icmd(priv, 0x0000072c, 0x00000000);
-	nv_icmd(priv, 0x0000072d, 0x00000000);
-	nv_icmd(priv, 0x0000072e, 0x00000000);
-	nv_icmd(priv, 0x0000072f, 0x00000000);
-	nv_icmd(priv, 0x000008c0, 0x00000000);
-	nv_icmd(priv, 0x000008c1, 0x00000000);
-	nv_icmd(priv, 0x000008c2, 0x00000000);
-	nv_icmd(priv, 0x000008c3, 0x00000000);
-	nv_icmd(priv, 0x000008c4, 0x00000000);
-	nv_icmd(priv, 0x000008c5, 0x00000000);
-	nv_icmd(priv, 0x000008c6, 0x00000000);
-	nv_icmd(priv, 0x000008c7, 0x00000000);
-	nv_icmd(priv, 0x000008c8, 0x00000000);
-	nv_icmd(priv, 0x000008c9, 0x00000000);
-	nv_icmd(priv, 0x000008ca, 0x00000000);
-	nv_icmd(priv, 0x000008cb, 0x00000000);
-	nv_icmd(priv, 0x000008cc, 0x00000000);
-	nv_icmd(priv, 0x000008cd, 0x00000000);
-	nv_icmd(priv, 0x000008ce, 0x00000000);
-	nv_icmd(priv, 0x000008cf, 0x00000000);
-	nv_icmd(priv, 0x00000890, 0x00000000);
-	nv_icmd(priv, 0x00000891, 0x00000000);
-	nv_icmd(priv, 0x00000892, 0x00000000);
-	nv_icmd(priv, 0x00000893, 0x00000000);
-	nv_icmd(priv, 0x00000894, 0x00000000);
-	nv_icmd(priv, 0x00000895, 0x00000000);
-	nv_icmd(priv, 0x00000896, 0x00000000);
-	nv_icmd(priv, 0x00000897, 0x00000000);
-	nv_icmd(priv, 0x00000898, 0x00000000);
-	nv_icmd(priv, 0x00000899, 0x00000000);
-	nv_icmd(priv, 0x0000089a, 0x00000000);
-	nv_icmd(priv, 0x0000089b, 0x00000000);
-	nv_icmd(priv, 0x0000089c, 0x00000000);
-	nv_icmd(priv, 0x0000089d, 0x00000000);
-	nv_icmd(priv, 0x0000089e, 0x00000000);
-	nv_icmd(priv, 0x0000089f, 0x00000000);
-	nv_icmd(priv, 0x000008e0, 0x00000000);
-	nv_icmd(priv, 0x000008e1, 0x00000000);
-	nv_icmd(priv, 0x000008e2, 0x00000000);
-	nv_icmd(priv, 0x000008e3, 0x00000000);
-	nv_icmd(priv, 0x000008e4, 0x00000000);
-	nv_icmd(priv, 0x000008e5, 0x00000000);
-	nv_icmd(priv, 0x000008e6, 0x00000000);
-	nv_icmd(priv, 0x000008e7, 0x00000000);
-	nv_icmd(priv, 0x000008e8, 0x00000000);
-	nv_icmd(priv, 0x000008e9, 0x00000000);
-	nv_icmd(priv, 0x000008ea, 0x00000000);
-	nv_icmd(priv, 0x000008eb, 0x00000000);
-	nv_icmd(priv, 0x000008ec, 0x00000000);
-	nv_icmd(priv, 0x000008ed, 0x00000000);
-	nv_icmd(priv, 0x000008ee, 0x00000000);
-	nv_icmd(priv, 0x000008ef, 0x00000000);
-	nv_icmd(priv, 0x000008a0, 0x00000000);
-	nv_icmd(priv, 0x000008a1, 0x00000000);
-	nv_icmd(priv, 0x000008a2, 0x00000000);
-	nv_icmd(priv, 0x000008a3, 0x00000000);
-	nv_icmd(priv, 0x000008a4, 0x00000000);
-	nv_icmd(priv, 0x000008a5, 0x00000000);
-	nv_icmd(priv, 0x000008a6, 0x00000000);
-	nv_icmd(priv, 0x000008a7, 0x00000000);
-	nv_icmd(priv, 0x000008a8, 0x00000000);
-	nv_icmd(priv, 0x000008a9, 0x00000000);
-	nv_icmd(priv, 0x000008aa, 0x00000000);
-	nv_icmd(priv, 0x000008ab, 0x00000000);
-	nv_icmd(priv, 0x000008ac, 0x00000000);
-	nv_icmd(priv, 0x000008ad, 0x00000000);
-	nv_icmd(priv, 0x000008ae, 0x00000000);
-	nv_icmd(priv, 0x000008af, 0x00000000);
-	nv_icmd(priv, 0x000008f0, 0x00000000);
-	nv_icmd(priv, 0x000008f1, 0x00000000);
-	nv_icmd(priv, 0x000008f2, 0x00000000);
-	nv_icmd(priv, 0x000008f3, 0x00000000);
-	nv_icmd(priv, 0x000008f4, 0x00000000);
-	nv_icmd(priv, 0x000008f5, 0x00000000);
-	nv_icmd(priv, 0x000008f6, 0x00000000);
-	nv_icmd(priv, 0x000008f7, 0x00000000);
-	nv_icmd(priv, 0x000008f8, 0x00000000);
-	nv_icmd(priv, 0x000008f9, 0x00000000);
-	nv_icmd(priv, 0x000008fa, 0x00000000);
-	nv_icmd(priv, 0x000008fb, 0x00000000);
-	nv_icmd(priv, 0x000008fc, 0x00000000);
-	nv_icmd(priv, 0x000008fd, 0x00000000);
-	nv_icmd(priv, 0x000008fe, 0x00000000);
-	nv_icmd(priv, 0x000008ff, 0x00000000);
-	nv_icmd(priv, 0x0000094c, 0x000000ff);
-	nv_icmd(priv, 0x0000094d, 0xffffffff);
-	nv_icmd(priv, 0x0000094e, 0x00000002);
-	nv_icmd(priv, 0x000002ec, 0x00000001);
-	nv_icmd(priv, 0x00000303, 0x00000001);
-	nv_icmd(priv, 0x000002e6, 0x00000001);
-	nv_icmd(priv, 0x00000466, 0x00000052);
-	nv_icmd(priv, 0x00000301, 0x3f800000);
-	nv_icmd(priv, 0x00000304, 0x30201000);
-	nv_icmd(priv, 0x00000305, 0x70605040);
-	nv_icmd(priv, 0x00000306, 0xb8a89888);
-	nv_icmd(priv, 0x00000307, 0xf8e8d8c8);
-	nv_icmd(priv, 0x0000030a, 0x00ffff00);
-	nv_icmd(priv, 0x0000030b, 0x0000001a);
-	nv_icmd(priv, 0x0000030c, 0x00000001);
-	nv_icmd(priv, 0x00000318, 0x00000001);
-	nv_icmd(priv, 0x00000340, 0x00000000);
-	nv_icmd(priv, 0x00000375, 0x00000001);
-	nv_icmd(priv, 0x00000351, 0x00000100);
-	nv_icmd(priv, 0x0000037d, 0x00000006);
-	nv_icmd(priv, 0x000003a0, 0x00000002);
-	nv_icmd(priv, 0x000003aa, 0x00000001);
-	nv_icmd(priv, 0x000003a9, 0x00000001);
-	nv_icmd(priv, 0x00000380, 0x00000001);
-	nv_icmd(priv, 0x00000360, 0x00000040);
-	nv_icmd(priv, 0x00000366, 0x00000000);
-	nv_icmd(priv, 0x00000367, 0x00000000);
-	nv_icmd(priv, 0x00000368, 0x00001fff);
-	nv_icmd(priv, 0x00000370, 0x00000000);
-	nv_icmd(priv, 0x00000371, 0x00000000);
-	nv_icmd(priv, 0x00000372, 0x003fffff);
-	nv_icmd(priv, 0x0000037a, 0x00000012);
-	nv_icmd(priv, 0x000005e0, 0x00000022);
-	nv_icmd(priv, 0x000005e1, 0x00000022);
-	nv_icmd(priv, 0x000005e2, 0x00000022);
-	nv_icmd(priv, 0x000005e3, 0x00000022);
-	nv_icmd(priv, 0x000005e4, 0x00000022);
-	nv_icmd(priv, 0x00000619, 0x00000003);
-	nv_icmd(priv, 0x00000811, 0x00000003);
-	nv_icmd(priv, 0x00000812, 0x00000004);
-	nv_icmd(priv, 0x00000813, 0x00000006);
-	nv_icmd(priv, 0x00000814, 0x00000008);
-	nv_icmd(priv, 0x00000815, 0x0000000b);
-	nv_icmd(priv, 0x00000800, 0x00000001);
-	nv_icmd(priv, 0x00000801, 0x00000001);
-	nv_icmd(priv, 0x00000802, 0x00000001);
-	nv_icmd(priv, 0x00000803, 0x00000001);
-	nv_icmd(priv, 0x00000804, 0x00000001);
-	nv_icmd(priv, 0x00000805, 0x00000001);
-	nv_icmd(priv, 0x00000632, 0x00000001);
-	nv_icmd(priv, 0x00000633, 0x00000002);
-	nv_icmd(priv, 0x00000634, 0x00000003);
-	nv_icmd(priv, 0x00000635, 0x00000004);
-	nv_icmd(priv, 0x00000654, 0x3f800000);
-	nv_icmd(priv, 0x00000657, 0x3f800000);
-	nv_icmd(priv, 0x00000655, 0x3f800000);
-	nv_icmd(priv, 0x00000656, 0x3f800000);
-	nv_icmd(priv, 0x000006cd, 0x3f800000);
-	nv_icmd(priv, 0x000007f5, 0x3f800000);
-	nv_icmd(priv, 0x000007dc, 0x39291909);
-	nv_icmd(priv, 0x000007dd, 0x79695949);
-	nv_icmd(priv, 0x000007de, 0xb9a99989);
-	nv_icmd(priv, 0x000007df, 0xf9e9d9c9);
-	nv_icmd(priv, 0x000007e8, 0x00003210);
-	nv_icmd(priv, 0x000007e9, 0x00007654);
-	nv_icmd(priv, 0x000007ea, 0x00000098);
-	nv_icmd(priv, 0x000007ec, 0x39291909);
-	nv_icmd(priv, 0x000007ed, 0x79695949);
-	nv_icmd(priv, 0x000007ee, 0xb9a99989);
-	nv_icmd(priv, 0x000007ef, 0xf9e9d9c9);
-	nv_icmd(priv, 0x000007f0, 0x00003210);
-	nv_icmd(priv, 0x000007f1, 0x00007654);
-	nv_icmd(priv, 0x000007f2, 0x00000098);
-	nv_icmd(priv, 0x000005a5, 0x00000001);
-	nv_icmd(priv, 0x00000980, 0x00000000);
-	nv_icmd(priv, 0x00000981, 0x00000000);
-	nv_icmd(priv, 0x00000982, 0x00000000);
-	nv_icmd(priv, 0x00000983, 0x00000000);
-	nv_icmd(priv, 0x00000984, 0x00000000);
-	nv_icmd(priv, 0x00000985, 0x00000000);
-	nv_icmd(priv, 0x00000986, 0x00000000);
-	nv_icmd(priv, 0x00000987, 0x00000000);
-	nv_icmd(priv, 0x00000988, 0x00000000);
-	nv_icmd(priv, 0x00000989, 0x00000000);
-	nv_icmd(priv, 0x0000098a, 0x00000000);
-	nv_icmd(priv, 0x0000098b, 0x00000000);
-	nv_icmd(priv, 0x0000098c, 0x00000000);
-	nv_icmd(priv, 0x0000098d, 0x00000000);
-	nv_icmd(priv, 0x0000098e, 0x00000000);
-	nv_icmd(priv, 0x0000098f, 0x00000000);
-	nv_icmd(priv, 0x00000990, 0x00000000);
-	nv_icmd(priv, 0x00000991, 0x00000000);
-	nv_icmd(priv, 0x00000992, 0x00000000);
-	nv_icmd(priv, 0x00000993, 0x00000000);
-	nv_icmd(priv, 0x00000994, 0x00000000);
-	nv_icmd(priv, 0x00000995, 0x00000000);
-	nv_icmd(priv, 0x00000996, 0x00000000);
-	nv_icmd(priv, 0x00000997, 0x00000000);
-	nv_icmd(priv, 0x00000998, 0x00000000);
-	nv_icmd(priv, 0x00000999, 0x00000000);
-	nv_icmd(priv, 0x0000099a, 0x00000000);
-	nv_icmd(priv, 0x0000099b, 0x00000000);
-	nv_icmd(priv, 0x0000099c, 0x00000000);
-	nv_icmd(priv, 0x0000099d, 0x00000000);
-	nv_icmd(priv, 0x0000099e, 0x00000000);
-	nv_icmd(priv, 0x0000099f, 0x00000000);
-	nv_icmd(priv, 0x000009a0, 0x00000000);
-	nv_icmd(priv, 0x000009a1, 0x00000000);
-	nv_icmd(priv, 0x000009a2, 0x00000000);
-	nv_icmd(priv, 0x000009a3, 0x00000000);
-	nv_icmd(priv, 0x000009a4, 0x00000000);
-	nv_icmd(priv, 0x000009a5, 0x00000000);
-	nv_icmd(priv, 0x000009a6, 0x00000000);
-	nv_icmd(priv, 0x000009a7, 0x00000000);
-	nv_icmd(priv, 0x000009a8, 0x00000000);
-	nv_icmd(priv, 0x000009a9, 0x00000000);
-	nv_icmd(priv, 0x000009aa, 0x00000000);
-	nv_icmd(priv, 0x000009ab, 0x00000000);
-	nv_icmd(priv, 0x000009ac, 0x00000000);
-	nv_icmd(priv, 0x000009ad, 0x00000000);
-	nv_icmd(priv, 0x000009ae, 0x00000000);
-	nv_icmd(priv, 0x000009af, 0x00000000);
-	nv_icmd(priv, 0x000009b0, 0x00000000);
-	nv_icmd(priv, 0x000009b1, 0x00000000);
-	nv_icmd(priv, 0x000009b2, 0x00000000);
-	nv_icmd(priv, 0x000009b3, 0x00000000);
-	nv_icmd(priv, 0x000009b4, 0x00000000);
-	nv_icmd(priv, 0x000009b5, 0x00000000);
-	nv_icmd(priv, 0x000009b6, 0x00000000);
-	nv_icmd(priv, 0x000009b7, 0x00000000);
-	nv_icmd(priv, 0x000009b8, 0x00000000);
-	nv_icmd(priv, 0x000009b9, 0x00000000);
-	nv_icmd(priv, 0x000009ba, 0x00000000);
-	nv_icmd(priv, 0x000009bb, 0x00000000);
-	nv_icmd(priv, 0x000009bc, 0x00000000);
-	nv_icmd(priv, 0x000009bd, 0x00000000);
-	nv_icmd(priv, 0x000009be, 0x00000000);
-	nv_icmd(priv, 0x000009bf, 0x00000000);
-	nv_icmd(priv, 0x000009c0, 0x00000000);
-	nv_icmd(priv, 0x000009c1, 0x00000000);
-	nv_icmd(priv, 0x000009c2, 0x00000000);
-	nv_icmd(priv, 0x000009c3, 0x00000000);
-	nv_icmd(priv, 0x000009c4, 0x00000000);
-	nv_icmd(priv, 0x000009c5, 0x00000000);
-	nv_icmd(priv, 0x000009c6, 0x00000000);
-	nv_icmd(priv, 0x000009c7, 0x00000000);
-	nv_icmd(priv, 0x000009c8, 0x00000000);
-	nv_icmd(priv, 0x000009c9, 0x00000000);
-	nv_icmd(priv, 0x000009ca, 0x00000000);
-	nv_icmd(priv, 0x000009cb, 0x00000000);
-	nv_icmd(priv, 0x000009cc, 0x00000000);
-	nv_icmd(priv, 0x000009cd, 0x00000000);
-	nv_icmd(priv, 0x000009ce, 0x00000000);
-	nv_icmd(priv, 0x000009cf, 0x00000000);
-	nv_icmd(priv, 0x000009d0, 0x00000000);
-	nv_icmd(priv, 0x000009d1, 0x00000000);
-	nv_icmd(priv, 0x000009d2, 0x00000000);
-	nv_icmd(priv, 0x000009d3, 0x00000000);
-	nv_icmd(priv, 0x000009d4, 0x00000000);
-	nv_icmd(priv, 0x000009d5, 0x00000000);
-	nv_icmd(priv, 0x000009d6, 0x00000000);
-	nv_icmd(priv, 0x000009d7, 0x00000000);
-	nv_icmd(priv, 0x000009d8, 0x00000000);
-	nv_icmd(priv, 0x000009d9, 0x00000000);
-	nv_icmd(priv, 0x000009da, 0x00000000);
-	nv_icmd(priv, 0x000009db, 0x00000000);
-	nv_icmd(priv, 0x000009dc, 0x00000000);
-	nv_icmd(priv, 0x000009dd, 0x00000000);
-	nv_icmd(priv, 0x000009de, 0x00000000);
-	nv_icmd(priv, 0x000009df, 0x00000000);
-	nv_icmd(priv, 0x000009e0, 0x00000000);
-	nv_icmd(priv, 0x000009e1, 0x00000000);
-	nv_icmd(priv, 0x000009e2, 0x00000000);
-	nv_icmd(priv, 0x000009e3, 0x00000000);
-	nv_icmd(priv, 0x000009e4, 0x00000000);
-	nv_icmd(priv, 0x000009e5, 0x00000000);
-	nv_icmd(priv, 0x000009e6, 0x00000000);
-	nv_icmd(priv, 0x000009e7, 0x00000000);
-	nv_icmd(priv, 0x000009e8, 0x00000000);
-	nv_icmd(priv, 0x000009e9, 0x00000000);
-	nv_icmd(priv, 0x000009ea, 0x00000000);
-	nv_icmd(priv, 0x000009eb, 0x00000000);
-	nv_icmd(priv, 0x000009ec, 0x00000000);
-	nv_icmd(priv, 0x000009ed, 0x00000000);
-	nv_icmd(priv, 0x000009ee, 0x00000000);
-	nv_icmd(priv, 0x000009ef, 0x00000000);
-	nv_icmd(priv, 0x000009f0, 0x00000000);
-	nv_icmd(priv, 0x000009f1, 0x00000000);
-	nv_icmd(priv, 0x000009f2, 0x00000000);
-	nv_icmd(priv, 0x000009f3, 0x00000000);
-	nv_icmd(priv, 0x000009f4, 0x00000000);
-	nv_icmd(priv, 0x000009f5, 0x00000000);
-	nv_icmd(priv, 0x000009f6, 0x00000000);
-	nv_icmd(priv, 0x000009f7, 0x00000000);
-	nv_icmd(priv, 0x000009f8, 0x00000000);
-	nv_icmd(priv, 0x000009f9, 0x00000000);
-	nv_icmd(priv, 0x000009fa, 0x00000000);
-	nv_icmd(priv, 0x000009fb, 0x00000000);
-	nv_icmd(priv, 0x000009fc, 0x00000000);
-	nv_icmd(priv, 0x000009fd, 0x00000000);
-	nv_icmd(priv, 0x000009fe, 0x00000000);
-	nv_icmd(priv, 0x000009ff, 0x00000000);
-	nv_icmd(priv, 0x00000468, 0x00000004);
-	nv_icmd(priv, 0x0000046c, 0x00000001);
-	nv_icmd(priv, 0x00000470, 0x00000000);
-	nv_icmd(priv, 0x00000471, 0x00000000);
-	nv_icmd(priv, 0x00000472, 0x00000000);
-	nv_icmd(priv, 0x00000473, 0x00000000);
-	nv_icmd(priv, 0x00000474, 0x00000000);
-	nv_icmd(priv, 0x00000475, 0x00000000);
-	nv_icmd(priv, 0x00000476, 0x00000000);
-	nv_icmd(priv, 0x00000477, 0x00000000);
-	nv_icmd(priv, 0x00000478, 0x00000000);
-	nv_icmd(priv, 0x00000479, 0x00000000);
-	nv_icmd(priv, 0x0000047a, 0x00000000);
-	nv_icmd(priv, 0x0000047b, 0x00000000);
-	nv_icmd(priv, 0x0000047c, 0x00000000);
-	nv_icmd(priv, 0x0000047d, 0x00000000);
-	nv_icmd(priv, 0x0000047e, 0x00000000);
-	nv_icmd(priv, 0x0000047f, 0x00000000);
-	nv_icmd(priv, 0x00000480, 0x00000000);
-	nv_icmd(priv, 0x00000481, 0x00000000);
-	nv_icmd(priv, 0x00000482, 0x00000000);
-	nv_icmd(priv, 0x00000483, 0x00000000);
-	nv_icmd(priv, 0x00000484, 0x00000000);
-	nv_icmd(priv, 0x00000485, 0x00000000);
-	nv_icmd(priv, 0x00000486, 0x00000000);
-	nv_icmd(priv, 0x00000487, 0x00000000);
-	nv_icmd(priv, 0x00000488, 0x00000000);
-	nv_icmd(priv, 0x00000489, 0x00000000);
-	nv_icmd(priv, 0x0000048a, 0x00000000);
-	nv_icmd(priv, 0x0000048b, 0x00000000);
-	nv_icmd(priv, 0x0000048c, 0x00000000);
-	nv_icmd(priv, 0x0000048d, 0x00000000);
-	nv_icmd(priv, 0x0000048e, 0x00000000);
-	nv_icmd(priv, 0x0000048f, 0x00000000);
-	nv_icmd(priv, 0x00000490, 0x00000000);
-	nv_icmd(priv, 0x00000491, 0x00000000);
-	nv_icmd(priv, 0x00000492, 0x00000000);
-	nv_icmd(priv, 0x00000493, 0x00000000);
-	nv_icmd(priv, 0x00000494, 0x00000000);
-	nv_icmd(priv, 0x00000495, 0x00000000);
-	nv_icmd(priv, 0x00000496, 0x00000000);
-	nv_icmd(priv, 0x00000497, 0x00000000);
-	nv_icmd(priv, 0x00000498, 0x00000000);
-	nv_icmd(priv, 0x00000499, 0x00000000);
-	nv_icmd(priv, 0x0000049a, 0x00000000);
-	nv_icmd(priv, 0x0000049b, 0x00000000);
-	nv_icmd(priv, 0x0000049c, 0x00000000);
-	nv_icmd(priv, 0x0000049d, 0x00000000);
-	nv_icmd(priv, 0x0000049e, 0x00000000);
-	nv_icmd(priv, 0x0000049f, 0x00000000);
-	nv_icmd(priv, 0x000004a0, 0x00000000);
-	nv_icmd(priv, 0x000004a1, 0x00000000);
-	nv_icmd(priv, 0x000004a2, 0x00000000);
-	nv_icmd(priv, 0x000004a3, 0x00000000);
-	nv_icmd(priv, 0x000004a4, 0x00000000);
-	nv_icmd(priv, 0x000004a5, 0x00000000);
-	nv_icmd(priv, 0x000004a6, 0x00000000);
-	nv_icmd(priv, 0x000004a7, 0x00000000);
-	nv_icmd(priv, 0x000004a8, 0x00000000);
-	nv_icmd(priv, 0x000004a9, 0x00000000);
-	nv_icmd(priv, 0x000004aa, 0x00000000);
-	nv_icmd(priv, 0x000004ab, 0x00000000);
-	nv_icmd(priv, 0x000004ac, 0x00000000);
-	nv_icmd(priv, 0x000004ad, 0x00000000);
-	nv_icmd(priv, 0x000004ae, 0x00000000);
-	nv_icmd(priv, 0x000004af, 0x00000000);
-	nv_icmd(priv, 0x000004b0, 0x00000000);
-	nv_icmd(priv, 0x000004b1, 0x00000000);
-	nv_icmd(priv, 0x000004b2, 0x00000000);
-	nv_icmd(priv, 0x000004b3, 0x00000000);
-	nv_icmd(priv, 0x000004b4, 0x00000000);
-	nv_icmd(priv, 0x000004b5, 0x00000000);
-	nv_icmd(priv, 0x000004b6, 0x00000000);
-	nv_icmd(priv, 0x000004b7, 0x00000000);
-	nv_icmd(priv, 0x000004b8, 0x00000000);
-	nv_icmd(priv, 0x000004b9, 0x00000000);
-	nv_icmd(priv, 0x000004ba, 0x00000000);
-	nv_icmd(priv, 0x000004bb, 0x00000000);
-	nv_icmd(priv, 0x000004bc, 0x00000000);
-	nv_icmd(priv, 0x000004bd, 0x00000000);
-	nv_icmd(priv, 0x000004be, 0x00000000);
-	nv_icmd(priv, 0x000004bf, 0x00000000);
-	nv_icmd(priv, 0x000004c0, 0x00000000);
-	nv_icmd(priv, 0x000004c1, 0x00000000);
-	nv_icmd(priv, 0x000004c2, 0x00000000);
-	nv_icmd(priv, 0x000004c3, 0x00000000);
-	nv_icmd(priv, 0x000004c4, 0x00000000);
-	nv_icmd(priv, 0x000004c5, 0x00000000);
-	nv_icmd(priv, 0x000004c6, 0x00000000);
-	nv_icmd(priv, 0x000004c7, 0x00000000);
-	nv_icmd(priv, 0x000004c8, 0x00000000);
-	nv_icmd(priv, 0x000004c9, 0x00000000);
-	nv_icmd(priv, 0x000004ca, 0x00000000);
-	nv_icmd(priv, 0x000004cb, 0x00000000);
-	nv_icmd(priv, 0x000004cc, 0x00000000);
-	nv_icmd(priv, 0x000004cd, 0x00000000);
-	nv_icmd(priv, 0x000004ce, 0x00000000);
-	nv_icmd(priv, 0x000004cf, 0x00000000);
-	nv_icmd(priv, 0x00000510, 0x3f800000);
-	nv_icmd(priv, 0x00000511, 0x3f800000);
-	nv_icmd(priv, 0x00000512, 0x3f800000);
-	nv_icmd(priv, 0x00000513, 0x3f800000);
-	nv_icmd(priv, 0x00000514, 0x3f800000);
-	nv_icmd(priv, 0x00000515, 0x3f800000);
-	nv_icmd(priv, 0x00000516, 0x3f800000);
-	nv_icmd(priv, 0x00000517, 0x3f800000);
-	nv_icmd(priv, 0x00000518, 0x3f800000);
-	nv_icmd(priv, 0x00000519, 0x3f800000);
-	nv_icmd(priv, 0x0000051a, 0x3f800000);
-	nv_icmd(priv, 0x0000051b, 0x3f800000);
-	nv_icmd(priv, 0x0000051c, 0x3f800000);
-	nv_icmd(priv, 0x0000051d, 0x3f800000);
-	nv_icmd(priv, 0x0000051e, 0x3f800000);
-	nv_icmd(priv, 0x0000051f, 0x3f800000);
-	nv_icmd(priv, 0x00000520, 0x000002b6);
-	nv_icmd(priv, 0x00000529, 0x00000001);
-	nv_icmd(priv, 0x00000530, 0xffff0000);
-	nv_icmd(priv, 0x00000531, 0xffff0000);
-	nv_icmd(priv, 0x00000532, 0xffff0000);
-	nv_icmd(priv, 0x00000533, 0xffff0000);
-	nv_icmd(priv, 0x00000534, 0xffff0000);
-	nv_icmd(priv, 0x00000535, 0xffff0000);
-	nv_icmd(priv, 0x00000536, 0xffff0000);
-	nv_icmd(priv, 0x00000537, 0xffff0000);
-	nv_icmd(priv, 0x00000538, 0xffff0000);
-	nv_icmd(priv, 0x00000539, 0xffff0000);
-	nv_icmd(priv, 0x0000053a, 0xffff0000);
-	nv_icmd(priv, 0x0000053b, 0xffff0000);
-	nv_icmd(priv, 0x0000053c, 0xffff0000);
-	nv_icmd(priv, 0x0000053d, 0xffff0000);
-	nv_icmd(priv, 0x0000053e, 0xffff0000);
-	nv_icmd(priv, 0x0000053f, 0xffff0000);
-	nv_icmd(priv, 0x00000585, 0x0000003f);
-	nv_icmd(priv, 0x00000576, 0x00000003);
-	if (nv_device(priv)->chipset == 0xc1 ||
-	    nv_device(priv)->chipset >= 0xd0)
-		nv_icmd(priv, 0x0000057b, 0x00000059);
-	nv_icmd(priv, 0x00000586, 0x00000040);
-	nv_icmd(priv, 0x00000582, 0x00000080);
-	nv_icmd(priv, 0x00000583, 0x00000080);
-	nv_icmd(priv, 0x000005c2, 0x00000001);
-	nv_icmd(priv, 0x00000638, 0x00000001);
-	nv_icmd(priv, 0x00000639, 0x00000001);
-	nv_icmd(priv, 0x0000063a, 0x00000002);
-	nv_icmd(priv, 0x0000063b, 0x00000001);
-	nv_icmd(priv, 0x0000063c, 0x00000001);
-	nv_icmd(priv, 0x0000063d, 0x00000002);
-	nv_icmd(priv, 0x0000063e, 0x00000001);
-	nv_icmd(priv, 0x000008b8, 0x00000001);
-	nv_icmd(priv, 0x000008b9, 0x00000001);
-	nv_icmd(priv, 0x000008ba, 0x00000001);
-	nv_icmd(priv, 0x000008bb, 0x00000001);
-	nv_icmd(priv, 0x000008bc, 0x00000001);
-	nv_icmd(priv, 0x000008bd, 0x00000001);
-	nv_icmd(priv, 0x000008be, 0x00000001);
-	nv_icmd(priv, 0x000008bf, 0x00000001);
-	nv_icmd(priv, 0x00000900, 0x00000001);
-	nv_icmd(priv, 0x00000901, 0x00000001);
-	nv_icmd(priv, 0x00000902, 0x00000001);
-	nv_icmd(priv, 0x00000903, 0x00000001);
-	nv_icmd(priv, 0x00000904, 0x00000001);
-	nv_icmd(priv, 0x00000905, 0x00000001);
-	nv_icmd(priv, 0x00000906, 0x00000001);
-	nv_icmd(priv, 0x00000907, 0x00000001);
-	nv_icmd(priv, 0x00000908, 0x00000002);
-	nv_icmd(priv, 0x00000909, 0x00000002);
-	nv_icmd(priv, 0x0000090a, 0x00000002);
-	nv_icmd(priv, 0x0000090b, 0x00000002);
-	nv_icmd(priv, 0x0000090c, 0x00000002);
-	nv_icmd(priv, 0x0000090d, 0x00000002);
-	nv_icmd(priv, 0x0000090e, 0x00000002);
-	nv_icmd(priv, 0x0000090f, 0x00000002);
-	nv_icmd(priv, 0x00000910, 0x00000001);
-	nv_icmd(priv, 0x00000911, 0x00000001);
-	nv_icmd(priv, 0x00000912, 0x00000001);
-	nv_icmd(priv, 0x00000913, 0x00000001);
-	nv_icmd(priv, 0x00000914, 0x00000001);
-	nv_icmd(priv, 0x00000915, 0x00000001);
-	nv_icmd(priv, 0x00000916, 0x00000001);
-	nv_icmd(priv, 0x00000917, 0x00000001);
-	nv_icmd(priv, 0x00000918, 0x00000001);
-	nv_icmd(priv, 0x00000919, 0x00000001);
-	nv_icmd(priv, 0x0000091a, 0x00000001);
-	nv_icmd(priv, 0x0000091b, 0x00000001);
-	nv_icmd(priv, 0x0000091c, 0x00000001);
-	nv_icmd(priv, 0x0000091d, 0x00000001);
-	nv_icmd(priv, 0x0000091e, 0x00000001);
-	nv_icmd(priv, 0x0000091f, 0x00000001);
-	nv_icmd(priv, 0x00000920, 0x00000002);
-	nv_icmd(priv, 0x00000921, 0x00000002);
-	nv_icmd(priv, 0x00000922, 0x00000002);
-	nv_icmd(priv, 0x00000923, 0x00000002);
-	nv_icmd(priv, 0x00000924, 0x00000002);
-	nv_icmd(priv, 0x00000925, 0x00000002);
-	nv_icmd(priv, 0x00000926, 0x00000002);
-	nv_icmd(priv, 0x00000927, 0x00000002);
-	nv_icmd(priv, 0x00000928, 0x00000001);
-	nv_icmd(priv, 0x00000929, 0x00000001);
-	nv_icmd(priv, 0x0000092a, 0x00000001);
-	nv_icmd(priv, 0x0000092b, 0x00000001);
-	nv_icmd(priv, 0x0000092c, 0x00000001);
-	nv_icmd(priv, 0x0000092d, 0x00000001);
-	nv_icmd(priv, 0x0000092e, 0x00000001);
-	nv_icmd(priv, 0x0000092f, 0x00000001);
-	nv_icmd(priv, 0x00000648, 0x00000001);
-	nv_icmd(priv, 0x00000649, 0x00000001);
-	nv_icmd(priv, 0x0000064a, 0x00000001);
-	nv_icmd(priv, 0x0000064b, 0x00000001);
-	nv_icmd(priv, 0x0000064c, 0x00000001);
-	nv_icmd(priv, 0x0000064d, 0x00000001);
-	nv_icmd(priv, 0x0000064e, 0x00000001);
-	nv_icmd(priv, 0x0000064f, 0x00000001);
-	nv_icmd(priv, 0x00000650, 0x00000001);
-	nv_icmd(priv, 0x00000658, 0x0000000f);
-	nv_icmd(priv, 0x000007ff, 0x0000000a);
-	nv_icmd(priv, 0x0000066a, 0x40000000);
-	nv_icmd(priv, 0x0000066b, 0x10000000);
-	nv_icmd(priv, 0x0000066c, 0xffff0000);
-	nv_icmd(priv, 0x0000066d, 0xffff0000);
-	nv_icmd(priv, 0x000007af, 0x00000008);
-	nv_icmd(priv, 0x000007b0, 0x00000008);
-	nv_icmd(priv, 0x000007f6, 0x00000001);
-	nv_icmd(priv, 0x000006b2, 0x00000055);
-	nv_icmd(priv, 0x000007ad, 0x00000003);
-	nv_icmd(priv, 0x00000937, 0x00000001);
-	nv_icmd(priv, 0x00000971, 0x00000008);
-	nv_icmd(priv, 0x00000972, 0x00000040);
-	nv_icmd(priv, 0x00000973, 0x0000012c);
-	nv_icmd(priv, 0x0000097c, 0x00000040);
-	nv_icmd(priv, 0x00000979, 0x00000003);
-	nv_icmd(priv, 0x00000975, 0x00000020);
-	nv_icmd(priv, 0x00000976, 0x00000001);
-	nv_icmd(priv, 0x00000977, 0x00000020);
-	nv_icmd(priv, 0x00000978, 0x00000001);
-	nv_icmd(priv, 0x00000957, 0x00000003);
-	nv_icmd(priv, 0x0000095e, 0x20164010);
-	nv_icmd(priv, 0x0000095f, 0x00000020);
-	if (nv_device(priv)->chipset >= 0xd0)
-		nv_icmd(priv, 0x0000097d, 0x00000020);
-	nv_icmd(priv, 0x00000683, 0x00000006);
-	nv_icmd(priv, 0x00000685, 0x003fffff);
-	nv_icmd(priv, 0x00000687, 0x00000c48);
-	nv_icmd(priv, 0x000006a0, 0x00000005);
-	nv_icmd(priv, 0x00000840, 0x00300008);
-	nv_icmd(priv, 0x00000841, 0x04000080);
-	nv_icmd(priv, 0x00000842, 0x00300008);
-	nv_icmd(priv, 0x00000843, 0x04000080);
-	nv_icmd(priv, 0x00000818, 0x00000000);
-	nv_icmd(priv, 0x00000819, 0x00000000);
-	nv_icmd(priv, 0x0000081a, 0x00000000);
-	nv_icmd(priv, 0x0000081b, 0x00000000);
-	nv_icmd(priv, 0x0000081c, 0x00000000);
-	nv_icmd(priv, 0x0000081d, 0x00000000);
-	nv_icmd(priv, 0x0000081e, 0x00000000);
-	nv_icmd(priv, 0x0000081f, 0x00000000);
-	nv_icmd(priv, 0x00000848, 0x00000000);
-	nv_icmd(priv, 0x00000849, 0x00000000);
-	nv_icmd(priv, 0x0000084a, 0x00000000);
-	nv_icmd(priv, 0x0000084b, 0x00000000);
-	nv_icmd(priv, 0x0000084c, 0x00000000);
-	nv_icmd(priv, 0x0000084d, 0x00000000);
-	nv_icmd(priv, 0x0000084e, 0x00000000);
-	nv_icmd(priv, 0x0000084f, 0x00000000);
-	nv_icmd(priv, 0x00000850, 0x00000000);
-	nv_icmd(priv, 0x00000851, 0x00000000);
-	nv_icmd(priv, 0x00000852, 0x00000000);
-	nv_icmd(priv, 0x00000853, 0x00000000);
-	nv_icmd(priv, 0x00000854, 0x00000000);
-	nv_icmd(priv, 0x00000855, 0x00000000);
-	nv_icmd(priv, 0x00000856, 0x00000000);
-	nv_icmd(priv, 0x00000857, 0x00000000);
-	nv_icmd(priv, 0x00000738, 0x00000000);
-	nv_icmd(priv, 0x000006aa, 0x00000001);
-	nv_icmd(priv, 0x000006ab, 0x00000002);
-	nv_icmd(priv, 0x000006ac, 0x00000080);
-	nv_icmd(priv, 0x000006ad, 0x00000100);
-	nv_icmd(priv, 0x000006ae, 0x00000100);
-	nv_icmd(priv, 0x000006b1, 0x00000011);
-	nv_icmd(priv, 0x000006bb, 0x000000cf);
-	nv_icmd(priv, 0x000006ce, 0x2a712488);
-	nv_icmd(priv, 0x00000739, 0x4085c000);
-	nv_icmd(priv, 0x0000073a, 0x00000080);
-	nv_icmd(priv, 0x00000786, 0x80000100);
-	nv_icmd(priv, 0x0000073c, 0x00010100);
-	nv_icmd(priv, 0x0000073d, 0x02800000);
-	nv_icmd(priv, 0x00000787, 0x000000cf);
-	nv_icmd(priv, 0x0000078c, 0x00000008);
-	nv_icmd(priv, 0x00000792, 0x00000001);
-	nv_icmd(priv, 0x00000794, 0x00000001);
-	nv_icmd(priv, 0x00000795, 0x00000001);
-	nv_icmd(priv, 0x00000796, 0x00000001);
-	nv_icmd(priv, 0x00000797, 0x000000cf);
-	nv_icmd(priv, 0x00000836, 0x00000001);
-	nv_icmd(priv, 0x0000079a, 0x00000002);
-	nv_icmd(priv, 0x00000833, 0x04444480);
-	nv_icmd(priv, 0x000007a1, 0x00000001);
-	nv_icmd(priv, 0x000007a3, 0x00000001);
-	nv_icmd(priv, 0x000007a4, 0x00000001);
-	nv_icmd(priv, 0x000007a5, 0x00000001);
-	nv_icmd(priv, 0x00000831, 0x00000004);
-	nv_icmd(priv, 0x0000080c, 0x00000002);
-	nv_icmd(priv, 0x0000080d, 0x00000100);
-	nv_icmd(priv, 0x0000080e, 0x00000100);
-	nv_icmd(priv, 0x0000080f, 0x00000001);
-	nv_icmd(priv, 0x00000823, 0x00000002);
-	nv_icmd(priv, 0x00000824, 0x00000100);
-	nv_icmd(priv, 0x00000825, 0x00000100);
-	nv_icmd(priv, 0x00000826, 0x00000001);
-	nv_icmd(priv, 0x0000095d, 0x00000001);
-	nv_icmd(priv, 0x0000082b, 0x00000004);
-	nv_icmd(priv, 0x00000942, 0x00010001);
-	nv_icmd(priv, 0x00000943, 0x00000001);
-	nv_icmd(priv, 0x00000944, 0x00000022);
-	nv_icmd(priv, 0x000007c5, 0x00010001);
-	nv_icmd(priv, 0x00000834, 0x00000001);
-	nv_icmd(priv, 0x000007c7, 0x00000001);
-	nv_icmd(priv, 0x0000c1b0, 0x0000000f);
-	nv_icmd(priv, 0x0000c1b1, 0x0000000f);
-	nv_icmd(priv, 0x0000c1b2, 0x0000000f);
-	nv_icmd(priv, 0x0000c1b3, 0x0000000f);
-	nv_icmd(priv, 0x0000c1b4, 0x0000000f);
-	nv_icmd(priv, 0x0000c1b5, 0x0000000f);
-	nv_icmd(priv, 0x0000c1b6, 0x0000000f);
-	nv_icmd(priv, 0x0000c1b7, 0x0000000f);
-	nv_icmd(priv, 0x0000c1b8, 0x0fac6881);
-	nv_icmd(priv, 0x0000c1b9, 0x00fac688);
-	nv_icmd(priv, 0x0001e100, 0x00000001);
-	nv_icmd(priv, 0x00001000, 0x00000002);
-	nv_icmd(priv, 0x000006aa, 0x00000001);
-	nv_icmd(priv, 0x000006ad, 0x00000100);
-	nv_icmd(priv, 0x000006ae, 0x00000100);
-	nv_icmd(priv, 0x000006b1, 0x00000011);
-	nv_icmd(priv, 0x0000078c, 0x00000008);
-	nv_icmd(priv, 0x00000792, 0x00000001);
-	nv_icmd(priv, 0x00000794, 0x00000001);
-	nv_icmd(priv, 0x00000795, 0x00000001);
-	nv_icmd(priv, 0x00000796, 0x00000001);
-	nv_icmd(priv, 0x00000797, 0x000000cf);
-	nv_icmd(priv, 0x0000079a, 0x00000002);
-	nv_icmd(priv, 0x00000833, 0x04444480);
-	nv_icmd(priv, 0x000007a1, 0x00000001);
-	nv_icmd(priv, 0x000007a3, 0x00000001);
-	nv_icmd(priv, 0x000007a4, 0x00000001);
-	nv_icmd(priv, 0x000007a5, 0x00000001);
-	nv_icmd(priv, 0x00000831, 0x00000004);
-	nv_icmd(priv, 0x0001e100, 0x00000001);
-	nv_icmd(priv, 0x00001000, 0x00000014);
-	nv_icmd(priv, 0x00000351, 0x00000100);
-	nv_icmd(priv, 0x00000957, 0x00000003);
-	nv_icmd(priv, 0x0000095d, 0x00000001);
-	nv_icmd(priv, 0x0000082b, 0x00000004);
-	nv_icmd(priv, 0x00000942, 0x00010001);
-	nv_icmd(priv, 0x00000943, 0x00000001);
-	nv_icmd(priv, 0x000007c5, 0x00010001);
-	nv_icmd(priv, 0x00000834, 0x00000001);
-	nv_icmd(priv, 0x000007c7, 0x00000001);
-	nv_icmd(priv, 0x0001e100, 0x00000001);
-	nv_icmd(priv, 0x00001000, 0x00000001);
-	nv_icmd(priv, 0x0000080c, 0x00000002);
-	nv_icmd(priv, 0x0000080d, 0x00000100);
-	nv_icmd(priv, 0x0000080e, 0x00000100);
-	nv_icmd(priv, 0x0000080f, 0x00000001);
-	nv_icmd(priv, 0x00000823, 0x00000002);
-	nv_icmd(priv, 0x00000824, 0x00000100);
-	nv_icmd(priv, 0x00000825, 0x00000100);
-	nv_icmd(priv, 0x00000826, 0x00000001);
-	nv_icmd(priv, 0x0001e100, 0x00000001);
-	nv_wr32(priv, 0x400208, 0x00000000);
-	nv_wr32(priv, 0x404154, 0x00000400);
-
-	nvc0_grctx_generate_9097(priv);
-	if (fermi >= 0x9197)
-		nvc0_grctx_generate_9197(priv);
-	if (fermi >= 0x9297)
-		nvc0_grctx_generate_9297(priv);
-	nvc0_grctx_generate_902d(priv);
-	nvc0_grctx_generate_9039(priv);
-	nvc0_grctx_generate_90c0(priv);
-
-	nv_wr32(priv, 0x000260, r000260);
-
-	return nvc0_grctx_fini(&info);
-}
+struct nouveau_oclass *
+nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xc0),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+	.main = nvc0_grctx_generate_main,
+	.mods = nvc0_grctx_generate_mods,
+	.unkn = nvc0_grctx_generate_unkn,
+	.hub  = nvc0_grctx_init_hub,
+	.gpc  = nvc0_grctx_init_gpc,
+	.icmd = nvc0_grctx_init_icmd,
+	.mthd = nvc0_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
new file mode 100644
index 0000000..e5be3ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
@@ -0,0 +1,823 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nvc1_grctx_init_icmd[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000b2,  40, 0x01, 0x00000000 },
+	{ 0x000210,   8, 0x01, 0x00000040 },
+	{ 0x000218,   8, 0x01, 0x0000c080 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00001fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x003fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x0005e0,   5, 0x01, 0x00000022 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   1, 0x01, 0x00000001 },
+	{ 0x000639,   1, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x00000c48 },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00300008 },
+	{ 0x000841,   1, 0x01, 0x04000080 },
+	{ 0x000842,   1, 0x01, 0x00300008 },
+	{ 0x000843,   1, 0x01, 0x04000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x000944,   1, 0x01, 0x00000022 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000014 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc1_grctx_init_9097[] = {
+	{ 0x000800,   8, 0x40, 0x00000000 },
+	{ 0x000804,   8, 0x40, 0x00000000 },
+	{ 0x000808,   8, 0x40, 0x00000400 },
+	{ 0x00080c,   8, 0x40, 0x00000300 },
+	{ 0x000810,   1, 0x04, 0x000000cf },
+	{ 0x000850,   7, 0x40, 0x00000000 },
+	{ 0x000814,   8, 0x40, 0x00000040 },
+	{ 0x000818,   8, 0x40, 0x00000001 },
+	{ 0x00081c,   8, 0x40, 0x00000000 },
+	{ 0x000820,   8, 0x40, 0x00000000 },
+	{ 0x002700,   8, 0x20, 0x00000000 },
+	{ 0x002704,   8, 0x20, 0x00000000 },
+	{ 0x002708,   8, 0x20, 0x00000000 },
+	{ 0x00270c,   8, 0x20, 0x00000000 },
+	{ 0x002710,   8, 0x20, 0x00014000 },
+	{ 0x002714,   8, 0x20, 0x00000040 },
+	{ 0x001c00,  16, 0x10, 0x00000000 },
+	{ 0x001c04,  16, 0x10, 0x00000000 },
+	{ 0x001c08,  16, 0x10, 0x00000000 },
+	{ 0x001c0c,  16, 0x10, 0x00000000 },
+	{ 0x001d00,  16, 0x10, 0x00000000 },
+	{ 0x001d04,  16, 0x10, 0x00000000 },
+	{ 0x001d08,  16, 0x10, 0x00000000 },
+	{ 0x001d0c,  16, 0x10, 0x00000000 },
+	{ 0x001f00,  16, 0x08, 0x00000000 },
+	{ 0x001f04,  16, 0x08, 0x00000000 },
+	{ 0x001f80,  16, 0x08, 0x00000000 },
+	{ 0x001f84,  16, 0x08, 0x00000000 },
+	{ 0x002200,   5, 0x10, 0x00000022 },
+	{ 0x002000,   1, 0x04, 0x00000000 },
+	{ 0x002040,   1, 0x04, 0x00000011 },
+	{ 0x002080,   1, 0x04, 0x00000020 },
+	{ 0x0020c0,   1, 0x04, 0x00000030 },
+	{ 0x002100,   1, 0x04, 0x00000040 },
+	{ 0x002140,   1, 0x04, 0x00000051 },
+	{ 0x00200c,   6, 0x40, 0x00000001 },
+	{ 0x002010,   1, 0x04, 0x00000000 },
+	{ 0x002050,   1, 0x04, 0x00000000 },
+	{ 0x002090,   1, 0x04, 0x00000001 },
+	{ 0x0020d0,   1, 0x04, 0x00000002 },
+	{ 0x002110,   1, 0x04, 0x00000003 },
+	{ 0x002150,   1, 0x04, 0x00000004 },
+	{ 0x000380,   4, 0x20, 0x00000000 },
+	{ 0x000384,   4, 0x20, 0x00000000 },
+	{ 0x000388,   4, 0x20, 0x00000000 },
+	{ 0x00038c,   4, 0x20, 0x00000000 },
+	{ 0x000700,   4, 0x10, 0x00000000 },
+	{ 0x000704,   4, 0x10, 0x00000000 },
+	{ 0x000708,   4, 0x10, 0x00000000 },
+	{ 0x002800, 128, 0x04, 0x00000000 },
+	{ 0x000a00,  16, 0x20, 0x00000000 },
+	{ 0x000a04,  16, 0x20, 0x00000000 },
+	{ 0x000a08,  16, 0x20, 0x00000000 },
+	{ 0x000a0c,  16, 0x20, 0x00000000 },
+	{ 0x000a10,  16, 0x20, 0x00000000 },
+	{ 0x000a14,  16, 0x20, 0x00000000 },
+	{ 0x000c00,  16, 0x10, 0x00000000 },
+	{ 0x000c04,  16, 0x10, 0x00000000 },
+	{ 0x000c08,  16, 0x10, 0x00000000 },
+	{ 0x000c0c,  16, 0x10, 0x3f800000 },
+	{ 0x000d00,   8, 0x08, 0xffff0000 },
+	{ 0x000d04,   8, 0x08, 0xffff0000 },
+	{ 0x000e00,  16, 0x10, 0x00000000 },
+	{ 0x000e04,  16, 0x10, 0xffff0000 },
+	{ 0x000e08,  16, 0x10, 0xffff0000 },
+	{ 0x000d40,   4, 0x08, 0x00000000 },
+	{ 0x000d44,   4, 0x08, 0x00000000 },
+	{ 0x001e00,   8, 0x20, 0x00000001 },
+	{ 0x001e04,   8, 0x20, 0x00000001 },
+	{ 0x001e08,   8, 0x20, 0x00000002 },
+	{ 0x001e0c,   8, 0x20, 0x00000001 },
+	{ 0x001e10,   8, 0x20, 0x00000001 },
+	{ 0x001e14,   8, 0x20, 0x00000002 },
+	{ 0x001e18,   8, 0x20, 0x00000001 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x001514,   1, 0x04, 0x00000000 },
+	{ 0x000d68,   1, 0x04, 0x0000ffff },
+	{ 0x00121c,   1, 0x04, 0x0fac6881 },
+	{ 0x000fac,   1, 0x04, 0x00000001 },
+	{ 0x001538,   1, 0x04, 0x00000001 },
+	{ 0x000fe0,   2, 0x04, 0x00000000 },
+	{ 0x000fe8,   1, 0x04, 0x00000014 },
+	{ 0x000fec,   1, 0x04, 0x00000040 },
+	{ 0x000ff0,   1, 0x04, 0x00000000 },
+	{ 0x00179c,   1, 0x04, 0x00000000 },
+	{ 0x001228,   1, 0x04, 0x00000400 },
+	{ 0x00122c,   1, 0x04, 0x00000300 },
+	{ 0x001230,   1, 0x04, 0x00010001 },
+	{ 0x0007f8,   1, 0x04, 0x00000000 },
+	{ 0x0015b4,   1, 0x04, 0x00000001 },
+	{ 0x0015cc,   1, 0x04, 0x00000000 },
+	{ 0x001534,   1, 0x04, 0x00000000 },
+	{ 0x000fb0,   1, 0x04, 0x00000000 },
+	{ 0x0015d0,   1, 0x04, 0x00000000 },
+	{ 0x00153c,   1, 0x04, 0x00000000 },
+	{ 0x0016b4,   1, 0x04, 0x00000003 },
+	{ 0x000fbc,   4, 0x04, 0x0000ffff },
+	{ 0x000df8,   2, 0x04, 0x00000000 },
+	{ 0x001948,   1, 0x04, 0x00000000 },
+	{ 0x001970,   1, 0x04, 0x00000001 },
+	{ 0x00161c,   1, 0x04, 0x000009f0 },
+	{ 0x000dcc,   1, 0x04, 0x00000010 },
+	{ 0x00163c,   1, 0x04, 0x00000000 },
+	{ 0x0015e4,   1, 0x04, 0x00000000 },
+	{ 0x001160,  32, 0x04, 0x25e00040 },
+	{ 0x001880,  32, 0x04, 0x00000000 },
+	{ 0x000f84,   2, 0x04, 0x00000000 },
+	{ 0x0017c8,   2, 0x04, 0x00000000 },
+	{ 0x0017d0,   1, 0x04, 0x000000ff },
+	{ 0x0017d4,   1, 0x04, 0xffffffff },
+	{ 0x0017d8,   1, 0x04, 0x00000002 },
+	{ 0x0017dc,   1, 0x04, 0x00000000 },
+	{ 0x0015f4,   2, 0x04, 0x00000000 },
+	{ 0x001434,   2, 0x04, 0x00000000 },
+	{ 0x000d74,   1, 0x04, 0x00000000 },
+	{ 0x000dec,   1, 0x04, 0x00000001 },
+	{ 0x0013a4,   1, 0x04, 0x00000000 },
+	{ 0x001318,   1, 0x04, 0x00000001 },
+	{ 0x001644,   1, 0x04, 0x00000000 },
+	{ 0x000748,   1, 0x04, 0x00000000 },
+	{ 0x000de8,   1, 0x04, 0x00000000 },
+	{ 0x001648,   1, 0x04, 0x00000000 },
+	{ 0x0012a4,   1, 0x04, 0x00000000 },
+	{ 0x001120,   4, 0x04, 0x00000000 },
+	{ 0x001118,   1, 0x04, 0x00000000 },
+	{ 0x00164c,   1, 0x04, 0x00000000 },
+	{ 0x001658,   1, 0x04, 0x00000000 },
+	{ 0x001910,   1, 0x04, 0x00000290 },
+	{ 0x001518,   1, 0x04, 0x00000000 },
+	{ 0x00165c,   1, 0x04, 0x00000001 },
+	{ 0x001520,   1, 0x04, 0x00000000 },
+	{ 0x001604,   1, 0x04, 0x00000000 },
+	{ 0x001570,   1, 0x04, 0x00000000 },
+	{ 0x0013b0,   2, 0x04, 0x3f800000 },
+	{ 0x00020c,   1, 0x04, 0x00000000 },
+	{ 0x001670,   1, 0x04, 0x30201000 },
+	{ 0x001674,   1, 0x04, 0x70605040 },
+	{ 0x001678,   1, 0x04, 0xb8a89888 },
+	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+	{ 0x00166c,   1, 0x04, 0x00000000 },
+	{ 0x001680,   1, 0x04, 0x00ffff00 },
+	{ 0x0012d0,   1, 0x04, 0x00000003 },
+	{ 0x0012d4,   1, 0x04, 0x00000002 },
+	{ 0x001684,   2, 0x04, 0x00000000 },
+	{ 0x000dac,   2, 0x04, 0x00001b02 },
+	{ 0x000db4,   1, 0x04, 0x00000000 },
+	{ 0x00168c,   1, 0x04, 0x00000000 },
+	{ 0x0015bc,   1, 0x04, 0x00000000 },
+	{ 0x00156c,   1, 0x04, 0x00000000 },
+	{ 0x00187c,   1, 0x04, 0x00000000 },
+	{ 0x001110,   1, 0x04, 0x00000001 },
+	{ 0x000dc0,   3, 0x04, 0x00000000 },
+	{ 0x001234,   1, 0x04, 0x00000000 },
+	{ 0x001690,   1, 0x04, 0x00000000 },
+	{ 0x0012ac,   1, 0x04, 0x00000001 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x001000,   1, 0x04, 0x00000010 },
+	{ 0x0010fc,   1, 0x04, 0x00000000 },
+	{ 0x001290,   1, 0x04, 0x00000000 },
+	{ 0x000218,   1, 0x04, 0x00000010 },
+	{ 0x0012d8,   1, 0x04, 0x00000000 },
+	{ 0x0012dc,   1, 0x04, 0x00000010 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x00155c,   2, 0x04, 0x00000000 },
+	{ 0x001564,   1, 0x04, 0x00001fff },
+	{ 0x001574,   2, 0x04, 0x00000000 },
+	{ 0x00157c,   1, 0x04, 0x003fffff },
+	{ 0x001354,   1, 0x04, 0x00000000 },
+	{ 0x001664,   1, 0x04, 0x00000000 },
+	{ 0x001610,   1, 0x04, 0x00000012 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x00162c,   1, 0x04, 0x00000003 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000324,   6, 0x04, 0x3f800000 },
+	{ 0x000750,   1, 0x04, 0x00000000 },
+	{ 0x000760,   1, 0x04, 0x39291909 },
+	{ 0x000764,   1, 0x04, 0x79695949 },
+	{ 0x000768,   1, 0x04, 0xb9a99989 },
+	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x000770,   1, 0x04, 0x30201000 },
+	{ 0x000774,   1, 0x04, 0x70605040 },
+	{ 0x000778,   1, 0x04, 0x00009080 },
+	{ 0x000780,   1, 0x04, 0x39291909 },
+	{ 0x000784,   1, 0x04, 0x79695949 },
+	{ 0x000788,   1, 0x04, 0xb9a99989 },
+	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x0007d0,   1, 0x04, 0x30201000 },
+	{ 0x0007d4,   1, 0x04, 0x70605040 },
+	{ 0x0007d8,   1, 0x04, 0x00009080 },
+	{ 0x00037c,   1, 0x04, 0x00000001 },
+	{ 0x000740,   2, 0x04, 0x00000000 },
+	{ 0x002600,   1, 0x04, 0x00000000 },
+	{ 0x001918,   1, 0x04, 0x00000000 },
+	{ 0x00191c,   1, 0x04, 0x00000900 },
+	{ 0x001920,   1, 0x04, 0x00000405 },
+	{ 0x001308,   1, 0x04, 0x00000001 },
+	{ 0x001924,   1, 0x04, 0x00000000 },
+	{ 0x0013ac,   1, 0x04, 0x00000000 },
+	{ 0x00192c,   1, 0x04, 0x00000001 },
+	{ 0x00193c,   1, 0x04, 0x00002c1c },
+	{ 0x000d7c,   1, 0x04, 0x00000000 },
+	{ 0x000f8c,   1, 0x04, 0x00000000 },
+	{ 0x0002c0,   1, 0x04, 0x00000001 },
+	{ 0x001510,   1, 0x04, 0x00000000 },
+	{ 0x001940,   1, 0x04, 0x00000000 },
+	{ 0x000ff4,   2, 0x04, 0x00000000 },
+	{ 0x00194c,   2, 0x04, 0x00000000 },
+	{ 0x001968,   1, 0x04, 0x00000000 },
+	{ 0x001590,   1, 0x04, 0x0000003f },
+	{ 0x0007e8,   4, 0x04, 0x00000000 },
+	{ 0x00196c,   1, 0x04, 0x00000011 },
+	{ 0x00197c,   1, 0x04, 0x00000000 },
+	{ 0x000fcc,   2, 0x04, 0x00000000 },
+	{ 0x0002d8,   1, 0x04, 0x00000040 },
+	{ 0x001980,   1, 0x04, 0x00000080 },
+	{ 0x001504,   1, 0x04, 0x00000080 },
+	{ 0x001984,   1, 0x04, 0x00000000 },
+	{ 0x000300,   1, 0x04, 0x00000001 },
+	{ 0x0013a8,   1, 0x04, 0x00000000 },
+	{ 0x0012ec,   1, 0x04, 0x00000000 },
+	{ 0x001310,   1, 0x04, 0x00000000 },
+	{ 0x001314,   1, 0x04, 0x00000001 },
+	{ 0x001380,   1, 0x04, 0x00000000 },
+	{ 0x001384,   4, 0x04, 0x00000001 },
+	{ 0x001394,   1, 0x04, 0x00000000 },
+	{ 0x00139c,   1, 0x04, 0x00000000 },
+	{ 0x001398,   1, 0x04, 0x00000000 },
+	{ 0x001594,   1, 0x04, 0x00000000 },
+	{ 0x001598,   4, 0x04, 0x00000001 },
+	{ 0x000f54,   3, 0x04, 0x00000000 },
+	{ 0x0019bc,   1, 0x04, 0x00000000 },
+	{ 0x000f9c,   2, 0x04, 0x00000000 },
+	{ 0x0012cc,   1, 0x04, 0x00000000 },
+	{ 0x0012e8,   1, 0x04, 0x00000000 },
+	{ 0x00130c,   1, 0x04, 0x00000001 },
+	{ 0x001360,   8, 0x04, 0x00000000 },
+	{ 0x00133c,   2, 0x04, 0x00000001 },
+	{ 0x001344,   1, 0x04, 0x00000002 },
+	{ 0x001348,   2, 0x04, 0x00000001 },
+	{ 0x001350,   1, 0x04, 0x00000002 },
+	{ 0x001358,   1, 0x04, 0x00000001 },
+	{ 0x0012e4,   1, 0x04, 0x00000000 },
+	{ 0x00131c,   1, 0x04, 0x00000000 },
+	{ 0x001320,   3, 0x04, 0x00000000 },
+	{ 0x0019c0,   1, 0x04, 0x00000000 },
+	{ 0x001140,   1, 0x04, 0x00000000 },
+	{ 0x0019c4,   1, 0x04, 0x00000000 },
+	{ 0x0019c8,   1, 0x04, 0x00001500 },
+	{ 0x00135c,   1, 0x04, 0x00000000 },
+	{ 0x000f90,   1, 0x04, 0x00000000 },
+	{ 0x0019e0,   8, 0x04, 0x00000001 },
+	{ 0x0019cc,   1, 0x04, 0x00000001 },
+	{ 0x0015b8,   1, 0x04, 0x00000000 },
+	{ 0x001a00,   1, 0x04, 0x00001111 },
+	{ 0x001a04,   7, 0x04, 0x00000000 },
+	{ 0x000d6c,   2, 0x04, 0xffff0000 },
+	{ 0x0010f8,   1, 0x04, 0x00001010 },
+	{ 0x000d80,   5, 0x04, 0x00000000 },
+	{ 0x000da0,   1, 0x04, 0x00000000 },
+	{ 0x001508,   1, 0x04, 0x80000000 },
+	{ 0x00150c,   1, 0x04, 0x40000000 },
+	{ 0x001668,   1, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000008 },
+	{ 0x000d9c,   1, 0x04, 0x00000001 },
+	{ 0x0007dc,   1, 0x04, 0x00000000 },
+	{ 0x00074c,   1, 0x04, 0x00000055 },
+	{ 0x001420,   1, 0x04, 0x00000003 },
+	{ 0x0017bc,   2, 0x04, 0x00000000 },
+	{ 0x0017c4,   1, 0x04, 0x00000001 },
+	{ 0x001008,   1, 0x04, 0x00000008 },
+	{ 0x00100c,   1, 0x04, 0x00000040 },
+	{ 0x001010,   1, 0x04, 0x0000012c },
+	{ 0x000d60,   1, 0x04, 0x00000040 },
+	{ 0x00075c,   1, 0x04, 0x00000003 },
+	{ 0x001018,   1, 0x04, 0x00000020 },
+	{ 0x00101c,   1, 0x04, 0x00000001 },
+	{ 0x001020,   1, 0x04, 0x00000020 },
+	{ 0x001024,   1, 0x04, 0x00000001 },
+	{ 0x001444,   3, 0x04, 0x00000000 },
+	{ 0x000360,   1, 0x04, 0x20164010 },
+	{ 0x000364,   1, 0x04, 0x00000020 },
+	{ 0x000368,   1, 0x04, 0x00000000 },
+	{ 0x000de4,   1, 0x04, 0x00000000 },
+	{ 0x000204,   1, 0x04, 0x00000006 },
+	{ 0x000208,   1, 0x04, 0x00000000 },
+	{ 0x0002cc,   1, 0x04, 0x003fffff },
+	{ 0x0002d0,   1, 0x04, 0x00000c48 },
+	{ 0x001220,   1, 0x04, 0x00000005 },
+	{ 0x000fdc,   1, 0x04, 0x00000000 },
+	{ 0x000f98,   1, 0x04, 0x00300008 },
+	{ 0x001284,   1, 0x04, 0x04000080 },
+	{ 0x001450,   1, 0x04, 0x00300008 },
+	{ 0x001454,   1, 0x04, 0x04000080 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_9197[] = {
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x0002e4,   1, 0x04, 0x0000b001 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_unk58xx[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180218 },
+	{ 0x405834,   2, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_rop[] = {
+	{ 0x408800,   1, 0x04, 0x02802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1003e005 },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x62000001 },
+	{ 0x408908,   1, 0x04, 0x00c80929 },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_gpc_0[] = {
+	{ 0x418380,   1, 0x04, 0x00000016 },
+	{ 0x418400,   1, 0x04, 0x38004e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x00200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{ 0x418600,   1, 0x04, 0x0000001f },
+	{ 0x418684,   1, 0x04, 0x0000000f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   1, 0x04, 0x00000000 },
+	{ 0x41870c,   1, 0x04, 0x07c80000 },
+	{ 0x418710,   1, 0x04, 0x00000000 },
+	{ 0x418800,   1, 0x04, 0x0006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x00100018 },
+	{ 0x41891c,   1, 0x04, 0x00ff00ff },
+	{ 0x418924,   1, 0x04, 0x00000000 },
+	{ 0x418928,   1, 0x04, 0x00ffff00 },
+	{ 0x41892c,   1, 0x04, 0x0000ff00 },
+	{ 0x418a00,   3, 0x04, 0x00000000 },
+	{ 0x418a0c,   1, 0x04, 0x00010000 },
+	{ 0x418a10,   3, 0x04, 0x00000000 },
+	{ 0x418a20,   3, 0x04, 0x00000000 },
+	{ 0x418a2c,   1, 0x04, 0x00010000 },
+	{ 0x418a30,   3, 0x04, 0x00000000 },
+	{ 0x418a40,   3, 0x04, 0x00000000 },
+	{ 0x418a4c,   1, 0x04, 0x00010000 },
+	{ 0x418a50,   3, 0x04, 0x00000000 },
+	{ 0x418a60,   3, 0x04, 0x00000000 },
+	{ 0x418a6c,   1, 0x04, 0x00010000 },
+	{ 0x418a70,   3, 0x04, 0x00000000 },
+	{ 0x418a80,   3, 0x04, 0x00000000 },
+	{ 0x418a8c,   1, 0x04, 0x00010000 },
+	{ 0x418a90,   3, 0x04, 0x00000000 },
+	{ 0x418aa0,   3, 0x04, 0x00000000 },
+	{ 0x418aac,   1, 0x04, 0x00010000 },
+	{ 0x418ab0,   3, 0x04, 0x00000000 },
+	{ 0x418ac0,   3, 0x04, 0x00000000 },
+	{ 0x418acc,   1, 0x04, 0x00010000 },
+	{ 0x418ad0,   3, 0x04, 0x00000000 },
+	{ 0x418ae0,   3, 0x04, 0x00000000 },
+	{ 0x418aec,   1, 0x04, 0x00010000 },
+	{ 0x418af0,   3, 0x04, 0x00000000 },
+	{ 0x418b00,   1, 0x04, 0x00000000 },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c6c,   1, 0x04, 0x00000001 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{ 0x419000,   1, 0x04, 0x00000780 },
+	{ 0x419004,   2, 0x04, 0x00000000 },
+	{ 0x419014,   1, 0x04, 0x00000004 },
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_tpc[] = {
+	{ 0x419818,   1, 0x04, 0x00000000 },
+	{ 0x41983c,   1, 0x04, 0x00038bc7 },
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x00000129 },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x00000000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419ac4,   1, 0x04, 0x0007f440 },
+	{ 0x419b00,   1, 0x04, 0x0a418820 },
+	{ 0x419b04,   1, 0x04, 0x062080e6 },
+	{ 0x419b08,   1, 0x04, 0x020398a4 },
+	{ 0x419b0c,   1, 0x04, 0x0e629062 },
+	{ 0x419b10,   1, 0x04, 0x0a418820 },
+	{ 0x419b14,   1, 0x04, 0x000000e6 },
+	{ 0x419bd0,   1, 0x04, 0x00900103 },
+	{ 0x419be0,   1, 0x04, 0x00400001 },
+	{ 0x419be4,   1, 0x04, 0x00000000 },
+	{ 0x419c00,   1, 0x04, 0x00000002 },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x00020048 },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000183 },
+	{ 0x419d20,   1, 0x04, 0x12180000 },
+	{ 0x419d24,   1, 0x04, 0x00001fff },
+	{ 0x419d44,   1, 0x04, 0x02180218 },
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419ee0,   1, 0x04, 0x00011110 },
+	{ 0x419f30,  11, 0x04, 0x00000000 },
+};
+
+void
+nvc1_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+	int gpc, tpc;
+	u32 offset;
+
+	mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+	mmio_list(0x408004, 0x00000000,  8, 0);
+	mmio_list(0x408008, 0x80000018,  0, 0);
+	mmio_list(0x40800c, 0x00000000,  8, 1);
+	mmio_list(0x408010, 0x80000000,  0, 0);
+	mmio_list(0x418810, 0x80000000, 12, 2);
+	mmio_list(0x419848, 0x10000000, 12, 2);
+	mmio_list(0x419004, 0x00000000,  8, 1);
+	mmio_list(0x419008, 0x00000000,  0, 0);
+	mmio_list(0x418808, 0x00000000,  8, 0);
+	mmio_list(0x41880c, 0x80000018,  0, 0);
+
+	mmio_list(0x405830, 0x02180218, 0, 0);
+	mmio_list(0x4064c4, 0x0086ffff, 0, 0);
+
+	for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			u32 addr = TPC_UNIT(gpc, tpc, 0x0520);
+			mmio_list(addr, 0x12180000 | offset, 0, 0);
+			offset += 0x0324;
+		}
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			u32 addr = TPC_UNIT(gpc, tpc, 0x0544);
+			mmio_list(addr, 0x02180000 | offset, 0, 0);
+			offset += 0x0324;
+		}
+	}
+}
+
+void
+nvc1_grctx_generate_unkn(struct nvc0_graph_priv *priv)
+{
+	nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
+	nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
+	nv_mask(priv, 0x419814, 0x00000004, 0x00000004);
+	nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
+	nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
+	nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
+}
+
+static struct nvc0_graph_init *
+nvc1_grctx_init_hub[] = {
+	nvc0_grctx_init_base,
+	nvc0_grctx_init_unk40xx,
+	nvc0_grctx_init_unk44xx,
+	nvc0_grctx_init_unk46xx,
+	nvc0_grctx_init_unk47xx,
+	nvc1_grctx_init_unk58xx,
+	nvc0_grctx_init_unk60xx,
+	nvc0_grctx_init_unk64xx,
+	nvc0_grctx_init_unk78xx,
+	nvc0_grctx_init_unk80xx,
+	nvc1_grctx_init_rop,
+	NULL
+};
+
+struct nvc0_graph_init *
+nvc1_grctx_init_gpc[] = {
+	nvc1_grctx_init_gpc_0,
+	nvc0_grctx_init_gpc_1,
+	nvc1_grctx_init_tpc,
+	NULL
+};
+
+static struct nvc0_graph_mthd
+nvc1_grctx_init_mthd[] = {
+	{ 0x9097, nvc1_grctx_init_9097, },
+	{ 0x9197, nvc1_grctx_init_9197, },
+	{ 0x902d, nvc0_grctx_init_902d, },
+	{ 0x9039, nvc0_grctx_init_9039, },
+	{ 0x90c0, nvc0_grctx_init_90c0, },
+	{ 0x902d, nvc0_grctx_init_mthd_magic, },
+	{}
+};
+
+struct nouveau_oclass *
+nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xc1),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+	.main = nvc0_grctx_generate_main,
+	.mods = nvc1_grctx_generate_mods,
+	.unkn = nvc1_grctx_generate_unkn,
+	.hub  = nvc1_grctx_init_hub,
+	.gpc  = nvc1_grctx_init_gpc,
+	.icmd = nvc1_grctx_init_icmd,
+	.mthd = nvc1_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c
new file mode 100644
index 0000000..8f237b3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nvc3_grctx_init_tpc[] = {
+	{ 0x419818,   1, 0x04, 0x00000000 },
+	{ 0x41983c,   1, 0x04, 0x00038bc7 },
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x0000012a },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x00000000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419ac4,   1, 0x04, 0x0007f440 },
+	{ 0x419b00,   1, 0x04, 0x0a418820 },
+	{ 0x419b04,   1, 0x04, 0x062080e6 },
+	{ 0x419b08,   1, 0x04, 0x020398a4 },
+	{ 0x419b0c,   1, 0x04, 0x0e629062 },
+	{ 0x419b10,   1, 0x04, 0x0a418820 },
+	{ 0x419b14,   1, 0x04, 0x000000e6 },
+	{ 0x419bd0,   1, 0x04, 0x00900103 },
+	{ 0x419be0,   1, 0x04, 0x00000001 },
+	{ 0x419be4,   1, 0x04, 0x00000000 },
+	{ 0x419c00,   1, 0x04, 0x00000002 },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x00020048 },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000183 },
+	{ 0x419d20,   1, 0x04, 0x02180000 },
+	{ 0x419d24,   1, 0x04, 0x00001fff },
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419ee0,   1, 0x04, 0x00011110 },
+	{ 0x419f30,  11, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init *
+nvc3_grctx_init_gpc[] = {
+	nvc0_grctx_init_gpc_0,
+	nvc0_grctx_init_gpc_1,
+	nvc3_grctx_init_tpc,
+	NULL
+};
+
+struct nouveau_oclass *
+nvc3_grctx_oclass = &(struct nvc0_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xc3),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+	.main = nvc0_grctx_generate_main,
+	.mods = nvc0_grctx_generate_mods,
+	.unkn = nvc0_grctx_generate_unkn,
+	.hub  = nvc0_grctx_init_hub,
+	.gpc  = nvc3_grctx_init_gpc,
+	.icmd = nvc0_grctx_init_icmd,
+	.mthd = nvc0_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
new file mode 100644
index 0000000..d0d4ce3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nvc8_grctx_init_icmd[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000b2,  40, 0x01, 0x00000000 },
+	{ 0x000210,   8, 0x01, 0x00000040 },
+	{ 0x000218,   8, 0x01, 0x0000c080 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00001fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x003fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x0005e0,   5, 0x01, 0x00000022 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   1, 0x01, 0x00000001 },
+	{ 0x000639,   1, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x00097d,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x00000c48 },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00300008 },
+	{ 0x000841,   1, 0x01, 0x04000080 },
+	{ 0x000842,   1, 0x01, 0x00300008 },
+	{ 0x000843,   1, 0x01, 0x04000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x000944,   1, 0x01, 0x00000022 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000014 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvc8_grctx_init_tpc[] = {
+	{ 0x419818,   1, 0x04, 0x00000000 },
+	{ 0x41983c,   1, 0x04, 0x00038bc7 },
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x0000012a },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x00000000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419b00,   1, 0x04, 0x0a418820 },
+	{ 0x419b04,   1, 0x04, 0x062080e6 },
+	{ 0x419b08,   1, 0x04, 0x020398a4 },
+	{ 0x419b0c,   1, 0x04, 0x0e629062 },
+	{ 0x419b10,   1, 0x04, 0x0a418820 },
+	{ 0x419b14,   1, 0x04, 0x000000e6 },
+	{ 0x419bd0,   1, 0x04, 0x00900103 },
+	{ 0x419be0,   1, 0x04, 0x00000001 },
+	{ 0x419be4,   1, 0x04, 0x00000000 },
+	{ 0x419c00,   1, 0x04, 0x00000002 },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x00060048 },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000183 },
+	{ 0x419d20,   1, 0x04, 0x02180000 },
+	{ 0x419d24,   1, 0x04, 0x00001fff },
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419f50,   2, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc8_grctx_init_9197[] = {
+	{ 0x0002e4,   1, 0x04, 0x0000b001 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc8_grctx_init_9297[] = {
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x00036c,   2, 0x04, 0x00000000 },
+	{ 0x0007a4,   2, 0x04, 0x00000000 },
+	{ 0x000374,   1, 0x04, 0x00000000 },
+	{ 0x000378,   1, 0x04, 0x00000020 },
+	{}
+};
+
+static struct nvc0_graph_mthd
+nvc8_grctx_init_mthd[] = {
+	{ 0x9097, nvc1_grctx_init_9097, },
+	{ 0x9197, nvc8_grctx_init_9197, },
+	{ 0x9297, nvc8_grctx_init_9297, },
+	{ 0x902d, nvc0_grctx_init_902d, },
+	{ 0x9039, nvc0_grctx_init_9039, },
+	{ 0x90c0, nvc0_grctx_init_90c0, },
+	{ 0x902d, nvc0_grctx_init_mthd_magic, },
+	{}
+};
+
+static struct nvc0_graph_init *
+nvc8_grctx_init_gpc[] = {
+	nvc0_grctx_init_gpc_0,
+	nvc0_grctx_init_gpc_1,
+	nvc8_grctx_init_tpc,
+	NULL
+};
+
+struct nouveau_oclass *
+nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xc8),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+	.main = nvc0_grctx_generate_main,
+	.mods = nvc0_grctx_generate_mods,
+	.unkn = nvc0_grctx_generate_unkn,
+	.hub  = nvc0_grctx_init_hub,
+	.gpc  = nvc8_grctx_init_gpc,
+	.icmd = nvc8_grctx_init_icmd,
+	.mthd = nvc8_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
new file mode 100644
index 0000000..438e784
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+struct nvc0_graph_init
+nvd7_grctx_init_unk40xx[] = {
+	{ 0x404004,  10, 0x04, 0x00000000 },
+	{ 0x404044,   1, 0x04, 0x00000000 },
+	{ 0x404094,   1, 0x04, 0x00000000 },
+	{ 0x404098,  12, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf0000087 },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404130,   1, 0x04, 0x00000000 },
+	{ 0x404134,   1, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x404168,   1, 0x04, 0x00000000 },
+	{ 0x404178,   2, 0x04, 0x00000000 },
+	{ 0x404200,   8, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_unk58xx[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180324 },
+	{ 0x405834,   1, 0x04, 0x08000000 },
+	{ 0x405838,   1, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_unk64xx[] = {
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   3, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x801a0078 },
+	{ 0x4064c4,   1, 0x04, 0x00c9ffff },
+	{ 0x4064d0,   8, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_gpc_0[] = {
+	{ 0x418380,   1, 0x04, 0x00000016 },
+	{ 0x418400,   1, 0x04, 0x38004e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x02200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{ 0x418600,   1, 0x04, 0x0000001f },
+	{ 0x418684,   1, 0x04, 0x0000000f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   3, 0x04, 0x00000000 },
+	{ 0x418800,   1, 0x04, 0x7006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100018 },
+	{ 0x41891c,   1, 0x04, 0x00ff00ff },
+	{ 0x418924,   1, 0x04, 0x00000000 },
+	{ 0x418928,   1, 0x04, 0x00ffff00 },
+	{ 0x41892c,   1, 0x04, 0x0000ff00 },
+	{ 0x418b00,   1, 0x04, 0x00000006 },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c6c,   1, 0x04, 0x00000001 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{ 0x419000,   1, 0x04, 0x00000780 },
+	{ 0x419004,   2, 0x04, 0x00000000 },
+	{ 0x419014,   1, 0x04, 0x00000004 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_tpc[] = {
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x00000129 },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x00008000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419ac4,   1, 0x04, 0x0017f440 },
+	{ 0x419c00,   1, 0x04, 0x0000000a },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3efbefbe },
+	{ 0x419cb0,   1, 0x04, 0x00020048 },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000183 },
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419ee0,   1, 0x04, 0x00010110 },
+	{ 0x419f30,  11, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_unk[] = {
+	{ 0x41be24,   1, 0x04, 0x00000002 },
+	{ 0x41bec0,   1, 0x04, 0x12180000 },
+	{ 0x41bec4,   1, 0x04, 0x00003fff },
+	{ 0x41bee4,   1, 0x04, 0x03240218 },
+	{ 0x41bf00,   1, 0x04, 0x0a418820 },
+	{ 0x41bf04,   1, 0x04, 0x062080e6 },
+	{ 0x41bf08,   1, 0x04, 0x020398a4 },
+	{ 0x41bf0c,   1, 0x04, 0x0e629062 },
+	{ 0x41bf10,   1, 0x04, 0x0a418820 },
+	{ 0x41bf14,   1, 0x04, 0x000000e6 },
+	{ 0x41bfd0,   1, 0x04, 0x00900103 },
+	{ 0x41bfe0,   1, 0x04, 0x00400001 },
+	{ 0x41bfe4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static void
+nvd7_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+	u32 magic[GPC_MAX][2];
+	u32 offset;
+	int gpc;
+
+	mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+	mmio_list(0x40800c, 0x00000000,  8, 1);
+	mmio_list(0x408010, 0x80000000,  0, 0);
+	mmio_list(0x419004, 0x00000000,  8, 1);
+	mmio_list(0x419008, 0x00000000,  0, 0);
+	mmio_list(0x408004, 0x00000000,  8, 0);
+	mmio_list(0x408008, 0x80000018,  0, 0);
+	mmio_list(0x418808, 0x00000000,  8, 0);
+	mmio_list(0x41880c, 0x80000018,  0, 0);
+	mmio_list(0x418810, 0x80000000, 12, 2);
+	mmio_list(0x419848, 0x10000000, 12, 2);
+
+	mmio_list(0x405830, 0x02180324,  0, 0);
+	mmio_list(0x4064c4, 0x00c9ffff,  0, 0);
+
+	for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+		u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
+		u16 magic1 = 0x0324 * priv->tpc_nr[gpc];
+		magic[gpc][0]  = 0x10000000 | (magic0 << 16) | offset;
+		magic[gpc][1]  = 0x00000000 | (magic1 << 16);
+		offset += 0x0324 * priv->tpc_nr[gpc];
+	}
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
+		mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
+		offset += 0x07ff * priv->tpc_nr[gpc];
+	}
+	mmio_list(0x17e91c, 0x03060609, 0, 0); /* different from kepler */
+}
+
+void
+nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+	int i;
+
+	nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+
+	for (i = 0; oclass->hub[i]; i++)
+		nvc0_graph_mmio(priv, oclass->hub[i]);
+	for (i = 0; oclass->gpc[i]; i++)
+		nvc0_graph_mmio(priv, oclass->gpc[i]);
+
+	nv_wr32(priv, 0x404154, 0x00000000);
+
+	oclass->mods(priv, info);
+	oclass->unkn(priv);
+
+	nvc0_grctx_generate_tpcid(priv);
+	nvc0_grctx_generate_r406028(priv);
+	nvc0_grctx_generate_r4060a8(priv);
+	nve4_grctx_generate_r418bb8(priv);
+	nvc0_grctx_generate_r406800(priv);
+
+	for (i = 0; i < 8; i++)
+		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+
+	nvc0_graph_icmd(priv, oclass->icmd);
+	nv_wr32(priv, 0x404154, 0x00000400);
+	nvc0_graph_mthd(priv, oclass->mthd);
+	nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
+}
+
+
+static struct nvc0_graph_init *
+nvd7_grctx_init_hub[] = {
+	nvc0_grctx_init_base,
+	nvd7_grctx_init_unk40xx,
+	nvc0_grctx_init_unk44xx,
+	nvc0_grctx_init_unk46xx,
+	nvc0_grctx_init_unk47xx,
+	nvd7_grctx_init_unk58xx,
+	nvc0_grctx_init_unk60xx,
+	nvd7_grctx_init_unk64xx,
+	nvc0_grctx_init_unk78xx,
+	nvc0_grctx_init_unk80xx,
+	nvd9_grctx_init_rop,
+};
+
+struct nvc0_graph_init *
+nvd7_grctx_init_gpc[] = {
+	nvd7_grctx_init_gpc_0,
+	nvc0_grctx_init_gpc_1,
+	nvd7_grctx_init_tpc,
+	nvd7_grctx_init_unk,
+	NULL
+};
+
+struct nouveau_oclass *
+nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xd7),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+	.main = nvd7_grctx_generate_main,
+	.mods = nvd7_grctx_generate_mods,
+	.unkn = nve4_grctx_generate_unkn,
+	.hub  = nvd7_grctx_init_hub,
+	.gpc  = nvd7_grctx_init_gpc,
+	.icmd = nvd9_grctx_init_icmd,
+	.mthd = nvd9_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
new file mode 100644
index 0000000..818a475
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+struct nvc0_graph_init
+nvd9_grctx_init_90c0[] = {
+	{ 0x002700,   4, 0x40, 0x00000000 },
+	{ 0x002720,   4, 0x40, 0x00000000 },
+	{ 0x002704,   4, 0x40, 0x00000000 },
+	{ 0x002724,   4, 0x40, 0x00000000 },
+	{ 0x002708,   4, 0x40, 0x00000000 },
+	{ 0x002728,   4, 0x40, 0x00000000 },
+	{ 0x00270c,   8, 0x20, 0x00000000 },
+	{ 0x002710,   4, 0x40, 0x00014000 },
+	{ 0x002730,   4, 0x40, 0x00014000 },
+	{ 0x002714,   4, 0x40, 0x00000040 },
+	{ 0x002734,   4, 0x40, 0x00000040 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x000758,   1, 0x04, 0x00000100 },
+	{ 0x0002c4,   1, 0x04, 0x00000000 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x000204,   3, 0x04, 0x00000000 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{ 0x00024c,   1, 0x04, 0x00000000 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x001664,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvd9_grctx_init_icmd[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000b2,  40, 0x01, 0x00000000 },
+	{ 0x000210,   8, 0x01, 0x00000040 },
+	{ 0x000400,  24, 0x01, 0x00000040 },
+	{ 0x000218,   8, 0x01, 0x0000c080 },
+	{ 0x000440,  24, 0x01, 0x0000c080 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00001fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x003fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x0005e0,   5, 0x01, 0x00000022 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   1, 0x01, 0x00000001 },
+	{ 0x000639,   1, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x00097d,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x00000c48 },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00300008 },
+	{ 0x000841,   1, 0x01, 0x04000080 },
+	{ 0x000842,   1, 0x01, 0x00300008 },
+	{ 0x000843,   1, 0x01, 0x04000080 },
+	{ 0x000818,   8, 0x01, 0x00000000 },
+	{ 0x000848,  16, 0x01, 0x00000000 },
+	{ 0x000738,   1, 0x01, 0x00000000 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x000944,   1, 0x01, 0x00000022 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000014 },
+	{ 0x000351,   1, 0x01, 0x00000100 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095d,   1, 0x01, 0x00000001 },
+	{ 0x00082b,   1, 0x01, 0x00000004 },
+	{ 0x000942,   1, 0x01, 0x00010001 },
+	{ 0x000943,   1, 0x01, 0x00000001 },
+	{ 0x0007c5,   1, 0x01, 0x00010001 },
+	{ 0x000834,   1, 0x01, 0x00000001 },
+	{ 0x0007c7,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x00080c,   1, 0x01, 0x00000002 },
+	{ 0x00080d,   2, 0x01, 0x00000100 },
+	{ 0x00080f,   1, 0x01, 0x00000001 },
+	{ 0x000823,   1, 0x01, 0x00000002 },
+	{ 0x000824,   2, 0x01, 0x00000100 },
+	{ 0x000826,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+struct nvc0_graph_init
+nvd9_grctx_init_unk40xx[] = {
+	{ 0x404004,  11, 0x04, 0x00000000 },
+	{ 0x404044,   1, 0x04, 0x00000000 },
+	{ 0x404094,   1, 0x04, 0x00000000 },
+	{ 0x404098,  12, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf0000087 },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404130,   1, 0x04, 0x00000000 },
+	{ 0x404134,   1, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x404168,   1, 0x04, 0x00000000 },
+	{ 0x404178,   2, 0x04, 0x00000000 },
+	{ 0x404200,   8, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd9_grctx_init_unk58xx[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180218 },
+	{ 0x405834,   1, 0x04, 0x08000000 },
+	{ 0x405838,   1, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd9_grctx_init_unk64xx[] = {
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   3, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x80140078 },
+	{ 0x4064c4,   1, 0x04, 0x0086ffff },
+	{}
+};
+
+struct nvc0_graph_init
+nvd9_grctx_init_rop[] = {
+	{ 0x408800,   1, 0x04, 0x02802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1043e005 },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x1043e005 },
+	{ 0x408908,   1, 0x04, 0x00c8102f },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd9_grctx_init_gpc_0[] = {
+	{ 0x418380,   1, 0x04, 0x00000016 },
+	{ 0x418400,   1, 0x04, 0x38004e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x02200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{ 0x418600,   1, 0x04, 0x0000001f },
+	{ 0x418684,   1, 0x04, 0x0000000f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   3, 0x04, 0x00000000 },
+	{ 0x418800,   1, 0x04, 0x7006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00008442 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100008 },
+	{ 0x41891c,   1, 0x04, 0x00ff00ff },
+	{ 0x418924,   1, 0x04, 0x00000000 },
+	{ 0x418928,   1, 0x04, 0x00ffff00 },
+	{ 0x41892c,   1, 0x04, 0x0000ff00 },
+	{ 0x418b00,   1, 0x04, 0x00000006 },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c6c,   1, 0x04, 0x00000001 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{ 0x419000,   1, 0x04, 0x00000780 },
+	{ 0x419004,   2, 0x04, 0x00000000 },
+	{ 0x419014,   1, 0x04, 0x00000004 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd9_grctx_init_tpc[] = {
+	{ 0x419818,   1, 0x04, 0x00000000 },
+	{ 0x41983c,   1, 0x04, 0x00038bc7 },
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x00000129 },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{ 0x419a00,   1, 0x04, 0x000001f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000023 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x00000000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419ac4,   1, 0x04, 0x0017f440 },
+	{ 0x419b00,   1, 0x04, 0x0a418820 },
+	{ 0x419b04,   1, 0x04, 0x062080e6 },
+	{ 0x419b08,   1, 0x04, 0x020398a4 },
+	{ 0x419b0c,   1, 0x04, 0x0e629062 },
+	{ 0x419b10,   1, 0x04, 0x0a418820 },
+	{ 0x419b14,   1, 0x04, 0x000000e6 },
+	{ 0x419bd0,   1, 0x04, 0x00900103 },
+	{ 0x419be0,   1, 0x04, 0x00400001 },
+	{ 0x419be4,   1, 0x04, 0x00000000 },
+	{ 0x419c00,   1, 0x04, 0x0000000a },
+	{ 0x419c04,   1, 0x04, 0x00000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3cf3cf3c },
+	{ 0x419cb0,   1, 0x04, 0x00020048 },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000183 },
+	{ 0x419d20,   1, 0x04, 0x12180000 },
+	{ 0x419d24,   1, 0x04, 0x00001fff },
+	{ 0x419d44,   1, 0x04, 0x02180218 },
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000002 },
+	{ 0x419e44,   1, 0x04, 0x001beff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000000f },
+	{ 0x419e50,  17, 0x04, 0x00000000 },
+	{ 0x419e98,   1, 0x04, 0x00000000 },
+	{ 0x419ee0,   1, 0x04, 0x00010110 },
+	{ 0x419f30,  11, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init *
+nvd9_grctx_init_hub[] = {
+	nvc0_grctx_init_base,
+	nvd9_grctx_init_unk40xx,
+	nvc0_grctx_init_unk44xx,
+	nvc0_grctx_init_unk46xx,
+	nvc0_grctx_init_unk47xx,
+	nvd9_grctx_init_unk58xx,
+	nvc0_grctx_init_unk60xx,
+	nvd9_grctx_init_unk64xx,
+	nvc0_grctx_init_unk78xx,
+	nvc0_grctx_init_unk80xx,
+	nvd9_grctx_init_rop,
+};
+
+struct nvc0_graph_init *
+nvd9_grctx_init_gpc[] = {
+	nvd9_grctx_init_gpc_0,
+	nvc0_grctx_init_gpc_1,
+	nvd9_grctx_init_tpc,
+	NULL
+};
+
+struct nvc0_graph_init
+nvd9_grctx_init_mthd_magic[] = {
+	{ 0x3410, 1, 0x04, 0x80002006 },
+	{}
+};
+
+struct nvc0_graph_mthd
+nvd9_grctx_init_mthd[] = {
+	{ 0x9097, nvc1_grctx_init_9097, },
+	{ 0x9197, nvc8_grctx_init_9197, },
+	{ 0x9297, nvc8_grctx_init_9297, },
+	{ 0x902d, nvc0_grctx_init_902d, },
+	{ 0x9039, nvc0_grctx_init_9039, },
+	{ 0x90c0, nvd9_grctx_init_90c0, },
+	{ 0x902d, nvd9_grctx_init_mthd_magic, },
+	{}
+};
+
+struct nouveau_oclass *
+nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xd9),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+	.main = nvc0_grctx_generate_main,
+	.mods = nvc1_grctx_generate_mods,
+	.unkn = nvc1_grctx_generate_unkn,
+	.hub  = nvd9_grctx_init_hub,
+	.gpc  = nvd9_grctx_init_gpc,
+	.icmd = nvd9_grctx_init_icmd,
+	.mthd = nvd9_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
deleted file mode 100644
index ae27dae..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
+++ /dev/null
@@ -1,2793 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-static void
-nve0_grctx_generate_icmd(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x400208, 0x80000000);
-	nv_icmd(priv, 0x001000, 0x00000004);
-	nv_icmd(priv, 0x000039, 0x00000000);
-	nv_icmd(priv, 0x00003a, 0x00000000);
-	nv_icmd(priv, 0x00003b, 0x00000000);
-	nv_icmd(priv, 0x0000a9, 0x0000ffff);
-	nv_icmd(priv, 0x000038, 0x0fac6881);
-	nv_icmd(priv, 0x00003d, 0x00000001);
-	nv_icmd(priv, 0x0000e8, 0x00000400);
-	nv_icmd(priv, 0x0000e9, 0x00000400);
-	nv_icmd(priv, 0x0000ea, 0x00000400);
-	nv_icmd(priv, 0x0000eb, 0x00000400);
-	nv_icmd(priv, 0x0000ec, 0x00000400);
-	nv_icmd(priv, 0x0000ed, 0x00000400);
-	nv_icmd(priv, 0x0000ee, 0x00000400);
-	nv_icmd(priv, 0x0000ef, 0x00000400);
-	nv_icmd(priv, 0x000078, 0x00000300);
-	nv_icmd(priv, 0x000079, 0x00000300);
-	nv_icmd(priv, 0x00007a, 0x00000300);
-	nv_icmd(priv, 0x00007b, 0x00000300);
-	nv_icmd(priv, 0x00007c, 0x00000300);
-	nv_icmd(priv, 0x00007d, 0x00000300);
-	nv_icmd(priv, 0x00007e, 0x00000300);
-	nv_icmd(priv, 0x00007f, 0x00000300);
-	nv_icmd(priv, 0x000050, 0x00000011);
-	nv_icmd(priv, 0x000058, 0x00000008);
-	nv_icmd(priv, 0x000059, 0x00000008);
-	nv_icmd(priv, 0x00005a, 0x00000008);
-	nv_icmd(priv, 0x00005b, 0x00000008);
-	nv_icmd(priv, 0x00005c, 0x00000008);
-	nv_icmd(priv, 0x00005d, 0x00000008);
-	nv_icmd(priv, 0x00005e, 0x00000008);
-	nv_icmd(priv, 0x00005f, 0x00000008);
-	nv_icmd(priv, 0x000208, 0x00000001);
-	nv_icmd(priv, 0x000209, 0x00000001);
-	nv_icmd(priv, 0x00020a, 0x00000001);
-	nv_icmd(priv, 0x00020b, 0x00000001);
-	nv_icmd(priv, 0x00020c, 0x00000001);
-	nv_icmd(priv, 0x00020d, 0x00000001);
-	nv_icmd(priv, 0x00020e, 0x00000001);
-	nv_icmd(priv, 0x00020f, 0x00000001);
-	nv_icmd(priv, 0x000081, 0x00000001);
-	nv_icmd(priv, 0x000085, 0x00000004);
-	nv_icmd(priv, 0x000088, 0x00000400);
-	nv_icmd(priv, 0x000090, 0x00000300);
-	nv_icmd(priv, 0x000098, 0x00001001);
-	nv_icmd(priv, 0x0000e3, 0x00000001);
-	nv_icmd(priv, 0x0000da, 0x00000001);
-	nv_icmd(priv, 0x0000f8, 0x00000003);
-	nv_icmd(priv, 0x0000fa, 0x00000001);
-	nv_icmd(priv, 0x00009f, 0x0000ffff);
-	nv_icmd(priv, 0x0000a0, 0x0000ffff);
-	nv_icmd(priv, 0x0000a1, 0x0000ffff);
-	nv_icmd(priv, 0x0000a2, 0x0000ffff);
-	nv_icmd(priv, 0x0000b1, 0x00000001);
-	nv_icmd(priv, 0x0000ad, 0x0000013e);
-	nv_icmd(priv, 0x0000e1, 0x00000010);
-	nv_icmd(priv, 0x000290, 0x00000000);
-	nv_icmd(priv, 0x000291, 0x00000000);
-	nv_icmd(priv, 0x000292, 0x00000000);
-	nv_icmd(priv, 0x000293, 0x00000000);
-	nv_icmd(priv, 0x000294, 0x00000000);
-	nv_icmd(priv, 0x000295, 0x00000000);
-	nv_icmd(priv, 0x000296, 0x00000000);
-	nv_icmd(priv, 0x000297, 0x00000000);
-	nv_icmd(priv, 0x000298, 0x00000000);
-	nv_icmd(priv, 0x000299, 0x00000000);
-	nv_icmd(priv, 0x00029a, 0x00000000);
-	nv_icmd(priv, 0x00029b, 0x00000000);
-	nv_icmd(priv, 0x00029c, 0x00000000);
-	nv_icmd(priv, 0x00029d, 0x00000000);
-	nv_icmd(priv, 0x00029e, 0x00000000);
-	nv_icmd(priv, 0x00029f, 0x00000000);
-	nv_icmd(priv, 0x0003b0, 0x00000000);
-	nv_icmd(priv, 0x0003b1, 0x00000000);
-	nv_icmd(priv, 0x0003b2, 0x00000000);
-	nv_icmd(priv, 0x0003b3, 0x00000000);
-	nv_icmd(priv, 0x0003b4, 0x00000000);
-	nv_icmd(priv, 0x0003b5, 0x00000000);
-	nv_icmd(priv, 0x0003b6, 0x00000000);
-	nv_icmd(priv, 0x0003b7, 0x00000000);
-	nv_icmd(priv, 0x0003b8, 0x00000000);
-	nv_icmd(priv, 0x0003b9, 0x00000000);
-	nv_icmd(priv, 0x0003ba, 0x00000000);
-	nv_icmd(priv, 0x0003bb, 0x00000000);
-	nv_icmd(priv, 0x0003bc, 0x00000000);
-	nv_icmd(priv, 0x0003bd, 0x00000000);
-	nv_icmd(priv, 0x0003be, 0x00000000);
-	nv_icmd(priv, 0x0003bf, 0x00000000);
-	nv_icmd(priv, 0x0002a0, 0x00000000);
-	nv_icmd(priv, 0x0002a1, 0x00000000);
-	nv_icmd(priv, 0x0002a2, 0x00000000);
-	nv_icmd(priv, 0x0002a3, 0x00000000);
-	nv_icmd(priv, 0x0002a4, 0x00000000);
-	nv_icmd(priv, 0x0002a5, 0x00000000);
-	nv_icmd(priv, 0x0002a6, 0x00000000);
-	nv_icmd(priv, 0x0002a7, 0x00000000);
-	nv_icmd(priv, 0x0002a8, 0x00000000);
-	nv_icmd(priv, 0x0002a9, 0x00000000);
-	nv_icmd(priv, 0x0002aa, 0x00000000);
-	nv_icmd(priv, 0x0002ab, 0x00000000);
-	nv_icmd(priv, 0x0002ac, 0x00000000);
-	nv_icmd(priv, 0x0002ad, 0x00000000);
-	nv_icmd(priv, 0x0002ae, 0x00000000);
-	nv_icmd(priv, 0x0002af, 0x00000000);
-	nv_icmd(priv, 0x000420, 0x00000000);
-	nv_icmd(priv, 0x000421, 0x00000000);
-	nv_icmd(priv, 0x000422, 0x00000000);
-	nv_icmd(priv, 0x000423, 0x00000000);
-	nv_icmd(priv, 0x000424, 0x00000000);
-	nv_icmd(priv, 0x000425, 0x00000000);
-	nv_icmd(priv, 0x000426, 0x00000000);
-	nv_icmd(priv, 0x000427, 0x00000000);
-	nv_icmd(priv, 0x000428, 0x00000000);
-	nv_icmd(priv, 0x000429, 0x00000000);
-	nv_icmd(priv, 0x00042a, 0x00000000);
-	nv_icmd(priv, 0x00042b, 0x00000000);
-	nv_icmd(priv, 0x00042c, 0x00000000);
-	nv_icmd(priv, 0x00042d, 0x00000000);
-	nv_icmd(priv, 0x00042e, 0x00000000);
-	nv_icmd(priv, 0x00042f, 0x00000000);
-	nv_icmd(priv, 0x0002b0, 0x00000000);
-	nv_icmd(priv, 0x0002b1, 0x00000000);
-	nv_icmd(priv, 0x0002b2, 0x00000000);
-	nv_icmd(priv, 0x0002b3, 0x00000000);
-	nv_icmd(priv, 0x0002b4, 0x00000000);
-	nv_icmd(priv, 0x0002b5, 0x00000000);
-	nv_icmd(priv, 0x0002b6, 0x00000000);
-	nv_icmd(priv, 0x0002b7, 0x00000000);
-	nv_icmd(priv, 0x0002b8, 0x00000000);
-	nv_icmd(priv, 0x0002b9, 0x00000000);
-	nv_icmd(priv, 0x0002ba, 0x00000000);
-	nv_icmd(priv, 0x0002bb, 0x00000000);
-	nv_icmd(priv, 0x0002bc, 0x00000000);
-	nv_icmd(priv, 0x0002bd, 0x00000000);
-	nv_icmd(priv, 0x0002be, 0x00000000);
-	nv_icmd(priv, 0x0002bf, 0x00000000);
-	nv_icmd(priv, 0x000430, 0x00000000);
-	nv_icmd(priv, 0x000431, 0x00000000);
-	nv_icmd(priv, 0x000432, 0x00000000);
-	nv_icmd(priv, 0x000433, 0x00000000);
-	nv_icmd(priv, 0x000434, 0x00000000);
-	nv_icmd(priv, 0x000435, 0x00000000);
-	nv_icmd(priv, 0x000436, 0x00000000);
-	nv_icmd(priv, 0x000437, 0x00000000);
-	nv_icmd(priv, 0x000438, 0x00000000);
-	nv_icmd(priv, 0x000439, 0x00000000);
-	nv_icmd(priv, 0x00043a, 0x00000000);
-	nv_icmd(priv, 0x00043b, 0x00000000);
-	nv_icmd(priv, 0x00043c, 0x00000000);
-	nv_icmd(priv, 0x00043d, 0x00000000);
-	nv_icmd(priv, 0x00043e, 0x00000000);
-	nv_icmd(priv, 0x00043f, 0x00000000);
-	nv_icmd(priv, 0x0002c0, 0x00000000);
-	nv_icmd(priv, 0x0002c1, 0x00000000);
-	nv_icmd(priv, 0x0002c2, 0x00000000);
-	nv_icmd(priv, 0x0002c3, 0x00000000);
-	nv_icmd(priv, 0x0002c4, 0x00000000);
-	nv_icmd(priv, 0x0002c5, 0x00000000);
-	nv_icmd(priv, 0x0002c6, 0x00000000);
-	nv_icmd(priv, 0x0002c7, 0x00000000);
-	nv_icmd(priv, 0x0002c8, 0x00000000);
-	nv_icmd(priv, 0x0002c9, 0x00000000);
-	nv_icmd(priv, 0x0002ca, 0x00000000);
-	nv_icmd(priv, 0x0002cb, 0x00000000);
-	nv_icmd(priv, 0x0002cc, 0x00000000);
-	nv_icmd(priv, 0x0002cd, 0x00000000);
-	nv_icmd(priv, 0x0002ce, 0x00000000);
-	nv_icmd(priv, 0x0002cf, 0x00000000);
-	nv_icmd(priv, 0x0004d0, 0x00000000);
-	nv_icmd(priv, 0x0004d1, 0x00000000);
-	nv_icmd(priv, 0x0004d2, 0x00000000);
-	nv_icmd(priv, 0x0004d3, 0x00000000);
-	nv_icmd(priv, 0x0004d4, 0x00000000);
-	nv_icmd(priv, 0x0004d5, 0x00000000);
-	nv_icmd(priv, 0x0004d6, 0x00000000);
-	nv_icmd(priv, 0x0004d7, 0x00000000);
-	nv_icmd(priv, 0x0004d8, 0x00000000);
-	nv_icmd(priv, 0x0004d9, 0x00000000);
-	nv_icmd(priv, 0x0004da, 0x00000000);
-	nv_icmd(priv, 0x0004db, 0x00000000);
-	nv_icmd(priv, 0x0004dc, 0x00000000);
-	nv_icmd(priv, 0x0004dd, 0x00000000);
-	nv_icmd(priv, 0x0004de, 0x00000000);
-	nv_icmd(priv, 0x0004df, 0x00000000);
-	nv_icmd(priv, 0x000720, 0x00000000);
-	nv_icmd(priv, 0x000721, 0x00000000);
-	nv_icmd(priv, 0x000722, 0x00000000);
-	nv_icmd(priv, 0x000723, 0x00000000);
-	nv_icmd(priv, 0x000724, 0x00000000);
-	nv_icmd(priv, 0x000725, 0x00000000);
-	nv_icmd(priv, 0x000726, 0x00000000);
-	nv_icmd(priv, 0x000727, 0x00000000);
-	nv_icmd(priv, 0x000728, 0x00000000);
-	nv_icmd(priv, 0x000729, 0x00000000);
-	nv_icmd(priv, 0x00072a, 0x00000000);
-	nv_icmd(priv, 0x00072b, 0x00000000);
-	nv_icmd(priv, 0x00072c, 0x00000000);
-	nv_icmd(priv, 0x00072d, 0x00000000);
-	nv_icmd(priv, 0x00072e, 0x00000000);
-	nv_icmd(priv, 0x00072f, 0x00000000);
-	nv_icmd(priv, 0x0008c0, 0x00000000);
-	nv_icmd(priv, 0x0008c1, 0x00000000);
-	nv_icmd(priv, 0x0008c2, 0x00000000);
-	nv_icmd(priv, 0x0008c3, 0x00000000);
-	nv_icmd(priv, 0x0008c4, 0x00000000);
-	nv_icmd(priv, 0x0008c5, 0x00000000);
-	nv_icmd(priv, 0x0008c6, 0x00000000);
-	nv_icmd(priv, 0x0008c7, 0x00000000);
-	nv_icmd(priv, 0x0008c8, 0x00000000);
-	nv_icmd(priv, 0x0008c9, 0x00000000);
-	nv_icmd(priv, 0x0008ca, 0x00000000);
-	nv_icmd(priv, 0x0008cb, 0x00000000);
-	nv_icmd(priv, 0x0008cc, 0x00000000);
-	nv_icmd(priv, 0x0008cd, 0x00000000);
-	nv_icmd(priv, 0x0008ce, 0x00000000);
-	nv_icmd(priv, 0x0008cf, 0x00000000);
-	nv_icmd(priv, 0x000890, 0x00000000);
-	nv_icmd(priv, 0x000891, 0x00000000);
-	nv_icmd(priv, 0x000892, 0x00000000);
-	nv_icmd(priv, 0x000893, 0x00000000);
-	nv_icmd(priv, 0x000894, 0x00000000);
-	nv_icmd(priv, 0x000895, 0x00000000);
-	nv_icmd(priv, 0x000896, 0x00000000);
-	nv_icmd(priv, 0x000897, 0x00000000);
-	nv_icmd(priv, 0x000898, 0x00000000);
-	nv_icmd(priv, 0x000899, 0x00000000);
-	nv_icmd(priv, 0x00089a, 0x00000000);
-	nv_icmd(priv, 0x00089b, 0x00000000);
-	nv_icmd(priv, 0x00089c, 0x00000000);
-	nv_icmd(priv, 0x00089d, 0x00000000);
-	nv_icmd(priv, 0x00089e, 0x00000000);
-	nv_icmd(priv, 0x00089f, 0x00000000);
-	nv_icmd(priv, 0x0008e0, 0x00000000);
-	nv_icmd(priv, 0x0008e1, 0x00000000);
-	nv_icmd(priv, 0x0008e2, 0x00000000);
-	nv_icmd(priv, 0x0008e3, 0x00000000);
-	nv_icmd(priv, 0x0008e4, 0x00000000);
-	nv_icmd(priv, 0x0008e5, 0x00000000);
-	nv_icmd(priv, 0x0008e6, 0x00000000);
-	nv_icmd(priv, 0x0008e7, 0x00000000);
-	nv_icmd(priv, 0x0008e8, 0x00000000);
-	nv_icmd(priv, 0x0008e9, 0x00000000);
-	nv_icmd(priv, 0x0008ea, 0x00000000);
-	nv_icmd(priv, 0x0008eb, 0x00000000);
-	nv_icmd(priv, 0x0008ec, 0x00000000);
-	nv_icmd(priv, 0x0008ed, 0x00000000);
-	nv_icmd(priv, 0x0008ee, 0x00000000);
-	nv_icmd(priv, 0x0008ef, 0x00000000);
-	nv_icmd(priv, 0x0008a0, 0x00000000);
-	nv_icmd(priv, 0x0008a1, 0x00000000);
-	nv_icmd(priv, 0x0008a2, 0x00000000);
-	nv_icmd(priv, 0x0008a3, 0x00000000);
-	nv_icmd(priv, 0x0008a4, 0x00000000);
-	nv_icmd(priv, 0x0008a5, 0x00000000);
-	nv_icmd(priv, 0x0008a6, 0x00000000);
-	nv_icmd(priv, 0x0008a7, 0x00000000);
-	nv_icmd(priv, 0x0008a8, 0x00000000);
-	nv_icmd(priv, 0x0008a9, 0x00000000);
-	nv_icmd(priv, 0x0008aa, 0x00000000);
-	nv_icmd(priv, 0x0008ab, 0x00000000);
-	nv_icmd(priv, 0x0008ac, 0x00000000);
-	nv_icmd(priv, 0x0008ad, 0x00000000);
-	nv_icmd(priv, 0x0008ae, 0x00000000);
-	nv_icmd(priv, 0x0008af, 0x00000000);
-	nv_icmd(priv, 0x0008f0, 0x00000000);
-	nv_icmd(priv, 0x0008f1, 0x00000000);
-	nv_icmd(priv, 0x0008f2, 0x00000000);
-	nv_icmd(priv, 0x0008f3, 0x00000000);
-	nv_icmd(priv, 0x0008f4, 0x00000000);
-	nv_icmd(priv, 0x0008f5, 0x00000000);
-	nv_icmd(priv, 0x0008f6, 0x00000000);
-	nv_icmd(priv, 0x0008f7, 0x00000000);
-	nv_icmd(priv, 0x0008f8, 0x00000000);
-	nv_icmd(priv, 0x0008f9, 0x00000000);
-	nv_icmd(priv, 0x0008fa, 0x00000000);
-	nv_icmd(priv, 0x0008fb, 0x00000000);
-	nv_icmd(priv, 0x0008fc, 0x00000000);
-	nv_icmd(priv, 0x0008fd, 0x00000000);
-	nv_icmd(priv, 0x0008fe, 0x00000000);
-	nv_icmd(priv, 0x0008ff, 0x00000000);
-	nv_icmd(priv, 0x00094c, 0x000000ff);
-	nv_icmd(priv, 0x00094d, 0xffffffff);
-	nv_icmd(priv, 0x00094e, 0x00000002);
-	nv_icmd(priv, 0x0002ec, 0x00000001);
-	nv_icmd(priv, 0x000303, 0x00000001);
-	nv_icmd(priv, 0x0002e6, 0x00000001);
-	nv_icmd(priv, 0x000466, 0x00000052);
-	nv_icmd(priv, 0x000301, 0x3f800000);
-	nv_icmd(priv, 0x000304, 0x30201000);
-	nv_icmd(priv, 0x000305, 0x70605040);
-	nv_icmd(priv, 0x000306, 0xb8a89888);
-	nv_icmd(priv, 0x000307, 0xf8e8d8c8);
-	nv_icmd(priv, 0x00030a, 0x00ffff00);
-	nv_icmd(priv, 0x00030b, 0x0000001a);
-	nv_icmd(priv, 0x00030c, 0x00000001);
-	nv_icmd(priv, 0x000318, 0x00000001);
-	nv_icmd(priv, 0x000340, 0x00000000);
-	nv_icmd(priv, 0x000375, 0x00000001);
-	nv_icmd(priv, 0x00037d, 0x00000006);
-	nv_icmd(priv, 0x0003a0, 0x00000002);
-	nv_icmd(priv, 0x0003aa, 0x00000001);
-	nv_icmd(priv, 0x0003a9, 0x00000001);
-	nv_icmd(priv, 0x000380, 0x00000001);
-	nv_icmd(priv, 0x000383, 0x00000011);
-	nv_icmd(priv, 0x000360, 0x00000040);
-	nv_icmd(priv, 0x000366, 0x00000000);
-	nv_icmd(priv, 0x000367, 0x00000000);
-	nv_icmd(priv, 0x000368, 0x00000fff);
-	nv_icmd(priv, 0x000370, 0x00000000);
-	nv_icmd(priv, 0x000371, 0x00000000);
-	nv_icmd(priv, 0x000372, 0x000fffff);
-	nv_icmd(priv, 0x00037a, 0x00000012);
-	nv_icmd(priv, 0x000619, 0x00000003);
-	nv_icmd(priv, 0x000811, 0x00000003);
-	nv_icmd(priv, 0x000812, 0x00000004);
-	nv_icmd(priv, 0x000813, 0x00000006);
-	nv_icmd(priv, 0x000814, 0x00000008);
-	nv_icmd(priv, 0x000815, 0x0000000b);
-	nv_icmd(priv, 0x000800, 0x00000001);
-	nv_icmd(priv, 0x000801, 0x00000001);
-	nv_icmd(priv, 0x000802, 0x00000001);
-	nv_icmd(priv, 0x000803, 0x00000001);
-	nv_icmd(priv, 0x000804, 0x00000001);
-	nv_icmd(priv, 0x000805, 0x00000001);
-	nv_icmd(priv, 0x000632, 0x00000001);
-	nv_icmd(priv, 0x000633, 0x00000002);
-	nv_icmd(priv, 0x000634, 0x00000003);
-	nv_icmd(priv, 0x000635, 0x00000004);
-	nv_icmd(priv, 0x000654, 0x3f800000);
-	nv_icmd(priv, 0x000657, 0x3f800000);
-	nv_icmd(priv, 0x000655, 0x3f800000);
-	nv_icmd(priv, 0x000656, 0x3f800000);
-	nv_icmd(priv, 0x0006cd, 0x3f800000);
-	nv_icmd(priv, 0x0007f5, 0x3f800000);
-	nv_icmd(priv, 0x0007dc, 0x39291909);
-	nv_icmd(priv, 0x0007dd, 0x79695949);
-	nv_icmd(priv, 0x0007de, 0xb9a99989);
-	nv_icmd(priv, 0x0007df, 0xf9e9d9c9);
-	nv_icmd(priv, 0x0007e8, 0x00003210);
-	nv_icmd(priv, 0x0007e9, 0x00007654);
-	nv_icmd(priv, 0x0007ea, 0x00000098);
-	nv_icmd(priv, 0x0007ec, 0x39291909);
-	nv_icmd(priv, 0x0007ed, 0x79695949);
-	nv_icmd(priv, 0x0007ee, 0xb9a99989);
-	nv_icmd(priv, 0x0007ef, 0xf9e9d9c9);
-	nv_icmd(priv, 0x0007f0, 0x00003210);
-	nv_icmd(priv, 0x0007f1, 0x00007654);
-	nv_icmd(priv, 0x0007f2, 0x00000098);
-	nv_icmd(priv, 0x0005a5, 0x00000001);
-	nv_icmd(priv, 0x000980, 0x00000000);
-	nv_icmd(priv, 0x000981, 0x00000000);
-	nv_icmd(priv, 0x000982, 0x00000000);
-	nv_icmd(priv, 0x000983, 0x00000000);
-	nv_icmd(priv, 0x000984, 0x00000000);
-	nv_icmd(priv, 0x000985, 0x00000000);
-	nv_icmd(priv, 0x000986, 0x00000000);
-	nv_icmd(priv, 0x000987, 0x00000000);
-	nv_icmd(priv, 0x000988, 0x00000000);
-	nv_icmd(priv, 0x000989, 0x00000000);
-	nv_icmd(priv, 0x00098a, 0x00000000);
-	nv_icmd(priv, 0x00098b, 0x00000000);
-	nv_icmd(priv, 0x00098c, 0x00000000);
-	nv_icmd(priv, 0x00098d, 0x00000000);
-	nv_icmd(priv, 0x00098e, 0x00000000);
-	nv_icmd(priv, 0x00098f, 0x00000000);
-	nv_icmd(priv, 0x000990, 0x00000000);
-	nv_icmd(priv, 0x000991, 0x00000000);
-	nv_icmd(priv, 0x000992, 0x00000000);
-	nv_icmd(priv, 0x000993, 0x00000000);
-	nv_icmd(priv, 0x000994, 0x00000000);
-	nv_icmd(priv, 0x000995, 0x00000000);
-	nv_icmd(priv, 0x000996, 0x00000000);
-	nv_icmd(priv, 0x000997, 0x00000000);
-	nv_icmd(priv, 0x000998, 0x00000000);
-	nv_icmd(priv, 0x000999, 0x00000000);
-	nv_icmd(priv, 0x00099a, 0x00000000);
-	nv_icmd(priv, 0x00099b, 0x00000000);
-	nv_icmd(priv, 0x00099c, 0x00000000);
-	nv_icmd(priv, 0x00099d, 0x00000000);
-	nv_icmd(priv, 0x00099e, 0x00000000);
-	nv_icmd(priv, 0x00099f, 0x00000000);
-	nv_icmd(priv, 0x0009a0, 0x00000000);
-	nv_icmd(priv, 0x0009a1, 0x00000000);
-	nv_icmd(priv, 0x0009a2, 0x00000000);
-	nv_icmd(priv, 0x0009a3, 0x00000000);
-	nv_icmd(priv, 0x0009a4, 0x00000000);
-	nv_icmd(priv, 0x0009a5, 0x00000000);
-	nv_icmd(priv, 0x0009a6, 0x00000000);
-	nv_icmd(priv, 0x0009a7, 0x00000000);
-	nv_icmd(priv, 0x0009a8, 0x00000000);
-	nv_icmd(priv, 0x0009a9, 0x00000000);
-	nv_icmd(priv, 0x0009aa, 0x00000000);
-	nv_icmd(priv, 0x0009ab, 0x00000000);
-	nv_icmd(priv, 0x0009ac, 0x00000000);
-	nv_icmd(priv, 0x0009ad, 0x00000000);
-	nv_icmd(priv, 0x0009ae, 0x00000000);
-	nv_icmd(priv, 0x0009af, 0x00000000);
-	nv_icmd(priv, 0x0009b0, 0x00000000);
-	nv_icmd(priv, 0x0009b1, 0x00000000);
-	nv_icmd(priv, 0x0009b2, 0x00000000);
-	nv_icmd(priv, 0x0009b3, 0x00000000);
-	nv_icmd(priv, 0x0009b4, 0x00000000);
-	nv_icmd(priv, 0x0009b5, 0x00000000);
-	nv_icmd(priv, 0x0009b6, 0x00000000);
-	nv_icmd(priv, 0x0009b7, 0x00000000);
-	nv_icmd(priv, 0x0009b8, 0x00000000);
-	nv_icmd(priv, 0x0009b9, 0x00000000);
-	nv_icmd(priv, 0x0009ba, 0x00000000);
-	nv_icmd(priv, 0x0009bb, 0x00000000);
-	nv_icmd(priv, 0x0009bc, 0x00000000);
-	nv_icmd(priv, 0x0009bd, 0x00000000);
-	nv_icmd(priv, 0x0009be, 0x00000000);
-	nv_icmd(priv, 0x0009bf, 0x00000000);
-	nv_icmd(priv, 0x0009c0, 0x00000000);
-	nv_icmd(priv, 0x0009c1, 0x00000000);
-	nv_icmd(priv, 0x0009c2, 0x00000000);
-	nv_icmd(priv, 0x0009c3, 0x00000000);
-	nv_icmd(priv, 0x0009c4, 0x00000000);
-	nv_icmd(priv, 0x0009c5, 0x00000000);
-	nv_icmd(priv, 0x0009c6, 0x00000000);
-	nv_icmd(priv, 0x0009c7, 0x00000000);
-	nv_icmd(priv, 0x0009c8, 0x00000000);
-	nv_icmd(priv, 0x0009c9, 0x00000000);
-	nv_icmd(priv, 0x0009ca, 0x00000000);
-	nv_icmd(priv, 0x0009cb, 0x00000000);
-	nv_icmd(priv, 0x0009cc, 0x00000000);
-	nv_icmd(priv, 0x0009cd, 0x00000000);
-	nv_icmd(priv, 0x0009ce, 0x00000000);
-	nv_icmd(priv, 0x0009cf, 0x00000000);
-	nv_icmd(priv, 0x0009d0, 0x00000000);
-	nv_icmd(priv, 0x0009d1, 0x00000000);
-	nv_icmd(priv, 0x0009d2, 0x00000000);
-	nv_icmd(priv, 0x0009d3, 0x00000000);
-	nv_icmd(priv, 0x0009d4, 0x00000000);
-	nv_icmd(priv, 0x0009d5, 0x00000000);
-	nv_icmd(priv, 0x0009d6, 0x00000000);
-	nv_icmd(priv, 0x0009d7, 0x00000000);
-	nv_icmd(priv, 0x0009d8, 0x00000000);
-	nv_icmd(priv, 0x0009d9, 0x00000000);
-	nv_icmd(priv, 0x0009da, 0x00000000);
-	nv_icmd(priv, 0x0009db, 0x00000000);
-	nv_icmd(priv, 0x0009dc, 0x00000000);
-	nv_icmd(priv, 0x0009dd, 0x00000000);
-	nv_icmd(priv, 0x0009de, 0x00000000);
-	nv_icmd(priv, 0x0009df, 0x00000000);
-	nv_icmd(priv, 0x0009e0, 0x00000000);
-	nv_icmd(priv, 0x0009e1, 0x00000000);
-	nv_icmd(priv, 0x0009e2, 0x00000000);
-	nv_icmd(priv, 0x0009e3, 0x00000000);
-	nv_icmd(priv, 0x0009e4, 0x00000000);
-	nv_icmd(priv, 0x0009e5, 0x00000000);
-	nv_icmd(priv, 0x0009e6, 0x00000000);
-	nv_icmd(priv, 0x0009e7, 0x00000000);
-	nv_icmd(priv, 0x0009e8, 0x00000000);
-	nv_icmd(priv, 0x0009e9, 0x00000000);
-	nv_icmd(priv, 0x0009ea, 0x00000000);
-	nv_icmd(priv, 0x0009eb, 0x00000000);
-	nv_icmd(priv, 0x0009ec, 0x00000000);
-	nv_icmd(priv, 0x0009ed, 0x00000000);
-	nv_icmd(priv, 0x0009ee, 0x00000000);
-	nv_icmd(priv, 0x0009ef, 0x00000000);
-	nv_icmd(priv, 0x0009f0, 0x00000000);
-	nv_icmd(priv, 0x0009f1, 0x00000000);
-	nv_icmd(priv, 0x0009f2, 0x00000000);
-	nv_icmd(priv, 0x0009f3, 0x00000000);
-	nv_icmd(priv, 0x0009f4, 0x00000000);
-	nv_icmd(priv, 0x0009f5, 0x00000000);
-	nv_icmd(priv, 0x0009f6, 0x00000000);
-	nv_icmd(priv, 0x0009f7, 0x00000000);
-	nv_icmd(priv, 0x0009f8, 0x00000000);
-	nv_icmd(priv, 0x0009f9, 0x00000000);
-	nv_icmd(priv, 0x0009fa, 0x00000000);
-	nv_icmd(priv, 0x0009fb, 0x00000000);
-	nv_icmd(priv, 0x0009fc, 0x00000000);
-	nv_icmd(priv, 0x0009fd, 0x00000000);
-	nv_icmd(priv, 0x0009fe, 0x00000000);
-	nv_icmd(priv, 0x0009ff, 0x00000000);
-	nv_icmd(priv, 0x000468, 0x00000004);
-	nv_icmd(priv, 0x00046c, 0x00000001);
-	nv_icmd(priv, 0x000470, 0x00000000);
-	nv_icmd(priv, 0x000471, 0x00000000);
-	nv_icmd(priv, 0x000472, 0x00000000);
-	nv_icmd(priv, 0x000473, 0x00000000);
-	nv_icmd(priv, 0x000474, 0x00000000);
-	nv_icmd(priv, 0x000475, 0x00000000);
-	nv_icmd(priv, 0x000476, 0x00000000);
-	nv_icmd(priv, 0x000477, 0x00000000);
-	nv_icmd(priv, 0x000478, 0x00000000);
-	nv_icmd(priv, 0x000479, 0x00000000);
-	nv_icmd(priv, 0x00047a, 0x00000000);
-	nv_icmd(priv, 0x00047b, 0x00000000);
-	nv_icmd(priv, 0x00047c, 0x00000000);
-	nv_icmd(priv, 0x00047d, 0x00000000);
-	nv_icmd(priv, 0x00047e, 0x00000000);
-	nv_icmd(priv, 0x00047f, 0x00000000);
-	nv_icmd(priv, 0x000480, 0x00000000);
-	nv_icmd(priv, 0x000481, 0x00000000);
-	nv_icmd(priv, 0x000482, 0x00000000);
-	nv_icmd(priv, 0x000483, 0x00000000);
-	nv_icmd(priv, 0x000484, 0x00000000);
-	nv_icmd(priv, 0x000485, 0x00000000);
-	nv_icmd(priv, 0x000486, 0x00000000);
-	nv_icmd(priv, 0x000487, 0x00000000);
-	nv_icmd(priv, 0x000488, 0x00000000);
-	nv_icmd(priv, 0x000489, 0x00000000);
-	nv_icmd(priv, 0x00048a, 0x00000000);
-	nv_icmd(priv, 0x00048b, 0x00000000);
-	nv_icmd(priv, 0x00048c, 0x00000000);
-	nv_icmd(priv, 0x00048d, 0x00000000);
-	nv_icmd(priv, 0x00048e, 0x00000000);
-	nv_icmd(priv, 0x00048f, 0x00000000);
-	nv_icmd(priv, 0x000490, 0x00000000);
-	nv_icmd(priv, 0x000491, 0x00000000);
-	nv_icmd(priv, 0x000492, 0x00000000);
-	nv_icmd(priv, 0x000493, 0x00000000);
-	nv_icmd(priv, 0x000494, 0x00000000);
-	nv_icmd(priv, 0x000495, 0x00000000);
-	nv_icmd(priv, 0x000496, 0x00000000);
-	nv_icmd(priv, 0x000497, 0x00000000);
-	nv_icmd(priv, 0x000498, 0x00000000);
-	nv_icmd(priv, 0x000499, 0x00000000);
-	nv_icmd(priv, 0x00049a, 0x00000000);
-	nv_icmd(priv, 0x00049b, 0x00000000);
-	nv_icmd(priv, 0x00049c, 0x00000000);
-	nv_icmd(priv, 0x00049d, 0x00000000);
-	nv_icmd(priv, 0x00049e, 0x00000000);
-	nv_icmd(priv, 0x00049f, 0x00000000);
-	nv_icmd(priv, 0x0004a0, 0x00000000);
-	nv_icmd(priv, 0x0004a1, 0x00000000);
-	nv_icmd(priv, 0x0004a2, 0x00000000);
-	nv_icmd(priv, 0x0004a3, 0x00000000);
-	nv_icmd(priv, 0x0004a4, 0x00000000);
-	nv_icmd(priv, 0x0004a5, 0x00000000);
-	nv_icmd(priv, 0x0004a6, 0x00000000);
-	nv_icmd(priv, 0x0004a7, 0x00000000);
-	nv_icmd(priv, 0x0004a8, 0x00000000);
-	nv_icmd(priv, 0x0004a9, 0x00000000);
-	nv_icmd(priv, 0x0004aa, 0x00000000);
-	nv_icmd(priv, 0x0004ab, 0x00000000);
-	nv_icmd(priv, 0x0004ac, 0x00000000);
-	nv_icmd(priv, 0x0004ad, 0x00000000);
-	nv_icmd(priv, 0x0004ae, 0x00000000);
-	nv_icmd(priv, 0x0004af, 0x00000000);
-	nv_icmd(priv, 0x0004b0, 0x00000000);
-	nv_icmd(priv, 0x0004b1, 0x00000000);
-	nv_icmd(priv, 0x0004b2, 0x00000000);
-	nv_icmd(priv, 0x0004b3, 0x00000000);
-	nv_icmd(priv, 0x0004b4, 0x00000000);
-	nv_icmd(priv, 0x0004b5, 0x00000000);
-	nv_icmd(priv, 0x0004b6, 0x00000000);
-	nv_icmd(priv, 0x0004b7, 0x00000000);
-	nv_icmd(priv, 0x0004b8, 0x00000000);
-	nv_icmd(priv, 0x0004b9, 0x00000000);
-	nv_icmd(priv, 0x0004ba, 0x00000000);
-	nv_icmd(priv, 0x0004bb, 0x00000000);
-	nv_icmd(priv, 0x0004bc, 0x00000000);
-	nv_icmd(priv, 0x0004bd, 0x00000000);
-	nv_icmd(priv, 0x0004be, 0x00000000);
-	nv_icmd(priv, 0x0004bf, 0x00000000);
-	nv_icmd(priv, 0x0004c0, 0x00000000);
-	nv_icmd(priv, 0x0004c1, 0x00000000);
-	nv_icmd(priv, 0x0004c2, 0x00000000);
-	nv_icmd(priv, 0x0004c3, 0x00000000);
-	nv_icmd(priv, 0x0004c4, 0x00000000);
-	nv_icmd(priv, 0x0004c5, 0x00000000);
-	nv_icmd(priv, 0x0004c6, 0x00000000);
-	nv_icmd(priv, 0x0004c7, 0x00000000);
-	nv_icmd(priv, 0x0004c8, 0x00000000);
-	nv_icmd(priv, 0x0004c9, 0x00000000);
-	nv_icmd(priv, 0x0004ca, 0x00000000);
-	nv_icmd(priv, 0x0004cb, 0x00000000);
-	nv_icmd(priv, 0x0004cc, 0x00000000);
-	nv_icmd(priv, 0x0004cd, 0x00000000);
-	nv_icmd(priv, 0x0004ce, 0x00000000);
-	nv_icmd(priv, 0x0004cf, 0x00000000);
-	nv_icmd(priv, 0x000510, 0x3f800000);
-	nv_icmd(priv, 0x000511, 0x3f800000);
-	nv_icmd(priv, 0x000512, 0x3f800000);
-	nv_icmd(priv, 0x000513, 0x3f800000);
-	nv_icmd(priv, 0x000514, 0x3f800000);
-	nv_icmd(priv, 0x000515, 0x3f800000);
-	nv_icmd(priv, 0x000516, 0x3f800000);
-	nv_icmd(priv, 0x000517, 0x3f800000);
-	nv_icmd(priv, 0x000518, 0x3f800000);
-	nv_icmd(priv, 0x000519, 0x3f800000);
-	nv_icmd(priv, 0x00051a, 0x3f800000);
-	nv_icmd(priv, 0x00051b, 0x3f800000);
-	nv_icmd(priv, 0x00051c, 0x3f800000);
-	nv_icmd(priv, 0x00051d, 0x3f800000);
-	nv_icmd(priv, 0x00051e, 0x3f800000);
-	nv_icmd(priv, 0x00051f, 0x3f800000);
-	nv_icmd(priv, 0x000520, 0x000002b6);
-	nv_icmd(priv, 0x000529, 0x00000001);
-	nv_icmd(priv, 0x000530, 0xffff0000);
-	nv_icmd(priv, 0x000531, 0xffff0000);
-	nv_icmd(priv, 0x000532, 0xffff0000);
-	nv_icmd(priv, 0x000533, 0xffff0000);
-	nv_icmd(priv, 0x000534, 0xffff0000);
-	nv_icmd(priv, 0x000535, 0xffff0000);
-	nv_icmd(priv, 0x000536, 0xffff0000);
-	nv_icmd(priv, 0x000537, 0xffff0000);
-	nv_icmd(priv, 0x000538, 0xffff0000);
-	nv_icmd(priv, 0x000539, 0xffff0000);
-	nv_icmd(priv, 0x00053a, 0xffff0000);
-	nv_icmd(priv, 0x00053b, 0xffff0000);
-	nv_icmd(priv, 0x00053c, 0xffff0000);
-	nv_icmd(priv, 0x00053d, 0xffff0000);
-	nv_icmd(priv, 0x00053e, 0xffff0000);
-	nv_icmd(priv, 0x00053f, 0xffff0000);
-	nv_icmd(priv, 0x000585, 0x0000003f);
-	nv_icmd(priv, 0x000576, 0x00000003);
-	nv_icmd(priv, 0x00057b, 0x00000059);
-	nv_icmd(priv, 0x000586, 0x00000040);
-	nv_icmd(priv, 0x000582, 0x00000080);
-	nv_icmd(priv, 0x000583, 0x00000080);
-	nv_icmd(priv, 0x0005c2, 0x00000001);
-	nv_icmd(priv, 0x000638, 0x00000001);
-	nv_icmd(priv, 0x000639, 0x00000001);
-	nv_icmd(priv, 0x00063a, 0x00000002);
-	nv_icmd(priv, 0x00063b, 0x00000001);
-	nv_icmd(priv, 0x00063c, 0x00000001);
-	nv_icmd(priv, 0x00063d, 0x00000002);
-	nv_icmd(priv, 0x00063e, 0x00000001);
-	nv_icmd(priv, 0x0008b8, 0x00000001);
-	nv_icmd(priv, 0x0008b9, 0x00000001);
-	nv_icmd(priv, 0x0008ba, 0x00000001);
-	nv_icmd(priv, 0x0008bb, 0x00000001);
-	nv_icmd(priv, 0x0008bc, 0x00000001);
-	nv_icmd(priv, 0x0008bd, 0x00000001);
-	nv_icmd(priv, 0x0008be, 0x00000001);
-	nv_icmd(priv, 0x0008bf, 0x00000001);
-	nv_icmd(priv, 0x000900, 0x00000001);
-	nv_icmd(priv, 0x000901, 0x00000001);
-	nv_icmd(priv, 0x000902, 0x00000001);
-	nv_icmd(priv, 0x000903, 0x00000001);
-	nv_icmd(priv, 0x000904, 0x00000001);
-	nv_icmd(priv, 0x000905, 0x00000001);
-	nv_icmd(priv, 0x000906, 0x00000001);
-	nv_icmd(priv, 0x000907, 0x00000001);
-	nv_icmd(priv, 0x000908, 0x00000002);
-	nv_icmd(priv, 0x000909, 0x00000002);
-	nv_icmd(priv, 0x00090a, 0x00000002);
-	nv_icmd(priv, 0x00090b, 0x00000002);
-	nv_icmd(priv, 0x00090c, 0x00000002);
-	nv_icmd(priv, 0x00090d, 0x00000002);
-	nv_icmd(priv, 0x00090e, 0x00000002);
-	nv_icmd(priv, 0x00090f, 0x00000002);
-	nv_icmd(priv, 0x000910, 0x00000001);
-	nv_icmd(priv, 0x000911, 0x00000001);
-	nv_icmd(priv, 0x000912, 0x00000001);
-	nv_icmd(priv, 0x000913, 0x00000001);
-	nv_icmd(priv, 0x000914, 0x00000001);
-	nv_icmd(priv, 0x000915, 0x00000001);
-	nv_icmd(priv, 0x000916, 0x00000001);
-	nv_icmd(priv, 0x000917, 0x00000001);
-	nv_icmd(priv, 0x000918, 0x00000001);
-	nv_icmd(priv, 0x000919, 0x00000001);
-	nv_icmd(priv, 0x00091a, 0x00000001);
-	nv_icmd(priv, 0x00091b, 0x00000001);
-	nv_icmd(priv, 0x00091c, 0x00000001);
-	nv_icmd(priv, 0x00091d, 0x00000001);
-	nv_icmd(priv, 0x00091e, 0x00000001);
-	nv_icmd(priv, 0x00091f, 0x00000001);
-	nv_icmd(priv, 0x000920, 0x00000002);
-	nv_icmd(priv, 0x000921, 0x00000002);
-	nv_icmd(priv, 0x000922, 0x00000002);
-	nv_icmd(priv, 0x000923, 0x00000002);
-	nv_icmd(priv, 0x000924, 0x00000002);
-	nv_icmd(priv, 0x000925, 0x00000002);
-	nv_icmd(priv, 0x000926, 0x00000002);
-	nv_icmd(priv, 0x000927, 0x00000002);
-	nv_icmd(priv, 0x000928, 0x00000001);
-	nv_icmd(priv, 0x000929, 0x00000001);
-	nv_icmd(priv, 0x00092a, 0x00000001);
-	nv_icmd(priv, 0x00092b, 0x00000001);
-	nv_icmd(priv, 0x00092c, 0x00000001);
-	nv_icmd(priv, 0x00092d, 0x00000001);
-	nv_icmd(priv, 0x00092e, 0x00000001);
-	nv_icmd(priv, 0x00092f, 0x00000001);
-	nv_icmd(priv, 0x000648, 0x00000001);
-	nv_icmd(priv, 0x000649, 0x00000001);
-	nv_icmd(priv, 0x00064a, 0x00000001);
-	nv_icmd(priv, 0x00064b, 0x00000001);
-	nv_icmd(priv, 0x00064c, 0x00000001);
-	nv_icmd(priv, 0x00064d, 0x00000001);
-	nv_icmd(priv, 0x00064e, 0x00000001);
-	nv_icmd(priv, 0x00064f, 0x00000001);
-	nv_icmd(priv, 0x000650, 0x00000001);
-	nv_icmd(priv, 0x000658, 0x0000000f);
-	nv_icmd(priv, 0x0007ff, 0x0000000a);
-	nv_icmd(priv, 0x00066a, 0x40000000);
-	nv_icmd(priv, 0x00066b, 0x10000000);
-	nv_icmd(priv, 0x00066c, 0xffff0000);
-	nv_icmd(priv, 0x00066d, 0xffff0000);
-	nv_icmd(priv, 0x0007af, 0x00000008);
-	nv_icmd(priv, 0x0007b0, 0x00000008);
-	nv_icmd(priv, 0x0007f6, 0x00000001);
-	nv_icmd(priv, 0x0006b2, 0x00000055);
-	nv_icmd(priv, 0x0007ad, 0x00000003);
-	nv_icmd(priv, 0x000937, 0x00000001);
-	nv_icmd(priv, 0x000971, 0x00000008);
-	nv_icmd(priv, 0x000972, 0x00000040);
-	nv_icmd(priv, 0x000973, 0x0000012c);
-	nv_icmd(priv, 0x00097c, 0x00000040);
-	nv_icmd(priv, 0x000979, 0x00000003);
-	nv_icmd(priv, 0x000975, 0x00000020);
-	nv_icmd(priv, 0x000976, 0x00000001);
-	nv_icmd(priv, 0x000977, 0x00000020);
-	nv_icmd(priv, 0x000978, 0x00000001);
-	nv_icmd(priv, 0x000957, 0x00000003);
-	nv_icmd(priv, 0x00095e, 0x20164010);
-	nv_icmd(priv, 0x00095f, 0x00000020);
-	nv_icmd(priv, 0x00097d, 0x00000020);
-	nv_icmd(priv, 0x000683, 0x00000006);
-	nv_icmd(priv, 0x000685, 0x003fffff);
-	nv_icmd(priv, 0x000687, 0x003fffff);
-	nv_icmd(priv, 0x0006a0, 0x00000005);
-	nv_icmd(priv, 0x000840, 0x00400008);
-	nv_icmd(priv, 0x000841, 0x08000080);
-	nv_icmd(priv, 0x000842, 0x00400008);
-	nv_icmd(priv, 0x000843, 0x08000080);
-	nv_icmd(priv, 0x000818, 0x00000000);
-	nv_icmd(priv, 0x000819, 0x00000000);
-	nv_icmd(priv, 0x00081a, 0x00000000);
-	nv_icmd(priv, 0x00081b, 0x00000000);
-	nv_icmd(priv, 0x00081c, 0x00000000);
-	nv_icmd(priv, 0x00081d, 0x00000000);
-	nv_icmd(priv, 0x00081e, 0x00000000);
-	nv_icmd(priv, 0x00081f, 0x00000000);
-	nv_icmd(priv, 0x000848, 0x00000000);
-	nv_icmd(priv, 0x000849, 0x00000000);
-	nv_icmd(priv, 0x00084a, 0x00000000);
-	nv_icmd(priv, 0x00084b, 0x00000000);
-	nv_icmd(priv, 0x00084c, 0x00000000);
-	nv_icmd(priv, 0x00084d, 0x00000000);
-	nv_icmd(priv, 0x00084e, 0x00000000);
-	nv_icmd(priv, 0x00084f, 0x00000000);
-	nv_icmd(priv, 0x000850, 0x00000000);
-	nv_icmd(priv, 0x000851, 0x00000000);
-	nv_icmd(priv, 0x000852, 0x00000000);
-	nv_icmd(priv, 0x000853, 0x00000000);
-	nv_icmd(priv, 0x000854, 0x00000000);
-	nv_icmd(priv, 0x000855, 0x00000000);
-	nv_icmd(priv, 0x000856, 0x00000000);
-	nv_icmd(priv, 0x000857, 0x00000000);
-	nv_icmd(priv, 0x000738, 0x00000000);
-	nv_icmd(priv, 0x0006aa, 0x00000001);
-	nv_icmd(priv, 0x0006ab, 0x00000002);
-	nv_icmd(priv, 0x0006ac, 0x00000080);
-	nv_icmd(priv, 0x0006ad, 0x00000100);
-	nv_icmd(priv, 0x0006ae, 0x00000100);
-	nv_icmd(priv, 0x0006b1, 0x00000011);
-	nv_icmd(priv, 0x0006bb, 0x000000cf);
-	nv_icmd(priv, 0x0006ce, 0x2a712488);
-	nv_icmd(priv, 0x000739, 0x4085c000);
-	nv_icmd(priv, 0x00073a, 0x00000080);
-	nv_icmd(priv, 0x000786, 0x80000100);
-	nv_icmd(priv, 0x00073c, 0x00010100);
-	nv_icmd(priv, 0x00073d, 0x02800000);
-	nv_icmd(priv, 0x000787, 0x000000cf);
-	nv_icmd(priv, 0x00078c, 0x00000008);
-	nv_icmd(priv, 0x000792, 0x00000001);
-	nv_icmd(priv, 0x000794, 0x00000001);
-	nv_icmd(priv, 0x000795, 0x00000001);
-	nv_icmd(priv, 0x000796, 0x00000001);
-	nv_icmd(priv, 0x000797, 0x000000cf);
-	nv_icmd(priv, 0x000836, 0x00000001);
-	nv_icmd(priv, 0x00079a, 0x00000002);
-	nv_icmd(priv, 0x000833, 0x04444480);
-	nv_icmd(priv, 0x0007a1, 0x00000001);
-	nv_icmd(priv, 0x0007a3, 0x00000001);
-	nv_icmd(priv, 0x0007a4, 0x00000001);
-	nv_icmd(priv, 0x0007a5, 0x00000001);
-	nv_icmd(priv, 0x000831, 0x00000004);
-	nv_icmd(priv, 0x000b07, 0x00000002);
-	nv_icmd(priv, 0x000b08, 0x00000100);
-	nv_icmd(priv, 0x000b09, 0x00000100);
-	nv_icmd(priv, 0x000b0a, 0x00000001);
-	nv_icmd(priv, 0x000a04, 0x000000ff);
-	nv_icmd(priv, 0x000a0b, 0x00000040);
-	nv_icmd(priv, 0x00097f, 0x00000100);
-	nv_icmd(priv, 0x000a02, 0x00000001);
-	nv_icmd(priv, 0x000809, 0x00000007);
-	nv_icmd(priv, 0x00c221, 0x00000040);
-	nv_icmd(priv, 0x00c1b0, 0x0000000f);
-	nv_icmd(priv, 0x00c1b1, 0x0000000f);
-	nv_icmd(priv, 0x00c1b2, 0x0000000f);
-	nv_icmd(priv, 0x00c1b3, 0x0000000f);
-	nv_icmd(priv, 0x00c1b4, 0x0000000f);
-	nv_icmd(priv, 0x00c1b5, 0x0000000f);
-	nv_icmd(priv, 0x00c1b6, 0x0000000f);
-	nv_icmd(priv, 0x00c1b7, 0x0000000f);
-	nv_icmd(priv, 0x00c1b8, 0x0fac6881);
-	nv_icmd(priv, 0x00c1b9, 0x00fac688);
-	nv_icmd(priv, 0x00c401, 0x00000001);
-	nv_icmd(priv, 0x00c402, 0x00010001);
-	nv_icmd(priv, 0x00c403, 0x00000001);
-	nv_icmd(priv, 0x00c404, 0x00000001);
-	nv_icmd(priv, 0x00c40e, 0x00000020);
-	nv_icmd(priv, 0x00c500, 0x00000003);
-	nv_icmd(priv, 0x01e100, 0x00000001);
-	nv_icmd(priv, 0x001000, 0x00000002);
-	nv_icmd(priv, 0x0006aa, 0x00000001);
-	nv_icmd(priv, 0x0006ad, 0x00000100);
-	nv_icmd(priv, 0x0006ae, 0x00000100);
-	nv_icmd(priv, 0x0006b1, 0x00000011);
-	nv_icmd(priv, 0x00078c, 0x00000008);
-	nv_icmd(priv, 0x000792, 0x00000001);
-	nv_icmd(priv, 0x000794, 0x00000001);
-	nv_icmd(priv, 0x000795, 0x00000001);
-	nv_icmd(priv, 0x000796, 0x00000001);
-	nv_icmd(priv, 0x000797, 0x000000cf);
-	nv_icmd(priv, 0x00079a, 0x00000002);
-	nv_icmd(priv, 0x000833, 0x04444480);
-	nv_icmd(priv, 0x0007a1, 0x00000001);
-	nv_icmd(priv, 0x0007a3, 0x00000001);
-	nv_icmd(priv, 0x0007a4, 0x00000001);
-	nv_icmd(priv, 0x0007a5, 0x00000001);
-	nv_icmd(priv, 0x000831, 0x00000004);
-	nv_icmd(priv, 0x01e100, 0x00000001);
-	nv_icmd(priv, 0x001000, 0x00000008);
-	nv_icmd(priv, 0x000039, 0x00000000);
-	nv_icmd(priv, 0x00003a, 0x00000000);
-	nv_icmd(priv, 0x00003b, 0x00000000);
-	nv_icmd(priv, 0x000380, 0x00000001);
-	nv_icmd(priv, 0x000366, 0x00000000);
-	nv_icmd(priv, 0x000367, 0x00000000);
-	nv_icmd(priv, 0x000368, 0x00000fff);
-	nv_icmd(priv, 0x000370, 0x00000000);
-	nv_icmd(priv, 0x000371, 0x00000000);
-	nv_icmd(priv, 0x000372, 0x000fffff);
-	nv_icmd(priv, 0x000813, 0x00000006);
-	nv_icmd(priv, 0x000814, 0x00000008);
-	nv_icmd(priv, 0x000957, 0x00000003);
-	nv_icmd(priv, 0x000818, 0x00000000);
-	nv_icmd(priv, 0x000819, 0x00000000);
-	nv_icmd(priv, 0x00081a, 0x00000000);
-	nv_icmd(priv, 0x00081b, 0x00000000);
-	nv_icmd(priv, 0x00081c, 0x00000000);
-	nv_icmd(priv, 0x00081d, 0x00000000);
-	nv_icmd(priv, 0x00081e, 0x00000000);
-	nv_icmd(priv, 0x00081f, 0x00000000);
-	nv_icmd(priv, 0x000848, 0x00000000);
-	nv_icmd(priv, 0x000849, 0x00000000);
-	nv_icmd(priv, 0x00084a, 0x00000000);
-	nv_icmd(priv, 0x00084b, 0x00000000);
-	nv_icmd(priv, 0x00084c, 0x00000000);
-	nv_icmd(priv, 0x00084d, 0x00000000);
-	nv_icmd(priv, 0x00084e, 0x00000000);
-	nv_icmd(priv, 0x00084f, 0x00000000);
-	nv_icmd(priv, 0x000850, 0x00000000);
-	nv_icmd(priv, 0x000851, 0x00000000);
-	nv_icmd(priv, 0x000852, 0x00000000);
-	nv_icmd(priv, 0x000853, 0x00000000);
-	nv_icmd(priv, 0x000854, 0x00000000);
-	nv_icmd(priv, 0x000855, 0x00000000);
-	nv_icmd(priv, 0x000856, 0x00000000);
-	nv_icmd(priv, 0x000857, 0x00000000);
-	nv_icmd(priv, 0x000738, 0x00000000);
-	nv_icmd(priv, 0x000b07, 0x00000002);
-	nv_icmd(priv, 0x000b08, 0x00000100);
-	nv_icmd(priv, 0x000b09, 0x00000100);
-	nv_icmd(priv, 0x000b0a, 0x00000001);
-	nv_icmd(priv, 0x000a04, 0x000000ff);
-	nv_icmd(priv, 0x00097f, 0x00000100);
-	nv_icmd(priv, 0x000a02, 0x00000001);
-	nv_icmd(priv, 0x000809, 0x00000007);
-	nv_icmd(priv, 0x00c221, 0x00000040);
-	nv_icmd(priv, 0x00c401, 0x00000001);
-	nv_icmd(priv, 0x00c402, 0x00010001);
-	nv_icmd(priv, 0x00c403, 0x00000001);
-	nv_icmd(priv, 0x00c404, 0x00000001);
-	nv_icmd(priv, 0x00c40e, 0x00000020);
-	nv_icmd(priv, 0x00c500, 0x00000003);
-	nv_icmd(priv, 0x01e100, 0x00000001);
-	nv_icmd(priv, 0x001000, 0x00000001);
-	nv_icmd(priv, 0x000b07, 0x00000002);
-	nv_icmd(priv, 0x000b08, 0x00000100);
-	nv_icmd(priv, 0x000b09, 0x00000100);
-	nv_icmd(priv, 0x000b0a, 0x00000001);
-	nv_icmd(priv, 0x01e100, 0x00000001);
-	nv_wr32(priv, 0x400208, 0x00000000);
-}
-
-static void
-nve0_grctx_generate_a097(struct nvc0_graph_priv *priv)
-{
-	nv_mthd(priv, 0xa097, 0x0800, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0840, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0880, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x08c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0900, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0940, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0980, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x09c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0804, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0844, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0884, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x08c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0904, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0944, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0984, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x09c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0808, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x0848, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x0888, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x08c8, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x0908, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x0948, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x0988, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x09c8, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x080c, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x084c, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x088c, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x08cc, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x090c, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x094c, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x098c, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x09cc, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x0810, 0x000000cf);
-	nv_mthd(priv, 0xa097, 0x0850, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0890, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x08d0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0910, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0950, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0990, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x09d0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0814, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x0854, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x0894, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x08d4, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x0914, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x0954, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x0994, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x09d4, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x0818, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0858, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0898, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x08d8, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0918, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0958, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0998, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x09d8, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x081c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x085c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x089c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x08dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x091c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x095c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x099c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x09dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0820, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0860, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x08a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x08e0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0920, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0960, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x09a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x09e0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c00, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c10, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c20, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c30, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c40, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c50, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c60, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c70, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c80, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ca0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cb0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cc0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cd0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ce0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cf0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c04, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c14, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c24, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c34, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c44, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c54, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c64, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c74, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c84, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c94, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ca4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cb4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cc4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cd4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ce4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cf4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c08, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c18, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c28, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c38, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c48, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c58, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c68, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c78, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c88, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c98, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ca8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cb8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cc8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cd8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ce8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cf8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c0c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c1c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c2c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c3c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c4c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c5c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c6c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c7c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c8c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1c9c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cbc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ccc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cdc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1cfc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d00, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d10, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d20, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d30, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d40, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d50, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d60, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d70, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d80, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1da0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1db0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dc0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dd0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1de0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1df0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d04, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d14, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d24, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d34, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d44, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d54, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d64, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d74, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d84, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d94, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1da4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1db4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dc4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dd4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1de4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1df4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d08, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d18, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d28, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d38, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d48, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d58, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d68, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d78, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d88, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d98, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1da8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1db8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dc8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dd8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1de8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1df8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d0c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d1c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d2c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d3c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d4c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d5c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d6c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d7c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d8c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1d9c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dbc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dcc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ddc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1dfc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f00, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f08, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f10, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f18, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f20, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f28, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f30, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f38, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f40, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f48, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f50, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f58, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f60, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f68, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f70, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f78, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f04, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f0c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f14, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f1c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f24, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f2c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f34, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f3c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f44, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f4c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f54, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f5c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f64, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f6c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f74, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f7c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f80, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f88, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f98, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fa0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fa8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fb0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fb8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fc0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fc8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fd0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fd8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fe0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fe8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ff0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ff8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f84, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f8c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f94, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1f9c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fa4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fb4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fbc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fc4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fcc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fd4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fdc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fe4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1fec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ff4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1ffc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2000, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2040, 0x00000011);
-	nv_mthd(priv, 0xa097, 0x2080, 0x00000020);
-	nv_mthd(priv, 0xa097, 0x20c0, 0x00000030);
-	nv_mthd(priv, 0xa097, 0x2100, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x2140, 0x00000051);
-	nv_mthd(priv, 0xa097, 0x200c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x204c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x208c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x20cc, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x210c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x214c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x2010, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2050, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2090, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x20d0, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x2110, 0x00000003);
-	nv_mthd(priv, 0xa097, 0x2150, 0x00000004);
-	nv_mthd(priv, 0xa097, 0x0380, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03e0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0384, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03e4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0388, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03a8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03c8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03e8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x038c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03ac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x03ec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0700, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0710, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0720, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0730, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0704, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0714, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0724, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0734, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0708, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0718, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0728, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0738, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2800, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2804, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2808, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x280c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2810, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2814, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2818, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x281c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2820, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2824, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2828, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x282c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2830, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2834, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2838, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x283c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2840, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2844, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2848, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x284c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2850, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2854, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2858, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x285c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2860, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2864, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2868, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x286c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2870, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2874, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2878, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x287c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2880, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2884, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2888, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x288c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2890, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2894, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2898, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x289c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28a8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28ac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28b0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28b4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28b8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28bc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28c8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28d0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28d4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28d8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28e0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28e4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28e8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28ec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28f0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28f4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28f8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x28fc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2900, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2904, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2908, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x290c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2910, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2914, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2918, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x291c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2920, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2924, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2928, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x292c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2930, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2934, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2938, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x293c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2940, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2944, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2948, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x294c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2950, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2954, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2958, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x295c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2960, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2964, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2968, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x296c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2970, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2974, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2978, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x297c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2980, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2984, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2988, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x298c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2990, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2994, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2998, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x299c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29a8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29ac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29b0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29b4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29b8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29bc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29c8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29d0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29d4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29d8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29e0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29e4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29e8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29ec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29f0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29f4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29f8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x29fc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a00, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a20, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a40, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a60, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a80, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0aa0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ac0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ae0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b00, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b20, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b40, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b60, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b80, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ba0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bc0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0be0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a04, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a24, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a44, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a64, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a84, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0aa4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ac4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ae4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b04, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b24, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b44, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b64, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b84, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ba4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bc4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0be4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a08, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a28, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a48, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a68, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a88, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0aa8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ac8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ae8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b08, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b28, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b48, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b68, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b88, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ba8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bc8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0be8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a0c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a2c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a4c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a6c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a8c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0aac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0acc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0aec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b0c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b2c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b4c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b6c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b8c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bcc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a10, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a30, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a50, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a70, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ab0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ad0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0af0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b10, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b30, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b50, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b70, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bb0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bd0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bf0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a14, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a34, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a54, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a74, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0a94, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ab4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ad4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0af4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b14, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b34, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b54, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b74, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0b94, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bb4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bd4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0bf4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c00, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c10, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c20, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c30, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c40, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c50, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c60, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c70, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c80, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ca0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cb0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cc0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cd0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ce0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cf0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c04, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c14, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c24, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c34, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c44, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c54, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c64, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c74, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c84, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c94, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ca4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cb4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cc4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cd4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ce4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cf4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c08, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c18, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c28, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c38, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c48, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c58, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c68, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c78, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c88, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c98, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ca8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cb8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cc8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cd8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ce8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0cf8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0c0c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c1c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c2c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c3c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c4c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c5c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c6c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c7c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c8c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0c9c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0cac, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0cbc, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0ccc, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0cdc, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0cec, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0cfc, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0d00, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d08, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d10, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d18, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d20, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d28, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d30, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d38, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d04, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d0c, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d14, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d1c, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d24, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d2c, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d34, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d3c, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e00, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e10, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e20, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e30, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e40, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e50, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e60, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e70, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e80, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ea0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0eb0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ec0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ed0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ee0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ef0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0e04, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e14, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e24, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e34, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e44, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e54, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e64, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e74, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e84, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e94, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ea4, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0eb4, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ec4, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ed4, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ee4, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ef4, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e08, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e18, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e28, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e38, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e48, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e58, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e68, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e78, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e88, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0e98, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ea8, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0eb8, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ec8, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ed8, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ee8, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0ef8, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d40, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d48, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d50, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d58, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d44, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d4c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d54, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d5c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1e00, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e20, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e40, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e60, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e80, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ea0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ec0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ee0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e04, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e24, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e44, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e64, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e84, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ea4, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ec4, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ee4, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e08, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e28, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e48, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e68, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e88, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1ea8, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1ec8, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1ee8, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e0c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e2c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e4c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e6c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e8c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1eac, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ecc, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1eec, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e10, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e30, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e50, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e70, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e90, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1eb0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ed0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ef0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e14, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e34, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e54, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e74, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e94, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1eb4, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1ed4, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1ef4, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1e18, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e38, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e58, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e78, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1e98, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1eb8, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ed8, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1ef8, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x3400, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3404, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3408, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x340c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3410, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3414, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3418, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x341c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3420, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3424, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3428, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x342c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3430, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3434, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3438, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x343c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3440, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3444, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3448, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x344c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3450, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3454, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3458, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x345c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3460, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3464, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3468, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x346c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3470, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3474, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3478, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x347c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3480, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3484, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3488, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x348c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3490, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3494, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3498, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x349c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34a8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34ac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34b0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34b4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34b8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34bc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34c8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34d0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34d4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34d8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34e0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34e4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34e8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34ec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34f0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34f4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34f8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x34fc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3500, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3504, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3508, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x350c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3510, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3514, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3518, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x351c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3520, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3524, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3528, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x352c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3530, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3534, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3538, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x353c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3540, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3544, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3548, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x354c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3550, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3554, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3558, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x355c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3560, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3564, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3568, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x356c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3570, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3574, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3578, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x357c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3580, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3584, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3588, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x358c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3590, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3594, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x3598, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x359c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35a8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35ac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35b0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35b4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35b8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35bc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35c8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35d0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35d4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35d8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35e0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35e4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35e8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35ec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35f0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35f4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35f8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x35fc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x030c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1944, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1514, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d68, 0x0000ffff);
-	nv_mthd(priv, 0xa097, 0x121c, 0x0fac6881);
-	nv_mthd(priv, 0xa097, 0x0fac, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1538, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0fe0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0fe4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0fe8, 0x00000014);
-	nv_mthd(priv, 0xa097, 0x0fec, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x0ff0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x179c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1228, 0x00000400);
-	nv_mthd(priv, 0xa097, 0x122c, 0x00000300);
-	nv_mthd(priv, 0xa097, 0x1230, 0x00010001);
-	nv_mthd(priv, 0xa097, 0x07f8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x15b4, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x15cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1534, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0fb0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x15d0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x153c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x16b4, 0x00000003);
-	nv_mthd(priv, 0xa097, 0x0fbc, 0x0000ffff);
-	nv_mthd(priv, 0xa097, 0x0fc0, 0x0000ffff);
-	nv_mthd(priv, 0xa097, 0x0fc4, 0x0000ffff);
-	nv_mthd(priv, 0xa097, 0x0fc8, 0x0000ffff);
-	nv_mthd(priv, 0xa097, 0x0df8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0dfc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1948, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1970, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x161c, 0x000009f0);
-	nv_mthd(priv, 0xa097, 0x0dcc, 0x00000010);
-	nv_mthd(priv, 0xa097, 0x163c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x15e4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1160, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1164, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1168, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x116c, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1170, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1174, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1178, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x117c, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1180, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1184, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1188, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x118c, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1190, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1194, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1198, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x119c, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11a0, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11a4, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11a8, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11ac, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11b0, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11b4, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11b8, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11bc, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11c0, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11c4, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11c8, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11cc, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11d0, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11d4, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11d8, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x11dc, 0x25e00040);
-	nv_mthd(priv, 0xa097, 0x1880, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1884, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1888, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x188c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1890, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1894, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1898, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x189c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18a8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18ac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18b0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18b4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18b8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18bc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18c8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18d0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18d4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18d8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18e0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18e4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18e8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18ec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18f0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18f4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18f8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x18fc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0f84, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0f88, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x17c8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x17cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x17d0, 0x000000ff);
-	nv_mthd(priv, 0xa097, 0x17d4, 0xffffffff);
-	nv_mthd(priv, 0xa097, 0x17d8, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x17dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x15f4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x15f8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1434, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1438, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d74, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0dec, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x13a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1318, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1644, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0748, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0de8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1648, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x12a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1120, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1124, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1128, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x112c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1118, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x164c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1658, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1910, 0x00000290);
-	nv_mthd(priv, 0xa097, 0x1518, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x165c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1520, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1604, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1570, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x13b0, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x13b4, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x020c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1670, 0x30201000);
-	nv_mthd(priv, 0xa097, 0x1674, 0x70605040);
-	nv_mthd(priv, 0xa097, 0x1678, 0xb8a89888);
-	nv_mthd(priv, 0xa097, 0x167c, 0xf8e8d8c8);
-	nv_mthd(priv, 0xa097, 0x166c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1680, 0x00ffff00);
-	nv_mthd(priv, 0xa097, 0x12d0, 0x00000003);
-	nv_mthd(priv, 0xa097, 0x12d4, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1684, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1688, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0dac, 0x00001b02);
-	nv_mthd(priv, 0xa097, 0x0db0, 0x00001b02);
-	nv_mthd(priv, 0xa097, 0x0db4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x168c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x15bc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x156c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x187c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1110, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0dc0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0dc4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0dc8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1234, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1690, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x12ac, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0790, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0794, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0798, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x079c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x07a0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x077c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1000, 0x00000010);
-	nv_mthd(priv, 0xa097, 0x10fc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1290, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0218, 0x00000010);
-	nv_mthd(priv, 0xa097, 0x12d8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x12dc, 0x00000010);
-	nv_mthd(priv, 0xa097, 0x0d94, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x155c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1560, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1564, 0x00000fff);
-	nv_mthd(priv, 0xa097, 0x1574, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1578, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x157c, 0x000fffff);
-	nv_mthd(priv, 0xa097, 0x1354, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1610, 0x00000012);
-	nv_mthd(priv, 0xa097, 0x1608, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x160c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x260c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x07ac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x162c, 0x00000003);
-	nv_mthd(priv, 0xa097, 0x0210, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0320, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0324, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0328, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x032c, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0330, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0334, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0338, 0x3f800000);
-	nv_mthd(priv, 0xa097, 0x0750, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0760, 0x39291909);
-	nv_mthd(priv, 0xa097, 0x0764, 0x79695949);
-	nv_mthd(priv, 0xa097, 0x0768, 0xb9a99989);
-	nv_mthd(priv, 0xa097, 0x076c, 0xf9e9d9c9);
-	nv_mthd(priv, 0xa097, 0x0770, 0x30201000);
-	nv_mthd(priv, 0xa097, 0x0774, 0x70605040);
-	nv_mthd(priv, 0xa097, 0x0778, 0x00009080);
-	nv_mthd(priv, 0xa097, 0x0780, 0x39291909);
-	nv_mthd(priv, 0xa097, 0x0784, 0x79695949);
-	nv_mthd(priv, 0xa097, 0x0788, 0xb9a99989);
-	nv_mthd(priv, 0xa097, 0x078c, 0xf9e9d9c9);
-	nv_mthd(priv, 0xa097, 0x07d0, 0x30201000);
-	nv_mthd(priv, 0xa097, 0x07d4, 0x70605040);
-	nv_mthd(priv, 0xa097, 0x07d8, 0x00009080);
-	nv_mthd(priv, 0xa097, 0x037c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0740, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0744, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x2600, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1918, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x191c, 0x00000900);
-	nv_mthd(priv, 0xa097, 0x1920, 0x00000405);
-	nv_mthd(priv, 0xa097, 0x1308, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1924, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x13ac, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x192c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x193c, 0x00002c1c);
-	nv_mthd(priv, 0xa097, 0x0d7c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0f8c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x02c0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1510, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1940, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ff4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0ff8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x194c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1950, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1968, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1590, 0x0000003f);
-	nv_mthd(priv, 0xa097, 0x07e8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x07ec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x07f0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x07f4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x196c, 0x00000011);
-	nv_mthd(priv, 0xa097, 0x02e4, 0x0000b001);
-	nv_mthd(priv, 0xa097, 0x036c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0370, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x197c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0fcc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0fd0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x02d8, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x1980, 0x00000080);
-	nv_mthd(priv, 0xa097, 0x1504, 0x00000080);
-	nv_mthd(priv, 0xa097, 0x1984, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0300, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x13a8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x12ec, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1310, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1314, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1380, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1384, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1388, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x138c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1390, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1394, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x139c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1398, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1594, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1598, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x159c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x15a0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x15a4, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0f54, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0f58, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0f5c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x19bc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0f9c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0fa0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x12cc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x12e8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x130c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1360, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1364, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1368, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x136c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1370, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1374, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1378, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x137c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x133c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1340, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1344, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1348, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x134c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1350, 0x00000002);
-	nv_mthd(priv, 0xa097, 0x1358, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x12e4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x131c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1320, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1324, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1328, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x19c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1140, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x19c4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x19c8, 0x00001500);
-	nv_mthd(priv, 0xa097, 0x135c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0f90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x19e0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x19e4, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x19e8, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x19ec, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x19f0, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x19f4, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x19f8, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x19fc, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x19cc, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x15b8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1a00, 0x00001111);
-	nv_mthd(priv, 0xa097, 0x1a04, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1a08, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1a0c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1a10, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1a14, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1a18, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1a1c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d6c, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x0d70, 0xffff0000);
-	nv_mthd(priv, 0xa097, 0x10f8, 0x00001010);
-	nv_mthd(priv, 0xa097, 0x0d80, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d84, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d88, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d8c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0d90, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0da0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x07a4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x07a8, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1508, 0x80000000);
-	nv_mthd(priv, 0xa097, 0x150c, 0x40000000);
-	nv_mthd(priv, 0xa097, 0x1668, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0318, 0x00000008);
-	nv_mthd(priv, 0xa097, 0x031c, 0x00000008);
-	nv_mthd(priv, 0xa097, 0x0d9c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x0374, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0378, 0x00000020);
-	nv_mthd(priv, 0xa097, 0x07dc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x074c, 0x00000055);
-	nv_mthd(priv, 0xa097, 0x1420, 0x00000003);
-	nv_mthd(priv, 0xa097, 0x17bc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x17c0, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x17c4, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1008, 0x00000008);
-	nv_mthd(priv, 0xa097, 0x100c, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x1010, 0x0000012c);
-	nv_mthd(priv, 0xa097, 0x0d60, 0x00000040);
-	nv_mthd(priv, 0xa097, 0x075c, 0x00000003);
-	nv_mthd(priv, 0xa097, 0x1018, 0x00000020);
-	nv_mthd(priv, 0xa097, 0x101c, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1020, 0x00000020);
-	nv_mthd(priv, 0xa097, 0x1024, 0x00000001);
-	nv_mthd(priv, 0xa097, 0x1444, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x1448, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x144c, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0360, 0x20164010);
-	nv_mthd(priv, 0xa097, 0x0364, 0x00000020);
-	nv_mthd(priv, 0xa097, 0x0368, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0de4, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0204, 0x00000006);
-	nv_mthd(priv, 0xa097, 0x0208, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x02cc, 0x003fffff);
-	nv_mthd(priv, 0xa097, 0x02d0, 0x003fffff);
-	nv_mthd(priv, 0xa097, 0x1220, 0x00000005);
-	nv_mthd(priv, 0xa097, 0x0fdc, 0x00000000);
-	nv_mthd(priv, 0xa097, 0x0f98, 0x00400008);
-	nv_mthd(priv, 0xa097, 0x1284, 0x08000080);
-	nv_mthd(priv, 0xa097, 0x1450, 0x00400008);
-	nv_mthd(priv, 0xa097, 0x1454, 0x08000080);
-	nv_mthd(priv, 0xa097, 0x0214, 0x00000000);
-}
-
-static void
-nve0_grctx_generate_902d(struct nvc0_graph_priv *priv)
-{
-	nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
-	nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
-	nv_mthd(priv, 0x902d, 0x0208, 0x00000020);
-	nv_mthd(priv, 0x902d, 0x020c, 0x00000001);
-	nv_mthd(priv, 0x902d, 0x0210, 0x00000000);
-	nv_mthd(priv, 0x902d, 0x0214, 0x00000080);
-	nv_mthd(priv, 0x902d, 0x0218, 0x00000100);
-	nv_mthd(priv, 0x902d, 0x021c, 0x00000100);
-	nv_mthd(priv, 0x902d, 0x0220, 0x00000000);
-	nv_mthd(priv, 0x902d, 0x0224, 0x00000000);
-	nv_mthd(priv, 0x902d, 0x0230, 0x000000cf);
-	nv_mthd(priv, 0x902d, 0x0234, 0x00000001);
-	nv_mthd(priv, 0x902d, 0x0238, 0x00000020);
-	nv_mthd(priv, 0x902d, 0x023c, 0x00000001);
-	nv_mthd(priv, 0x902d, 0x0244, 0x00000080);
-	nv_mthd(priv, 0x902d, 0x0248, 0x00000100);
-	nv_mthd(priv, 0x902d, 0x024c, 0x00000100);
-	nv_mthd(priv, 0x902d, 0x3410, 0x00000000);
-}
-
-static void
-nve0_graph_generate_unk40xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x404010, 0x0);
-	nv_wr32(priv, 0x404014, 0x0);
-	nv_wr32(priv, 0x404018, 0x0);
-	nv_wr32(priv, 0x40401c, 0x0);
-	nv_wr32(priv, 0x404020, 0x0);
-	nv_wr32(priv, 0x404024, 0xe000);
-	nv_wr32(priv, 0x404028, 0x0);
-	nv_wr32(priv, 0x4040a8, 0x0);
-	nv_wr32(priv, 0x4040ac, 0x0);
-	nv_wr32(priv, 0x4040b0, 0x0);
-	nv_wr32(priv, 0x4040b4, 0x0);
-	nv_wr32(priv, 0x4040b8, 0x0);
-	nv_wr32(priv, 0x4040bc, 0x0);
-	nv_wr32(priv, 0x4040c0, 0x0);
-	nv_wr32(priv, 0x4040c4, 0x0);
-	nv_wr32(priv, 0x4040c8, 0xf800008f);
-	nv_wr32(priv, 0x4040d0, 0x0);
-	nv_wr32(priv, 0x4040d4, 0x0);
-	nv_wr32(priv, 0x4040d8, 0x0);
-	nv_wr32(priv, 0x4040dc, 0x0);
-	nv_wr32(priv, 0x4040e0, 0x0);
-	nv_wr32(priv, 0x4040e4, 0x0);
-	nv_wr32(priv, 0x4040e8, 0x1000);
-	nv_wr32(priv, 0x4040f8, 0x0);
-	nv_wr32(priv, 0x404130, 0x0);
-	nv_wr32(priv, 0x404134, 0x0);
-	nv_wr32(priv, 0x404138, 0x20000040);
-	nv_wr32(priv, 0x404150, 0x2e);
-	nv_wr32(priv, 0x404154, 0x400);
-	nv_wr32(priv, 0x404158, 0x200);
-	nv_wr32(priv, 0x404164, 0x55);
-	nv_wr32(priv, 0x4041a0, 0x0);
-	nv_wr32(priv, 0x4041a4, 0x0);
-	nv_wr32(priv, 0x4041a8, 0x0);
-	nv_wr32(priv, 0x4041ac, 0x0);
-	nv_wr32(priv, 0x404200, 0x0);
-	nv_wr32(priv, 0x404204, 0x0);
-	nv_wr32(priv, 0x404208, 0x0);
-	nv_wr32(priv, 0x40420c, 0x0);
-}
-
-static void
-nve0_graph_generate_unk44xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x404404, 0x0);
-	nv_wr32(priv, 0x404408, 0x0);
-	nv_wr32(priv, 0x40440c, 0x0);
-	nv_wr32(priv, 0x404410, 0x0);
-	nv_wr32(priv, 0x404414, 0x0);
-	nv_wr32(priv, 0x404418, 0x0);
-	nv_wr32(priv, 0x40441c, 0x0);
-	nv_wr32(priv, 0x404420, 0x0);
-	nv_wr32(priv, 0x404424, 0x0);
-	nv_wr32(priv, 0x404428, 0x0);
-	nv_wr32(priv, 0x40442c, 0x0);
-	nv_wr32(priv, 0x404430, 0x0);
-	nv_wr32(priv, 0x404434, 0x0);
-	nv_wr32(priv, 0x404438, 0x0);
-	nv_wr32(priv, 0x404460, 0x0);
-	nv_wr32(priv, 0x404464, 0x0);
-	nv_wr32(priv, 0x404468, 0xffffff);
-	nv_wr32(priv, 0x40446c, 0x0);
-	nv_wr32(priv, 0x404480, 0x1);
-	nv_wr32(priv, 0x404498, 0x1);
-}
-
-static void
-nve0_graph_generate_unk46xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x404604, 0x14);
-	nv_wr32(priv, 0x404608, 0x0);
-	nv_wr32(priv, 0x40460c, 0x3fff);
-	nv_wr32(priv, 0x404610, 0x100);
-	nv_wr32(priv, 0x404618, 0x0);
-	nv_wr32(priv, 0x40461c, 0x0);
-	nv_wr32(priv, 0x404620, 0x0);
-	nv_wr32(priv, 0x404624, 0x0);
-	nv_wr32(priv, 0x40462c, 0x0);
-	nv_wr32(priv, 0x404630, 0x0);
-	nv_wr32(priv, 0x404640, 0x0);
-	nv_wr32(priv, 0x404654, 0x0);
-	nv_wr32(priv, 0x404660, 0x0);
-	nv_wr32(priv, 0x404678, 0x0);
-	nv_wr32(priv, 0x40467c, 0x2);
-	nv_wr32(priv, 0x404680, 0x0);
-	nv_wr32(priv, 0x404684, 0x0);
-	nv_wr32(priv, 0x404688, 0x0);
-	nv_wr32(priv, 0x40468c, 0x0);
-	nv_wr32(priv, 0x404690, 0x0);
-	nv_wr32(priv, 0x404694, 0x0);
-	nv_wr32(priv, 0x404698, 0x0);
-	nv_wr32(priv, 0x40469c, 0x0);
-	nv_wr32(priv, 0x4046a0, 0x7f0080);
-	nv_wr32(priv, 0x4046a4, 0x0);
-	nv_wr32(priv, 0x4046a8, 0x0);
-	nv_wr32(priv, 0x4046ac, 0x0);
-	nv_wr32(priv, 0x4046b0, 0x0);
-	nv_wr32(priv, 0x4046b4, 0x0);
-	nv_wr32(priv, 0x4046b8, 0x0);
-	nv_wr32(priv, 0x4046bc, 0x0);
-	nv_wr32(priv, 0x4046c0, 0x0);
-	nv_wr32(priv, 0x4046c8, 0x0);
-	nv_wr32(priv, 0x4046cc, 0x0);
-	nv_wr32(priv, 0x4046d0, 0x0);
-}
-
-static void
-nve0_graph_generate_unk47xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x404700, 0x0);
-	nv_wr32(priv, 0x404704, 0x0);
-	nv_wr32(priv, 0x404708, 0x0);
-	nv_wr32(priv, 0x404718, 0x0);
-	nv_wr32(priv, 0x40471c, 0x0);
-	nv_wr32(priv, 0x404720, 0x0);
-	nv_wr32(priv, 0x404724, 0x0);
-	nv_wr32(priv, 0x404728, 0x0);
-	nv_wr32(priv, 0x40472c, 0x0);
-	nv_wr32(priv, 0x404730, 0x0);
-	nv_wr32(priv, 0x404734, 0x100);
-	nv_wr32(priv, 0x404738, 0x0);
-	nv_wr32(priv, 0x40473c, 0x0);
-	nv_wr32(priv, 0x404744, 0x0);
-	nv_wr32(priv, 0x404748, 0x0);
-	nv_wr32(priv, 0x404754, 0x0);
-}
-
-static void
-nve0_graph_generate_unk58xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x405800, 0xf8000bf);
-	nv_wr32(priv, 0x405830, 0x2180648);
-	nv_wr32(priv, 0x405834, 0x8000000);
-	nv_wr32(priv, 0x405838, 0x0);
-	nv_wr32(priv, 0x405854, 0x0);
-	nv_wr32(priv, 0x405870, 0x1);
-	nv_wr32(priv, 0x405874, 0x1);
-	nv_wr32(priv, 0x405878, 0x1);
-	nv_wr32(priv, 0x40587c, 0x1);
-	nv_wr32(priv, 0x405a00, 0x0);
-	nv_wr32(priv, 0x405a04, 0x0);
-	nv_wr32(priv, 0x405a18, 0x0);
-	nv_wr32(priv, 0x405b00, 0x0);
-	nv_wr32(priv, 0x405b10, 0x1000);
-}
-
-static void
-nve0_graph_generate_unk60xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x406020, 0x4103c1);
-	nv_wr32(priv, 0x406028, 0x1);
-	nv_wr32(priv, 0x40602c, 0x1);
-	nv_wr32(priv, 0x406030, 0x1);
-	nv_wr32(priv, 0x406034, 0x1);
-}
-
-static void
-nve0_graph_generate_unk64xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x4064a8, 0x0);
-	nv_wr32(priv, 0x4064ac, 0x3fff);
-	nv_wr32(priv, 0x4064b4, 0x0);
-	nv_wr32(priv, 0x4064b8, 0x0);
-	nv_wr32(priv, 0x4064c0, 0x801a00f0);
-	nv_wr32(priv, 0x4064c4, 0x192ffff);
-	nv_wr32(priv, 0x4064c8, 0x1800600);
-	nv_wr32(priv, 0x4064cc, 0x0);
-	nv_wr32(priv, 0x4064d0, 0x0);
-	nv_wr32(priv, 0x4064d4, 0x0);
-	nv_wr32(priv, 0x4064d8, 0x0);
-	nv_wr32(priv, 0x4064dc, 0x0);
-	nv_wr32(priv, 0x4064e0, 0x0);
-	nv_wr32(priv, 0x4064e4, 0x0);
-	nv_wr32(priv, 0x4064e8, 0x0);
-	nv_wr32(priv, 0x4064ec, 0x0);
-	nv_wr32(priv, 0x4064fc, 0x22a);
-}
-
-static void
-nve0_graph_generate_unk70xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x407040, 0x0);
-}
-
-static void
-nve0_graph_generate_unk78xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x407804, 0x23);
-	nv_wr32(priv, 0x40780c, 0xa418820);
-	nv_wr32(priv, 0x407810, 0x62080e6);
-	nv_wr32(priv, 0x407814, 0x20398a4);
-	nv_wr32(priv, 0x407818, 0xe629062);
-	nv_wr32(priv, 0x40781c, 0xa418820);
-	nv_wr32(priv, 0x407820, 0xe6);
-	nv_wr32(priv, 0x4078bc, 0x103);
-}
-
-static void
-nve0_graph_generate_unk80xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x408000, 0x0);
-	nv_wr32(priv, 0x408004, 0x0);
-	nv_wr32(priv, 0x408008, 0x30);
-	nv_wr32(priv, 0x40800c, 0x0);
-	nv_wr32(priv, 0x408010, 0x0);
-	nv_wr32(priv, 0x408014, 0x69);
-	nv_wr32(priv, 0x408018, 0xe100e100);
-	nv_wr32(priv, 0x408064, 0x0);
-}
-
-static void
-nve0_graph_generate_unk88xx(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x408800, 0x2802a3c);
-	nv_wr32(priv, 0x408804, 0x40);
-	nv_wr32(priv, 0x408808, 0x1043e005);
-	nv_wr32(priv, 0x408840, 0xb);
-	nv_wr32(priv, 0x408900, 0x3080b801);
-	nv_wr32(priv, 0x408904, 0x62000001);
-	nv_wr32(priv, 0x408908, 0xc8102f);
-	nv_wr32(priv, 0x408980, 0x11d);
-}
-
-static void
-nve0_graph_generate_gpc(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x418380, 0x16);
-	nv_wr32(priv, 0x418400, 0x38004e00);
-	nv_wr32(priv, 0x418404, 0x71e0ffff);
-	nv_wr32(priv, 0x41840c, 0x1008);
-	nv_wr32(priv, 0x418410, 0xfff0fff);
-	nv_wr32(priv, 0x418414, 0x2200fff);
-	nv_wr32(priv, 0x418450, 0x0);
-	nv_wr32(priv, 0x418454, 0x0);
-	nv_wr32(priv, 0x418458, 0x0);
-	nv_wr32(priv, 0x41845c, 0x0);
-	nv_wr32(priv, 0x418460, 0x0);
-	nv_wr32(priv, 0x418464, 0x0);
-	nv_wr32(priv, 0x418468, 0x1);
-	nv_wr32(priv, 0x41846c, 0x0);
-	nv_wr32(priv, 0x418470, 0x0);
-	nv_wr32(priv, 0x418600, 0x1f);
-	nv_wr32(priv, 0x418684, 0xf);
-	nv_wr32(priv, 0x418700, 0x2);
-	nv_wr32(priv, 0x418704, 0x80);
-	nv_wr32(priv, 0x418708, 0x0);
-	nv_wr32(priv, 0x41870c, 0x0);
-	nv_wr32(priv, 0x418710, 0x0);
-	nv_wr32(priv, 0x418800, 0x7006860a);
-	nv_wr32(priv, 0x418808, 0x0);
-	nv_wr32(priv, 0x41880c, 0x0);
-	nv_wr32(priv, 0x418810, 0x0);
-	nv_wr32(priv, 0x418828, 0x44);
-	nv_wr32(priv, 0x418830, 0x10000001);
-	nv_wr32(priv, 0x4188d8, 0x8);
-	nv_wr32(priv, 0x4188e0, 0x1000000);
-	nv_wr32(priv, 0x4188e8, 0x0);
-	nv_wr32(priv, 0x4188ec, 0x0);
-	nv_wr32(priv, 0x4188f0, 0x0);
-	nv_wr32(priv, 0x4188f4, 0x0);
-	nv_wr32(priv, 0x4188f8, 0x0);
-	nv_wr32(priv, 0x4188fc, 0x20100018);
-	nv_wr32(priv, 0x41891c, 0xff00ff);
-	nv_wr32(priv, 0x418924, 0x0);
-	nv_wr32(priv, 0x418928, 0xffff00);
-	nv_wr32(priv, 0x41892c, 0xff00);
-	nv_wr32(priv, 0x418a00, 0x0);
-	nv_wr32(priv, 0x418a04, 0x0);
-	nv_wr32(priv, 0x418a08, 0x0);
-	nv_wr32(priv, 0x418a0c, 0x10000);
-	nv_wr32(priv, 0x418a10, 0x0);
-	nv_wr32(priv, 0x418a14, 0x0);
-	nv_wr32(priv, 0x418a18, 0x0);
-	nv_wr32(priv, 0x418a20, 0x0);
-	nv_wr32(priv, 0x418a24, 0x0);
-	nv_wr32(priv, 0x418a28, 0x0);
-	nv_wr32(priv, 0x418a2c, 0x10000);
-	nv_wr32(priv, 0x418a30, 0x0);
-	nv_wr32(priv, 0x418a34, 0x0);
-	nv_wr32(priv, 0x418a38, 0x0);
-	nv_wr32(priv, 0x418a40, 0x0);
-	nv_wr32(priv, 0x418a44, 0x0);
-	nv_wr32(priv, 0x418a48, 0x0);
-	nv_wr32(priv, 0x418a4c, 0x10000);
-	nv_wr32(priv, 0x418a50, 0x0);
-	nv_wr32(priv, 0x418a54, 0x0);
-	nv_wr32(priv, 0x418a58, 0x0);
-	nv_wr32(priv, 0x418a60, 0x0);
-	nv_wr32(priv, 0x418a64, 0x0);
-	nv_wr32(priv, 0x418a68, 0x0);
-	nv_wr32(priv, 0x418a6c, 0x10000);
-	nv_wr32(priv, 0x418a70, 0x0);
-	nv_wr32(priv, 0x418a74, 0x0);
-	nv_wr32(priv, 0x418a78, 0x0);
-	nv_wr32(priv, 0x418a80, 0x0);
-	nv_wr32(priv, 0x418a84, 0x0);
-	nv_wr32(priv, 0x418a88, 0x0);
-	nv_wr32(priv, 0x418a8c, 0x10000);
-	nv_wr32(priv, 0x418a90, 0x0);
-	nv_wr32(priv, 0x418a94, 0x0);
-	nv_wr32(priv, 0x418a98, 0x0);
-	nv_wr32(priv, 0x418aa0, 0x0);
-	nv_wr32(priv, 0x418aa4, 0x0);
-	nv_wr32(priv, 0x418aa8, 0x0);
-	nv_wr32(priv, 0x418aac, 0x10000);
-	nv_wr32(priv, 0x418ab0, 0x0);
-	nv_wr32(priv, 0x418ab4, 0x0);
-	nv_wr32(priv, 0x418ab8, 0x0);
-	nv_wr32(priv, 0x418ac0, 0x0);
-	nv_wr32(priv, 0x418ac4, 0x0);
-	nv_wr32(priv, 0x418ac8, 0x0);
-	nv_wr32(priv, 0x418acc, 0x10000);
-	nv_wr32(priv, 0x418ad0, 0x0);
-	nv_wr32(priv, 0x418ad4, 0x0);
-	nv_wr32(priv, 0x418ad8, 0x0);
-	nv_wr32(priv, 0x418ae0, 0x0);
-	nv_wr32(priv, 0x418ae4, 0x0);
-	nv_wr32(priv, 0x418ae8, 0x0);
-	nv_wr32(priv, 0x418aec, 0x10000);
-	nv_wr32(priv, 0x418af0, 0x0);
-	nv_wr32(priv, 0x418af4, 0x0);
-	nv_wr32(priv, 0x418af8, 0x0);
-	nv_wr32(priv, 0x418b00, 0x6);
-	nv_wr32(priv, 0x418b08, 0xa418820);
-	nv_wr32(priv, 0x418b0c, 0x62080e6);
-	nv_wr32(priv, 0x418b10, 0x20398a4);
-	nv_wr32(priv, 0x418b14, 0xe629062);
-	nv_wr32(priv, 0x418b18, 0xa418820);
-	nv_wr32(priv, 0x418b1c, 0xe6);
-	nv_wr32(priv, 0x418bb8, 0x103);
-	nv_wr32(priv, 0x418c08, 0x1);
-	nv_wr32(priv, 0x418c10, 0x0);
-	nv_wr32(priv, 0x418c14, 0x0);
-	nv_wr32(priv, 0x418c18, 0x0);
-	nv_wr32(priv, 0x418c1c, 0x0);
-	nv_wr32(priv, 0x418c20, 0x0);
-	nv_wr32(priv, 0x418c24, 0x0);
-	nv_wr32(priv, 0x418c28, 0x0);
-	nv_wr32(priv, 0x418c2c, 0x0);
-	nv_wr32(priv, 0x418c40, 0xffffffff);
-	nv_wr32(priv, 0x418c6c, 0x1);
-	nv_wr32(priv, 0x418c80, 0x20200004);
-	nv_wr32(priv, 0x418c8c, 0x1);
-	nv_wr32(priv, 0x419000, 0x780);
-	nv_wr32(priv, 0x419004, 0x0);
-	nv_wr32(priv, 0x419008, 0x0);
-	nv_wr32(priv, 0x419014, 0x4);
-}
-
-static void
-nve0_graph_generate_tpc(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x419848, 0x0);
-	nv_wr32(priv, 0x419864, 0x129);
-	nv_wr32(priv, 0x419888, 0x0);
-	nv_wr32(priv, 0x419a00, 0xf0);
-	nv_wr32(priv, 0x419a04, 0x1);
-	nv_wr32(priv, 0x419a08, 0x21);
-	nv_wr32(priv, 0x419a0c, 0x20000);
-	nv_wr32(priv, 0x419a10, 0x0);
-	nv_wr32(priv, 0x419a14, 0x200);
-	nv_wr32(priv, 0x419a1c, 0xc000);
-	nv_wr32(priv, 0x419a20, 0x800);
-	nv_wr32(priv, 0x419a30, 0x1);
-	nv_wr32(priv, 0x419ac4, 0x37f440);
-	nv_wr32(priv, 0x419c00, 0xa);
-	nv_wr32(priv, 0x419c04, 0x80000006);
-	nv_wr32(priv, 0x419c08, 0x2);
-	nv_wr32(priv, 0x419c20, 0x0);
-	nv_wr32(priv, 0x419c24, 0x84210);
-	nv_wr32(priv, 0x419c28, 0x3efbefbe);
-	nv_wr32(priv, 0x419ce8, 0x0);
-	nv_wr32(priv, 0x419cf4, 0x3203);
-	nv_wr32(priv, 0x419e04, 0x0);
-	nv_wr32(priv, 0x419e08, 0x0);
-	nv_wr32(priv, 0x419e0c, 0x0);
-	nv_wr32(priv, 0x419e10, 0x402);
-	nv_wr32(priv, 0x419e44, 0x13eff2);
-	nv_wr32(priv, 0x419e48, 0x0);
-	nv_wr32(priv, 0x419e4c, 0x7f);
-	nv_wr32(priv, 0x419e50, 0x0);
-	nv_wr32(priv, 0x419e54, 0x0);
-	nv_wr32(priv, 0x419e58, 0x0);
-	nv_wr32(priv, 0x419e5c, 0x0);
-	nv_wr32(priv, 0x419e60, 0x0);
-	nv_wr32(priv, 0x419e64, 0x0);
-	nv_wr32(priv, 0x419e68, 0x0);
-	nv_wr32(priv, 0x419e6c, 0x0);
-	nv_wr32(priv, 0x419e70, 0x0);
-	nv_wr32(priv, 0x419e74, 0x0);
-	nv_wr32(priv, 0x419e78, 0x0);
-	nv_wr32(priv, 0x419e7c, 0x0);
-	nv_wr32(priv, 0x419e80, 0x0);
-	nv_wr32(priv, 0x419e84, 0x0);
-	nv_wr32(priv, 0x419e88, 0x0);
-	nv_wr32(priv, 0x419e8c, 0x0);
-	nv_wr32(priv, 0x419e90, 0x0);
-	nv_wr32(priv, 0x419e94, 0x0);
-	nv_wr32(priv, 0x419e98, 0x0);
-	nv_wr32(priv, 0x419eac, 0x1fcf);
-	nv_wr32(priv, 0x419eb0, 0xd3f);
-	nv_wr32(priv, 0x419ec8, 0x1304f);
-	nv_wr32(priv, 0x419f30, 0x0);
-	nv_wr32(priv, 0x419f34, 0x0);
-	nv_wr32(priv, 0x419f38, 0x0);
-	nv_wr32(priv, 0x419f3c, 0x0);
-	nv_wr32(priv, 0x419f40, 0x0);
-	nv_wr32(priv, 0x419f44, 0x0);
-	nv_wr32(priv, 0x419f48, 0x0);
-	nv_wr32(priv, 0x419f4c, 0x0);
-	nv_wr32(priv, 0x419f58, 0x0);
-	nv_wr32(priv, 0x419f78, 0xb);
-}
-
-static void
-nve0_graph_generate_tpcunk(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x41be24, 0x6);
-	nv_wr32(priv, 0x41bec0, 0x12180000);
-	nv_wr32(priv, 0x41bec4, 0x37f7f);
-	nv_wr32(priv, 0x41bee4, 0x6480430);
-	nv_wr32(priv, 0x41bf00, 0xa418820);
-	nv_wr32(priv, 0x41bf04, 0x62080e6);
-	nv_wr32(priv, 0x41bf08, 0x20398a4);
-	nv_wr32(priv, 0x41bf0c, 0xe629062);
-	nv_wr32(priv, 0x41bf10, 0xa418820);
-	nv_wr32(priv, 0x41bf14, 0xe6);
-	nv_wr32(priv, 0x41bfd0, 0x900103);
-	nv_wr32(priv, 0x41bfe0, 0x400001);
-	nv_wr32(priv, 0x41bfe4, 0x0);
-}
-
-int
-nve0_grctx_generate(struct nvc0_graph_priv *priv)
-{
-	struct nvc0_grctx info;
-	int ret, i, gpc, tpc, id;
-	u32 data[6] = {}, data2[2] = {}, tmp;
-	u32 tpc_set = 0, tpc_mask = 0;
-	u32 magic[GPC_MAX][2], offset;
-	u8 tpcnr[GPC_MAX], a, b;
-	u8 shift, ntpcv;
-
-	ret = nvc0_grctx_init(priv, &info);
-	if (ret)
-		return ret;
-
-	nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x400204, 0x00000000);
-	nv_wr32(priv, 0x400208, 0x00000000);
-
-	nve0_graph_generate_unk40xx(priv);
-	nve0_graph_generate_unk44xx(priv);
-	nve0_graph_generate_unk46xx(priv);
-	nve0_graph_generate_unk47xx(priv);
-	nve0_graph_generate_unk58xx(priv);
-	nve0_graph_generate_unk60xx(priv);
-	nve0_graph_generate_unk64xx(priv);
-	nve0_graph_generate_unk70xx(priv);
-	nve0_graph_generate_unk78xx(priv);
-	nve0_graph_generate_unk80xx(priv);
-	nve0_graph_generate_unk88xx(priv);
-	nve0_graph_generate_gpc(priv);
-	nve0_graph_generate_tpc(priv);
-	nve0_graph_generate_tpcunk(priv);
-
-	nv_wr32(priv, 0x404154, 0x0);
-
-	mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
-	mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
-	mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
-	mmio_list(0x40800c, 0x00000000,  8, 1);
-	mmio_list(0x408010, 0x80000000,  0, 0);
-	mmio_list(0x419004, 0x00000000,  8, 1);
-	mmio_list(0x419008, 0x00000000,  0, 0);
-	mmio_list(0x4064cc, 0x80000000,  0, 0);
-	mmio_list(0x408004, 0x00000000,  8, 0);
-	mmio_list(0x408008, 0x80000030,  0, 0);
-	mmio_list(0x418808, 0x00000000,  8, 0);
-	mmio_list(0x41880c, 0x80000030,  0, 0);
-	mmio_list(0x4064c8, 0x01800600,  0, 0);
-	mmio_list(0x418810, 0x80000000, 12, 2);
-	mmio_list(0x419848, 0x10000000, 12, 2);
-	mmio_list(0x405830, 0x02180648,  0, 0);
-	mmio_list(0x4064c4, 0x0192ffff,  0, 0);
-	for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
-		u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
-		u16 magic1 = 0x0648 * priv->tpc_nr[gpc];
-		magic[gpc][0]  = 0x10000000 | (magic0 << 16) | offset;
-		magic[gpc][1]  = 0x00000000 | (magic1 << 16);
-		offset += 0x0324 * priv->tpc_nr[gpc];
-	}
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
-		mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
-		offset += 0x07ff * priv->tpc_nr[gpc];
-	}
-	mmio_list(0x17e91c, 0x06060609, 0, 0);
-	mmio_list(0x17e920, 0x00090a05, 0, 0);
-
-	nv_wr32(priv, 0x418c6c, 0x1);
-	nv_wr32(priv, 0x41980c, 0x10);
-	nv_wr32(priv, 0x41be08, 0x4);
-	nv_wr32(priv, 0x4064c0, 0x801a00f0);
-	nv_wr32(priv, 0x405800, 0xf8000bf);
-	nv_wr32(priv, 0x419c00, 0xa);
-
-	for (tpc = 0, id = 0; tpc < 4; tpc++) {
-		for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-			if (tpc < priv->tpc_nr[gpc]) {
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0698), id);
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x04e8), id);
-				nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
-				nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0088), id++);
-			}
-
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
-		}
-	}
-
-	tmp = 0;
-	for (i = 0; i < priv->gpc_nr; i++)
-		tmp |= priv->tpc_nr[i] << (i * 4);
-	nv_wr32(priv, 0x406028, tmp);
-	nv_wr32(priv, 0x405870, tmp);
-
-	nv_wr32(priv, 0x40602c, 0x0);
-	nv_wr32(priv, 0x405874, 0x0);
-	nv_wr32(priv, 0x406030, 0x0);
-	nv_wr32(priv, 0x405878, 0x0);
-	nv_wr32(priv, 0x406034, 0x0);
-	nv_wr32(priv, 0x40587c, 0x0);
-
-	/* calculate first set of magics */
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-
-	gpc = -1;
-	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpcnr[gpc]--;
-
-		data[tpc / 6] |= gpc << ((tpc % 6) * 5);
-	}
-
-	for (; tpc < 32; tpc++)
-		data[tpc / 6] |= 7 << ((tpc % 6) * 5);
-
-	/* and the second... */
-	shift = 0;
-	ntpcv = priv->tpc_total;
-	while (!(ntpcv & (1 << 4))) {
-		ntpcv <<= 1;
-		shift++;
-	}
-
-	data2[0]  = ntpcv << 16;
-	data2[0] |= shift << 21;
-	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
-	data2[0] |= priv->tpc_total << 8;
-	data2[0] |= priv->magic_not_rop_nr;
-	for (i = 1; i < 7; i++)
-		data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-
-	/* and write it all the various parts of PGRAPH */
-	nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
-
-	nv_wr32(priv, 0x41bfd0, data2[0]);
-	nv_wr32(priv, 0x41bfe4, data2[1]);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
-
-	nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
-	for (i = 0; i < 6; i++)
-		nv_wr32(priv, 0x40780c + (i * 4), data[i]);
-
-
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++)
-		tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
-
-	for (i = 0, gpc = -1, b = -1; i < 32; i++) {
-		a = (i * (priv->tpc_total - 1)) / 32;
-		if (a != b) {
-			b = a;
-			do {
-				gpc = (gpc + 1) % priv->gpc_nr;
-			} while (!tpcnr[gpc]);
-			tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-			tpc_set |= 1 << ((gpc * 8) + tpc);
-		}
-
-		nv_wr32(priv, 0x406800 + (i * 0x20), tpc_set);
-		nv_wr32(priv, 0x406c00 + (i * 0x20), tpc_set ^ tpc_mask);
-	}
-
-	for (i = 0; i < 8; i++)
-		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
-
-	nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
-	if (priv->gpc_nr == 1) {
-		nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
-		nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
-	} else {
-		nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
-		nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
-	}
-	nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
-
-	nve0_grctx_generate_icmd(priv);
-	nve0_grctx_generate_a097(priv);
-	nve0_grctx_generate_902d(priv);
-
-	nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
-	nv_wr32(priv, 0x418800, 0x7026860a); //XXX
-	nv_wr32(priv, 0x41be10, 0x00bb8bc7); //XXX
-	return nvc0_grctx_fini(&info);
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
new file mode 100644
index 0000000..e2de73e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
@@ -0,0 +1,1018 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+struct nvc0_graph_init
+nve4_grctx_init_icmd[] = {
+	{ 0x001000,   1, 0x01, 0x00000004 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x0000a9,   1, 0x01, 0x0000ffff },
+	{ 0x000038,   1, 0x01, 0x0fac6881 },
+	{ 0x00003d,   1, 0x01, 0x00000001 },
+	{ 0x0000e8,   8, 0x01, 0x00000400 },
+	{ 0x000078,   8, 0x01, 0x00000300 },
+	{ 0x000050,   1, 0x01, 0x00000011 },
+	{ 0x000058,   8, 0x01, 0x00000008 },
+	{ 0x000208,   8, 0x01, 0x00000001 },
+	{ 0x000081,   1, 0x01, 0x00000001 },
+	{ 0x000085,   1, 0x01, 0x00000004 },
+	{ 0x000088,   1, 0x01, 0x00000400 },
+	{ 0x000090,   1, 0x01, 0x00000300 },
+	{ 0x000098,   1, 0x01, 0x00001001 },
+	{ 0x0000e3,   1, 0x01, 0x00000001 },
+	{ 0x0000da,   1, 0x01, 0x00000001 },
+	{ 0x0000f8,   1, 0x01, 0x00000003 },
+	{ 0x0000fa,   1, 0x01, 0x00000001 },
+	{ 0x00009f,   4, 0x01, 0x0000ffff },
+	{ 0x0000b1,   1, 0x01, 0x00000001 },
+	{ 0x0000ad,   1, 0x01, 0x0000013e },
+	{ 0x0000e1,   1, 0x01, 0x00000010 },
+	{ 0x000290,  16, 0x01, 0x00000000 },
+	{ 0x0003b0,  16, 0x01, 0x00000000 },
+	{ 0x0002a0,  16, 0x01, 0x00000000 },
+	{ 0x000420,  16, 0x01, 0x00000000 },
+	{ 0x0002b0,  16, 0x01, 0x00000000 },
+	{ 0x000430,  16, 0x01, 0x00000000 },
+	{ 0x0002c0,  16, 0x01, 0x00000000 },
+	{ 0x0004d0,  16, 0x01, 0x00000000 },
+	{ 0x000720,  16, 0x01, 0x00000000 },
+	{ 0x0008c0,  16, 0x01, 0x00000000 },
+	{ 0x000890,  16, 0x01, 0x00000000 },
+	{ 0x0008e0,  16, 0x01, 0x00000000 },
+	{ 0x0008a0,  16, 0x01, 0x00000000 },
+	{ 0x0008f0,  16, 0x01, 0x00000000 },
+	{ 0x00094c,   1, 0x01, 0x000000ff },
+	{ 0x00094d,   1, 0x01, 0xffffffff },
+	{ 0x00094e,   1, 0x01, 0x00000002 },
+	{ 0x0002ec,   1, 0x01, 0x00000001 },
+	{ 0x000303,   1, 0x01, 0x00000001 },
+	{ 0x0002e6,   1, 0x01, 0x00000001 },
+	{ 0x000466,   1, 0x01, 0x00000052 },
+	{ 0x000301,   1, 0x01, 0x3f800000 },
+	{ 0x000304,   1, 0x01, 0x30201000 },
+	{ 0x000305,   1, 0x01, 0x70605040 },
+	{ 0x000306,   1, 0x01, 0xb8a89888 },
+	{ 0x000307,   1, 0x01, 0xf8e8d8c8 },
+	{ 0x00030a,   1, 0x01, 0x00ffff00 },
+	{ 0x00030b,   1, 0x01, 0x0000001a },
+	{ 0x00030c,   1, 0x01, 0x00000001 },
+	{ 0x000318,   1, 0x01, 0x00000001 },
+	{ 0x000340,   1, 0x01, 0x00000000 },
+	{ 0x000375,   1, 0x01, 0x00000001 },
+	{ 0x00037d,   1, 0x01, 0x00000006 },
+	{ 0x0003a0,   1, 0x01, 0x00000002 },
+	{ 0x0003aa,   1, 0x01, 0x00000001 },
+	{ 0x0003a9,   1, 0x01, 0x00000001 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000383,   1, 0x01, 0x00000011 },
+	{ 0x000360,   1, 0x01, 0x00000040 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x00037a,   1, 0x01, 0x00000012 },
+	{ 0x000619,   1, 0x01, 0x00000003 },
+	{ 0x000811,   1, 0x01, 0x00000003 },
+	{ 0x000812,   1, 0x01, 0x00000004 },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000815,   1, 0x01, 0x0000000b },
+	{ 0x000800,   6, 0x01, 0x00000001 },
+	{ 0x000632,   1, 0x01, 0x00000001 },
+	{ 0x000633,   1, 0x01, 0x00000002 },
+	{ 0x000634,   1, 0x01, 0x00000003 },
+	{ 0x000635,   1, 0x01, 0x00000004 },
+	{ 0x000654,   1, 0x01, 0x3f800000 },
+	{ 0x000657,   1, 0x01, 0x3f800000 },
+	{ 0x000655,   2, 0x01, 0x3f800000 },
+	{ 0x0006cd,   1, 0x01, 0x3f800000 },
+	{ 0x0007f5,   1, 0x01, 0x3f800000 },
+	{ 0x0007dc,   1, 0x01, 0x39291909 },
+	{ 0x0007dd,   1, 0x01, 0x79695949 },
+	{ 0x0007de,   1, 0x01, 0xb9a99989 },
+	{ 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007e8,   1, 0x01, 0x00003210 },
+	{ 0x0007e9,   1, 0x01, 0x00007654 },
+	{ 0x0007ea,   1, 0x01, 0x00000098 },
+	{ 0x0007ec,   1, 0x01, 0x39291909 },
+	{ 0x0007ed,   1, 0x01, 0x79695949 },
+	{ 0x0007ee,   1, 0x01, 0xb9a99989 },
+	{ 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+	{ 0x0007f0,   1, 0x01, 0x00003210 },
+	{ 0x0007f1,   1, 0x01, 0x00007654 },
+	{ 0x0007f2,   1, 0x01, 0x00000098 },
+	{ 0x0005a5,   1, 0x01, 0x00000001 },
+	{ 0x000980, 128, 0x01, 0x00000000 },
+	{ 0x000468,   1, 0x01, 0x00000004 },
+	{ 0x00046c,   1, 0x01, 0x00000001 },
+	{ 0x000470,  96, 0x01, 0x00000000 },
+	{ 0x000510,  16, 0x01, 0x3f800000 },
+	{ 0x000520,   1, 0x01, 0x000002b6 },
+	{ 0x000529,   1, 0x01, 0x00000001 },
+	{ 0x000530,  16, 0x01, 0xffff0000 },
+	{ 0x000585,   1, 0x01, 0x0000003f },
+	{ 0x000576,   1, 0x01, 0x00000003 },
+	{ 0x00057b,   1, 0x01, 0x00000059 },
+	{ 0x000586,   1, 0x01, 0x00000040 },
+	{ 0x000582,   2, 0x01, 0x00000080 },
+	{ 0x0005c2,   1, 0x01, 0x00000001 },
+	{ 0x000638,   1, 0x01, 0x00000001 },
+	{ 0x000639,   1, 0x01, 0x00000001 },
+	{ 0x00063a,   1, 0x01, 0x00000002 },
+	{ 0x00063b,   2, 0x01, 0x00000001 },
+	{ 0x00063d,   1, 0x01, 0x00000002 },
+	{ 0x00063e,   1, 0x01, 0x00000001 },
+	{ 0x0008b8,   8, 0x01, 0x00000001 },
+	{ 0x000900,   8, 0x01, 0x00000001 },
+	{ 0x000908,   8, 0x01, 0x00000002 },
+	{ 0x000910,  16, 0x01, 0x00000001 },
+	{ 0x000920,   8, 0x01, 0x00000002 },
+	{ 0x000928,   8, 0x01, 0x00000001 },
+	{ 0x000648,   9, 0x01, 0x00000001 },
+	{ 0x000658,   1, 0x01, 0x0000000f },
+	{ 0x0007ff,   1, 0x01, 0x0000000a },
+	{ 0x00066a,   1, 0x01, 0x40000000 },
+	{ 0x00066b,   1, 0x01, 0x10000000 },
+	{ 0x00066c,   2, 0x01, 0xffff0000 },
+	{ 0x0007af,   2, 0x01, 0x00000008 },
+	{ 0x0007f6,   1, 0x01, 0x00000001 },
+	{ 0x0006b2,   1, 0x01, 0x00000055 },
+	{ 0x0007ad,   1, 0x01, 0x00000003 },
+	{ 0x000937,   1, 0x01, 0x00000001 },
+	{ 0x000971,   1, 0x01, 0x00000008 },
+	{ 0x000972,   1, 0x01, 0x00000040 },
+	{ 0x000973,   1, 0x01, 0x0000012c },
+	{ 0x00097c,   1, 0x01, 0x00000040 },
+	{ 0x000979,   1, 0x01, 0x00000003 },
+	{ 0x000975,   1, 0x01, 0x00000020 },
+	{ 0x000976,   1, 0x01, 0x00000001 },
+	{ 0x000977,   1, 0x01, 0x00000020 },
+	{ 0x000978,   1, 0x01, 0x00000001 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x00095e,   1, 0x01, 0x20164010 },
+	{ 0x00095f,   1, 0x01, 0x00000020 },
+	{ 0x00097d,   1, 0x01, 0x00000020 },
+	{ 0x000683,   1, 0x01, 0x00000006 },
+	{ 0x000685,   1, 0x01, 0x003fffff },
+	{ 0x000687,   1, 0x01, 0x003fffff },
+	{ 0x0006a0,   1, 0x01, 0x00000005 },
+	{ 0x000840,   1, 0x01, 0x00400008 },
+	{ 0x000841,   1, 0x01, 0x08000080 },
+	{ 0x000842,   1, 0x01, 0x00400008 },
+	{ 0x000843,   1, 0x01, 0x08000080 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ab,   1, 0x01, 0x00000002 },
+	{ 0x0006ac,   1, 0x01, 0x00000080 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x0006bb,   1, 0x01, 0x000000cf },
+	{ 0x0006ce,   1, 0x01, 0x2a712488 },
+	{ 0x000739,   1, 0x01, 0x4085c000 },
+	{ 0x00073a,   1, 0x01, 0x00000080 },
+	{ 0x000786,   1, 0x01, 0x80000100 },
+	{ 0x00073c,   1, 0x01, 0x00010100 },
+	{ 0x00073d,   1, 0x01, 0x02800000 },
+	{ 0x000787,   1, 0x01, 0x000000cf },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x000836,   1, 0x01, 0x00000001 },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x000a0b,   1, 0x01, 0x00000040 },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c1b0,   8, 0x01, 0x0000000f },
+	{ 0x00c1b8,   1, 0x01, 0x0fac6881 },
+	{ 0x00c1b9,   1, 0x01, 0x00fac688 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x00c500,   1, 0x01, 0x00000003 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000002 },
+	{ 0x0006aa,   1, 0x01, 0x00000001 },
+	{ 0x0006ad,   2, 0x01, 0x00000100 },
+	{ 0x0006b1,   1, 0x01, 0x00000011 },
+	{ 0x00078c,   1, 0x01, 0x00000008 },
+	{ 0x000792,   1, 0x01, 0x00000001 },
+	{ 0x000794,   1, 0x01, 0x00000001 },
+	{ 0x000795,   2, 0x01, 0x00000001 },
+	{ 0x000797,   1, 0x01, 0x000000cf },
+	{ 0x00079a,   1, 0x01, 0x00000002 },
+	{ 0x000833,   1, 0x01, 0x04444480 },
+	{ 0x0007a1,   1, 0x01, 0x00000001 },
+	{ 0x0007a3,   1, 0x01, 0x00000001 },
+	{ 0x0007a4,   2, 0x01, 0x00000001 },
+	{ 0x000831,   1, 0x01, 0x00000004 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000008 },
+	{ 0x000039,   3, 0x01, 0x00000000 },
+	{ 0x000380,   1, 0x01, 0x00000001 },
+	{ 0x000366,   2, 0x01, 0x00000000 },
+	{ 0x000368,   1, 0x01, 0x00000fff },
+	{ 0x000370,   2, 0x01, 0x00000000 },
+	{ 0x000372,   1, 0x01, 0x000fffff },
+	{ 0x000813,   1, 0x01, 0x00000006 },
+	{ 0x000814,   1, 0x01, 0x00000008 },
+	{ 0x000957,   1, 0x01, 0x00000003 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x000a04,   1, 0x01, 0x000000ff },
+	{ 0x00097f,   1, 0x01, 0x00000100 },
+	{ 0x000a02,   1, 0x01, 0x00000001 },
+	{ 0x000809,   1, 0x01, 0x00000007 },
+	{ 0x00c221,   1, 0x01, 0x00000040 },
+	{ 0x00c401,   1, 0x01, 0x00000001 },
+	{ 0x00c402,   1, 0x01, 0x00010001 },
+	{ 0x00c403,   2, 0x01, 0x00000001 },
+	{ 0x00c40e,   1, 0x01, 0x00000020 },
+	{ 0x00c500,   1, 0x01, 0x00000003 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{ 0x001000,   1, 0x01, 0x00000001 },
+	{ 0x000b07,   1, 0x01, 0x00000002 },
+	{ 0x000b08,   2, 0x01, 0x00000100 },
+	{ 0x000b0a,   1, 0x01, 0x00000001 },
+	{ 0x01e100,   1, 0x01, 0x00000001 },
+	{}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_a097[] = {
+	{ 0x000800,   8, 0x40, 0x00000000 },
+	{ 0x000804,   8, 0x40, 0x00000000 },
+	{ 0x000808,   8, 0x40, 0x00000400 },
+	{ 0x00080c,   8, 0x40, 0x00000300 },
+	{ 0x000810,   1, 0x04, 0x000000cf },
+	{ 0x000850,   7, 0x40, 0x00000000 },
+	{ 0x000814,   8, 0x40, 0x00000040 },
+	{ 0x000818,   8, 0x40, 0x00000001 },
+	{ 0x00081c,   8, 0x40, 0x00000000 },
+	{ 0x000820,   8, 0x40, 0x00000000 },
+	{ 0x001c00,  16, 0x10, 0x00000000 },
+	{ 0x001c04,  16, 0x10, 0x00000000 },
+	{ 0x001c08,  16, 0x10, 0x00000000 },
+	{ 0x001c0c,  16, 0x10, 0x00000000 },
+	{ 0x001d00,  16, 0x10, 0x00000000 },
+	{ 0x001d04,  16, 0x10, 0x00000000 },
+	{ 0x001d08,  16, 0x10, 0x00000000 },
+	{ 0x001d0c,  16, 0x10, 0x00000000 },
+	{ 0x001f00,  16, 0x08, 0x00000000 },
+	{ 0x001f04,  16, 0x08, 0x00000000 },
+	{ 0x001f80,  16, 0x08, 0x00000000 },
+	{ 0x001f84,  16, 0x08, 0x00000000 },
+	{ 0x002000,   1, 0x04, 0x00000000 },
+	{ 0x002040,   1, 0x04, 0x00000011 },
+	{ 0x002080,   1, 0x04, 0x00000020 },
+	{ 0x0020c0,   1, 0x04, 0x00000030 },
+	{ 0x002100,   1, 0x04, 0x00000040 },
+	{ 0x002140,   1, 0x04, 0x00000051 },
+	{ 0x00200c,   6, 0x40, 0x00000001 },
+	{ 0x002010,   1, 0x04, 0x00000000 },
+	{ 0x002050,   1, 0x04, 0x00000000 },
+	{ 0x002090,   1, 0x04, 0x00000001 },
+	{ 0x0020d0,   1, 0x04, 0x00000002 },
+	{ 0x002110,   1, 0x04, 0x00000003 },
+	{ 0x002150,   1, 0x04, 0x00000004 },
+	{ 0x000380,   4, 0x20, 0x00000000 },
+	{ 0x000384,   4, 0x20, 0x00000000 },
+	{ 0x000388,   4, 0x20, 0x00000000 },
+	{ 0x00038c,   4, 0x20, 0x00000000 },
+	{ 0x000700,   4, 0x10, 0x00000000 },
+	{ 0x000704,   4, 0x10, 0x00000000 },
+	{ 0x000708,   4, 0x10, 0x00000000 },
+	{ 0x002800, 128, 0x04, 0x00000000 },
+	{ 0x000a00,  16, 0x20, 0x00000000 },
+	{ 0x000a04,  16, 0x20, 0x00000000 },
+	{ 0x000a08,  16, 0x20, 0x00000000 },
+	{ 0x000a0c,  16, 0x20, 0x00000000 },
+	{ 0x000a10,  16, 0x20, 0x00000000 },
+	{ 0x000a14,  16, 0x20, 0x00000000 },
+	{ 0x000c00,  16, 0x10, 0x00000000 },
+	{ 0x000c04,  16, 0x10, 0x00000000 },
+	{ 0x000c08,  16, 0x10, 0x00000000 },
+	{ 0x000c0c,  16, 0x10, 0x3f800000 },
+	{ 0x000d00,   8, 0x08, 0xffff0000 },
+	{ 0x000d04,   8, 0x08, 0xffff0000 },
+	{ 0x000e00,  16, 0x10, 0x00000000 },
+	{ 0x000e04,  16, 0x10, 0xffff0000 },
+	{ 0x000e08,  16, 0x10, 0xffff0000 },
+	{ 0x000d40,   4, 0x08, 0x00000000 },
+	{ 0x000d44,   4, 0x08, 0x00000000 },
+	{ 0x001e00,   8, 0x20, 0x00000001 },
+	{ 0x001e04,   8, 0x20, 0x00000001 },
+	{ 0x001e08,   8, 0x20, 0x00000002 },
+	{ 0x001e0c,   8, 0x20, 0x00000001 },
+	{ 0x001e10,   8, 0x20, 0x00000001 },
+	{ 0x001e14,   8, 0x20, 0x00000002 },
+	{ 0x001e18,   8, 0x20, 0x00000001 },
+	{ 0x003400, 128, 0x04, 0x00000000 },
+	{ 0x00030c,   1, 0x04, 0x00000001 },
+	{ 0x001944,   1, 0x04, 0x00000000 },
+	{ 0x001514,   1, 0x04, 0x00000000 },
+	{ 0x000d68,   1, 0x04, 0x0000ffff },
+	{ 0x00121c,   1, 0x04, 0x0fac6881 },
+	{ 0x000fac,   1, 0x04, 0x00000001 },
+	{ 0x001538,   1, 0x04, 0x00000001 },
+	{ 0x000fe0,   2, 0x04, 0x00000000 },
+	{ 0x000fe8,   1, 0x04, 0x00000014 },
+	{ 0x000fec,   1, 0x04, 0x00000040 },
+	{ 0x000ff0,   1, 0x04, 0x00000000 },
+	{ 0x00179c,   1, 0x04, 0x00000000 },
+	{ 0x001228,   1, 0x04, 0x00000400 },
+	{ 0x00122c,   1, 0x04, 0x00000300 },
+	{ 0x001230,   1, 0x04, 0x00010001 },
+	{ 0x0007f8,   1, 0x04, 0x00000000 },
+	{ 0x0015b4,   1, 0x04, 0x00000001 },
+	{ 0x0015cc,   1, 0x04, 0x00000000 },
+	{ 0x001534,   1, 0x04, 0x00000000 },
+	{ 0x000fb0,   1, 0x04, 0x00000000 },
+	{ 0x0015d0,   1, 0x04, 0x00000000 },
+	{ 0x00153c,   1, 0x04, 0x00000000 },
+	{ 0x0016b4,   1, 0x04, 0x00000003 },
+	{ 0x000fbc,   4, 0x04, 0x0000ffff },
+	{ 0x000df8,   2, 0x04, 0x00000000 },
+	{ 0x001948,   1, 0x04, 0x00000000 },
+	{ 0x001970,   1, 0x04, 0x00000001 },
+	{ 0x00161c,   1, 0x04, 0x000009f0 },
+	{ 0x000dcc,   1, 0x04, 0x00000010 },
+	{ 0x00163c,   1, 0x04, 0x00000000 },
+	{ 0x0015e4,   1, 0x04, 0x00000000 },
+	{ 0x001160,  32, 0x04, 0x25e00040 },
+	{ 0x001880,  32, 0x04, 0x00000000 },
+	{ 0x000f84,   2, 0x04, 0x00000000 },
+	{ 0x0017c8,   2, 0x04, 0x00000000 },
+	{ 0x0017d0,   1, 0x04, 0x000000ff },
+	{ 0x0017d4,   1, 0x04, 0xffffffff },
+	{ 0x0017d8,   1, 0x04, 0x00000002 },
+	{ 0x0017dc,   1, 0x04, 0x00000000 },
+	{ 0x0015f4,   2, 0x04, 0x00000000 },
+	{ 0x001434,   2, 0x04, 0x00000000 },
+	{ 0x000d74,   1, 0x04, 0x00000000 },
+	{ 0x000dec,   1, 0x04, 0x00000001 },
+	{ 0x0013a4,   1, 0x04, 0x00000000 },
+	{ 0x001318,   1, 0x04, 0x00000001 },
+	{ 0x001644,   1, 0x04, 0x00000000 },
+	{ 0x000748,   1, 0x04, 0x00000000 },
+	{ 0x000de8,   1, 0x04, 0x00000000 },
+	{ 0x001648,   1, 0x04, 0x00000000 },
+	{ 0x0012a4,   1, 0x04, 0x00000000 },
+	{ 0x001120,   4, 0x04, 0x00000000 },
+	{ 0x001118,   1, 0x04, 0x00000000 },
+	{ 0x00164c,   1, 0x04, 0x00000000 },
+	{ 0x001658,   1, 0x04, 0x00000000 },
+	{ 0x001910,   1, 0x04, 0x00000290 },
+	{ 0x001518,   1, 0x04, 0x00000000 },
+	{ 0x00165c,   1, 0x04, 0x00000001 },
+	{ 0x001520,   1, 0x04, 0x00000000 },
+	{ 0x001604,   1, 0x04, 0x00000000 },
+	{ 0x001570,   1, 0x04, 0x00000000 },
+	{ 0x0013b0,   2, 0x04, 0x3f800000 },
+	{ 0x00020c,   1, 0x04, 0x00000000 },
+	{ 0x001670,   1, 0x04, 0x30201000 },
+	{ 0x001674,   1, 0x04, 0x70605040 },
+	{ 0x001678,   1, 0x04, 0xb8a89888 },
+	{ 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+	{ 0x00166c,   1, 0x04, 0x00000000 },
+	{ 0x001680,   1, 0x04, 0x00ffff00 },
+	{ 0x0012d0,   1, 0x04, 0x00000003 },
+	{ 0x0012d4,   1, 0x04, 0x00000002 },
+	{ 0x001684,   2, 0x04, 0x00000000 },
+	{ 0x000dac,   2, 0x04, 0x00001b02 },
+	{ 0x000db4,   1, 0x04, 0x00000000 },
+	{ 0x00168c,   1, 0x04, 0x00000000 },
+	{ 0x0015bc,   1, 0x04, 0x00000000 },
+	{ 0x00156c,   1, 0x04, 0x00000000 },
+	{ 0x00187c,   1, 0x04, 0x00000000 },
+	{ 0x001110,   1, 0x04, 0x00000001 },
+	{ 0x000dc0,   3, 0x04, 0x00000000 },
+	{ 0x001234,   1, 0x04, 0x00000000 },
+	{ 0x001690,   1, 0x04, 0x00000000 },
+	{ 0x0012ac,   1, 0x04, 0x00000001 },
+	{ 0x000790,   5, 0x04, 0x00000000 },
+	{ 0x00077c,   1, 0x04, 0x00000000 },
+	{ 0x001000,   1, 0x04, 0x00000010 },
+	{ 0x0010fc,   1, 0x04, 0x00000000 },
+	{ 0x001290,   1, 0x04, 0x00000000 },
+	{ 0x000218,   1, 0x04, 0x00000010 },
+	{ 0x0012d8,   1, 0x04, 0x00000000 },
+	{ 0x0012dc,   1, 0x04, 0x00000010 },
+	{ 0x000d94,   1, 0x04, 0x00000001 },
+	{ 0x00155c,   2, 0x04, 0x00000000 },
+	{ 0x001564,   1, 0x04, 0x00000fff },
+	{ 0x001574,   2, 0x04, 0x00000000 },
+	{ 0x00157c,   1, 0x04, 0x000fffff },
+	{ 0x001354,   1, 0x04, 0x00000000 },
+	{ 0x001610,   1, 0x04, 0x00000012 },
+	{ 0x001608,   2, 0x04, 0x00000000 },
+	{ 0x00260c,   1, 0x04, 0x00000000 },
+	{ 0x0007ac,   1, 0x04, 0x00000000 },
+	{ 0x00162c,   1, 0x04, 0x00000003 },
+	{ 0x000210,   1, 0x04, 0x00000000 },
+	{ 0x000320,   1, 0x04, 0x00000000 },
+	{ 0x000324,   6, 0x04, 0x3f800000 },
+	{ 0x000750,   1, 0x04, 0x00000000 },
+	{ 0x000760,   1, 0x04, 0x39291909 },
+	{ 0x000764,   1, 0x04, 0x79695949 },
+	{ 0x000768,   1, 0x04, 0xb9a99989 },
+	{ 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x000770,   1, 0x04, 0x30201000 },
+	{ 0x000774,   1, 0x04, 0x70605040 },
+	{ 0x000778,   1, 0x04, 0x00009080 },
+	{ 0x000780,   1, 0x04, 0x39291909 },
+	{ 0x000784,   1, 0x04, 0x79695949 },
+	{ 0x000788,   1, 0x04, 0xb9a99989 },
+	{ 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+	{ 0x0007d0,   1, 0x04, 0x30201000 },
+	{ 0x0007d4,   1, 0x04, 0x70605040 },
+	{ 0x0007d8,   1, 0x04, 0x00009080 },
+	{ 0x00037c,   1, 0x04, 0x00000001 },
+	{ 0x000740,   2, 0x04, 0x00000000 },
+	{ 0x002600,   1, 0x04, 0x00000000 },
+	{ 0x001918,   1, 0x04, 0x00000000 },
+	{ 0x00191c,   1, 0x04, 0x00000900 },
+	{ 0x001920,   1, 0x04, 0x00000405 },
+	{ 0x001308,   1, 0x04, 0x00000001 },
+	{ 0x001924,   1, 0x04, 0x00000000 },
+	{ 0x0013ac,   1, 0x04, 0x00000000 },
+	{ 0x00192c,   1, 0x04, 0x00000001 },
+	{ 0x00193c,   1, 0x04, 0x00002c1c },
+	{ 0x000d7c,   1, 0x04, 0x00000000 },
+	{ 0x000f8c,   1, 0x04, 0x00000000 },
+	{ 0x0002c0,   1, 0x04, 0x00000001 },
+	{ 0x001510,   1, 0x04, 0x00000000 },
+	{ 0x001940,   1, 0x04, 0x00000000 },
+	{ 0x000ff4,   2, 0x04, 0x00000000 },
+	{ 0x00194c,   2, 0x04, 0x00000000 },
+	{ 0x001968,   1, 0x04, 0x00000000 },
+	{ 0x001590,   1, 0x04, 0x0000003f },
+	{ 0x0007e8,   4, 0x04, 0x00000000 },
+	{ 0x00196c,   1, 0x04, 0x00000011 },
+	{ 0x0002e4,   1, 0x04, 0x0000b001 },
+	{ 0x00036c,   2, 0x04, 0x00000000 },
+	{ 0x00197c,   1, 0x04, 0x00000000 },
+	{ 0x000fcc,   2, 0x04, 0x00000000 },
+	{ 0x0002d8,   1, 0x04, 0x00000040 },
+	{ 0x001980,   1, 0x04, 0x00000080 },
+	{ 0x001504,   1, 0x04, 0x00000080 },
+	{ 0x001984,   1, 0x04, 0x00000000 },
+	{ 0x000300,   1, 0x04, 0x00000001 },
+	{ 0x0013a8,   1, 0x04, 0x00000000 },
+	{ 0x0012ec,   1, 0x04, 0x00000000 },
+	{ 0x001310,   1, 0x04, 0x00000000 },
+	{ 0x001314,   1, 0x04, 0x00000001 },
+	{ 0x001380,   1, 0x04, 0x00000000 },
+	{ 0x001384,   4, 0x04, 0x00000001 },
+	{ 0x001394,   1, 0x04, 0x00000000 },
+	{ 0x00139c,   1, 0x04, 0x00000000 },
+	{ 0x001398,   1, 0x04, 0x00000000 },
+	{ 0x001594,   1, 0x04, 0x00000000 },
+	{ 0x001598,   4, 0x04, 0x00000001 },
+	{ 0x000f54,   3, 0x04, 0x00000000 },
+	{ 0x0019bc,   1, 0x04, 0x00000000 },
+	{ 0x000f9c,   2, 0x04, 0x00000000 },
+	{ 0x0012cc,   1, 0x04, 0x00000000 },
+	{ 0x0012e8,   1, 0x04, 0x00000000 },
+	{ 0x00130c,   1, 0x04, 0x00000001 },
+	{ 0x001360,   8, 0x04, 0x00000000 },
+	{ 0x00133c,   2, 0x04, 0x00000001 },
+	{ 0x001344,   1, 0x04, 0x00000002 },
+	{ 0x001348,   2, 0x04, 0x00000001 },
+	{ 0x001350,   1, 0x04, 0x00000002 },
+	{ 0x001358,   1, 0x04, 0x00000001 },
+	{ 0x0012e4,   1, 0x04, 0x00000000 },
+	{ 0x00131c,   1, 0x04, 0x00000000 },
+	{ 0x001320,   3, 0x04, 0x00000000 },
+	{ 0x0019c0,   1, 0x04, 0x00000000 },
+	{ 0x001140,   1, 0x04, 0x00000000 },
+	{ 0x0019c4,   1, 0x04, 0x00000000 },
+	{ 0x0019c8,   1, 0x04, 0x00001500 },
+	{ 0x00135c,   1, 0x04, 0x00000000 },
+	{ 0x000f90,   1, 0x04, 0x00000000 },
+	{ 0x0019e0,   8, 0x04, 0x00000001 },
+	{ 0x0019cc,   1, 0x04, 0x00000001 },
+	{ 0x0015b8,   1, 0x04, 0x00000000 },
+	{ 0x001a00,   1, 0x04, 0x00001111 },
+	{ 0x001a04,   7, 0x04, 0x00000000 },
+	{ 0x000d6c,   2, 0x04, 0xffff0000 },
+	{ 0x0010f8,   1, 0x04, 0x00001010 },
+	{ 0x000d80,   5, 0x04, 0x00000000 },
+	{ 0x000da0,   1, 0x04, 0x00000000 },
+	{ 0x0007a4,   2, 0x04, 0x00000000 },
+	{ 0x001508,   1, 0x04, 0x80000000 },
+	{ 0x00150c,   1, 0x04, 0x40000000 },
+	{ 0x001668,   1, 0x04, 0x00000000 },
+	{ 0x000318,   2, 0x04, 0x00000008 },
+	{ 0x000d9c,   1, 0x04, 0x00000001 },
+	{ 0x000374,   1, 0x04, 0x00000000 },
+	{ 0x000378,   1, 0x04, 0x00000020 },
+	{ 0x0007dc,   1, 0x04, 0x00000000 },
+	{ 0x00074c,   1, 0x04, 0x00000055 },
+	{ 0x001420,   1, 0x04, 0x00000003 },
+	{ 0x0017bc,   2, 0x04, 0x00000000 },
+	{ 0x0017c4,   1, 0x04, 0x00000001 },
+	{ 0x001008,   1, 0x04, 0x00000008 },
+	{ 0x00100c,   1, 0x04, 0x00000040 },
+	{ 0x001010,   1, 0x04, 0x0000012c },
+	{ 0x000d60,   1, 0x04, 0x00000040 },
+	{ 0x00075c,   1, 0x04, 0x00000003 },
+	{ 0x001018,   1, 0x04, 0x00000020 },
+	{ 0x00101c,   1, 0x04, 0x00000001 },
+	{ 0x001020,   1, 0x04, 0x00000020 },
+	{ 0x001024,   1, 0x04, 0x00000001 },
+	{ 0x001444,   3, 0x04, 0x00000000 },
+	{ 0x000360,   1, 0x04, 0x20164010 },
+	{ 0x000364,   1, 0x04, 0x00000020 },
+	{ 0x000368,   1, 0x04, 0x00000000 },
+	{ 0x000de4,   1, 0x04, 0x00000000 },
+	{ 0x000204,   1, 0x04, 0x00000006 },
+	{ 0x000208,   1, 0x04, 0x00000000 },
+	{ 0x0002cc,   2, 0x04, 0x003fffff },
+	{ 0x001220,   1, 0x04, 0x00000005 },
+	{ 0x000fdc,   1, 0x04, 0x00000000 },
+	{ 0x000f98,   1, 0x04, 0x00400008 },
+	{ 0x001284,   1, 0x04, 0x08000080 },
+	{ 0x001450,   1, 0x04, 0x00400008 },
+	{ 0x001454,   1, 0x04, 0x08000080 },
+	{ 0x000214,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk40xx[] = {
+	{ 0x404010,   5, 0x04, 0x00000000 },
+	{ 0x404024,   1, 0x04, 0x0000e000 },
+	{ 0x404028,   1, 0x04, 0x00000000 },
+	{ 0x4040a8,   1, 0x04, 0x00000000 },
+	{ 0x4040ac,   7, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf800008f },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404130,   1, 0x04, 0x00000000 },
+	{ 0x404134,   1, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x4041a0,   4, 0x04, 0x00000000 },
+	{ 0x404200,   4, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_unk46xx[] = {
+	{ 0x404604,   1, 0x04, 0x00000014 },
+	{ 0x404608,   1, 0x04, 0x00000000 },
+	{ 0x40460c,   1, 0x04, 0x00003fff },
+	{ 0x404610,   1, 0x04, 0x00000100 },
+	{ 0x404618,   4, 0x04, 0x00000000 },
+	{ 0x40462c,   2, 0x04, 0x00000000 },
+	{ 0x404640,   1, 0x04, 0x00000000 },
+	{ 0x404654,   1, 0x04, 0x00000000 },
+	{ 0x404660,   1, 0x04, 0x00000000 },
+	{ 0x404678,   1, 0x04, 0x00000000 },
+	{ 0x40467c,   1, 0x04, 0x00000002 },
+	{ 0x404680,   8, 0x04, 0x00000000 },
+	{ 0x4046a0,   1, 0x04, 0x007f0080 },
+	{ 0x4046a4,   8, 0x04, 0x00000000 },
+	{ 0x4046c8,   3, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_unk47xx[] = {
+	{ 0x404700,   3, 0x04, 0x00000000 },
+	{ 0x404718,   7, 0x04, 0x00000000 },
+	{ 0x404734,   1, 0x04, 0x00000100 },
+	{ 0x404738,   2, 0x04, 0x00000000 },
+	{ 0x404744,   2, 0x04, 0x00000000 },
+	{ 0x404754,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_unk58xx[] = {
+	{ 0x405800,   1, 0x04, 0x0f8000bf },
+	{ 0x405830,   1, 0x04, 0x02180648 },
+	{ 0x405834,   1, 0x04, 0x08000000 },
+	{ 0x405838,   1, 0x04, 0x00000000 },
+	{ 0x405854,   1, 0x04, 0x00000000 },
+	{ 0x405870,   4, 0x04, 0x00000001 },
+	{ 0x405a00,   2, 0x04, 0x00000000 },
+	{ 0x405a18,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk5bxx[] = {
+	{ 0x405b00,   1, 0x04, 0x00000000 },
+	{ 0x405b10,   1, 0x04, 0x00001000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk60xx[] = {
+	{ 0x406020,   1, 0x04, 0x004103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk64xx[] = {
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b4,   2, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x801a00f0 },
+	{ 0x4064c4,   1, 0x04, 0x0192ffff },
+	{ 0x4064c8,   1, 0x04, 0x01800600 },
+	{ 0x4064cc,   9, 0x04, 0x00000000 },
+	{ 0x4064fc,   1, 0x04, 0x0000022a },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk70xx[] = {
+	{ 0x407040,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_unk80xx[] = {
+	{ 0x408000,   2, 0x04, 0x00000000 },
+	{ 0x408008,   1, 0x04, 0x00000030 },
+	{ 0x40800c,   2, 0x04, 0x00000000 },
+	{ 0x408014,   1, 0x04, 0x00000069 },
+	{ 0x408018,   1, 0x04, 0xe100e100 },
+	{ 0x408064,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_rop[] = {
+	{ 0x408800,   1, 0x04, 0x02802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1043e005 },
+	{ 0x408840,   1, 0x04, 0x0000000b },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x62000001 },
+	{ 0x408908,   1, 0x04, 0x00c8102f },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_gpc_0[] = {
+	{ 0x418380,   1, 0x04, 0x00000016 },
+	{ 0x418400,   1, 0x04, 0x38004e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x02200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{ 0x418600,   1, 0x04, 0x0000001f },
+	{ 0x418684,   1, 0x04, 0x0000000f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   3, 0x04, 0x00000000 },
+	{ 0x418800,   1, 0x04, 0x7006860a },
+	{ 0x418808,   3, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00000044 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100018 },
+	{ 0x41891c,   1, 0x04, 0x00ff00ff },
+	{ 0x418924,   1, 0x04, 0x00000000 },
+	{ 0x418928,   1, 0x04, 0x00ffff00 },
+	{ 0x41892c,   1, 0x04, 0x0000ff00 },
+	{ 0x418b00,   1, 0x04, 0x00000006 },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c40,   1, 0x04, 0xffffffff },
+	{ 0x418c6c,   1, 0x04, 0x00000001 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{ 0x419000,   1, 0x04, 0x00000780 },
+	{ 0x419004,   2, 0x04, 0x00000000 },
+	{ 0x419014,   1, 0x04, 0x00000004 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_tpc[] = {
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x00000129 },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{ 0x419a00,   1, 0x04, 0x000000f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000021 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x0000c000 },
+	{ 0x419a20,   1, 0x04, 0x00000800 },
+	{ 0x419a30,   1, 0x04, 0x00000001 },
+	{ 0x419ac4,   1, 0x04, 0x0037f440 },
+	{ 0x419c00,   1, 0x04, 0x0000000a },
+	{ 0x419c04,   1, 0x04, 0x80000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3efbefbe },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00003203 },
+	{ 0x419e04,   3, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00000402 },
+	{ 0x419e44,   1, 0x04, 0x0013eff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000007f },
+	{ 0x419e50,  19, 0x04, 0x00000000 },
+	{ 0x419eac,   1, 0x04, 0x00001f8f },
+	{ 0x419eb0,   1, 0x04, 0x00000d3f },
+	{ 0x419ec8,   1, 0x04, 0x0001304f },
+	{ 0x419f30,   8, 0x04, 0x00000000 },
+	{ 0x419f58,   1, 0x04, 0x00000000 },
+	{ 0x419f70,   1, 0x04, 0x00000000 },
+	{ 0x419f78,   1, 0x04, 0x0000000b },
+	{ 0x419f7c,   1, 0x04, 0x0000027a },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk[] = {
+	{ 0x41be24,   1, 0x04, 0x00000006 },
+	{ 0x41bec0,   1, 0x04, 0x12180000 },
+	{ 0x41bec4,   1, 0x04, 0x00037f7f },
+	{ 0x41bee4,   1, 0x04, 0x06480430 },
+	{ 0x41bf00,   1, 0x04, 0x0a418820 },
+	{ 0x41bf04,   1, 0x04, 0x062080e6 },
+	{ 0x41bf08,   1, 0x04, 0x020398a4 },
+	{ 0x41bf0c,   1, 0x04, 0x0e629062 },
+	{ 0x41bf10,   1, 0x04, 0x0a418820 },
+	{ 0x41bf14,   1, 0x04, 0x000000e6 },
+	{ 0x41bfd0,   1, 0x04, 0x00900103 },
+	{ 0x41bfe0,   1, 0x04, 0x00400001 },
+	{ 0x41bfe4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static void
+nve4_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+	u32 magic[GPC_MAX][2];
+	u32 offset;
+	int gpc;
+
+	mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+	mmio_list(0x40800c, 0x00000000,  8, 1);
+	mmio_list(0x408010, 0x80000000,  0, 0);
+	mmio_list(0x419004, 0x00000000,  8, 1);
+	mmio_list(0x419008, 0x00000000,  0, 0);
+	mmio_list(0x4064cc, 0x80000000,  0, 0);
+	mmio_list(0x408004, 0x00000000,  8, 0);
+	mmio_list(0x408008, 0x80000030,  0, 0);
+	mmio_list(0x418808, 0x00000000,  8, 0);
+	mmio_list(0x41880c, 0x80000030,  0, 0);
+	mmio_list(0x4064c8, 0x01800600,  0, 0);
+	mmio_list(0x418810, 0x80000000, 12, 2);
+	mmio_list(0x419848, 0x10000000, 12, 2);
+
+	mmio_list(0x405830, 0x02180648,  0, 0);
+	mmio_list(0x4064c4, 0x0192ffff,  0, 0);
+
+	for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+		u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
+		u16 magic1 = 0x0648 * priv->tpc_nr[gpc];
+		magic[gpc][0]  = 0x10000000 | (magic0 << 16) | offset;
+		magic[gpc][1]  = 0x00000000 | (magic1 << 16);
+		offset += 0x0324 * priv->tpc_nr[gpc];
+	}
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
+		mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
+		offset += 0x07ff * priv->tpc_nr[gpc];
+	}
+
+	mmio_list(0x17e91c, 0x06060609, 0, 0);
+	mmio_list(0x17e920, 0x00090a05, 0, 0);
+}
+
+void
+nve4_grctx_generate_unkn(struct nvc0_graph_priv *priv)
+{
+	nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
+	nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
+	nv_mask(priv, 0x41be08, 0x00000004, 0x00000004);
+	nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
+	nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
+	nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
+}
+
+void
+nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *priv)
+{
+	u32 data[6] = {}, data2[2] = {};
+	u8  tpcnr[GPC_MAX];
+	u8  shift, ntpcv;
+	int gpc, tpc, i;
+
+	/* calculate first set of magics */
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+	gpc = -1;
+	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpcnr[gpc]--;
+
+		data[tpc / 6] |= gpc << ((tpc % 6) * 5);
+	}
+
+	for (; tpc < 32; tpc++)
+		data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+
+	/* and the second... */
+	shift = 0;
+	ntpcv = priv->tpc_total;
+	while (!(ntpcv & (1 << 4))) {
+		ntpcv <<= 1;
+		shift++;
+	}
+
+	data2[0]  = (ntpcv << 16);
+	data2[0] |= (shift << 21);
+	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+	for (i = 1; i < 7; i++)
+		data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+	/* GPC_BROADCAST */
+	nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
+
+	/* GPC_BROADCAST.TP_BROADCAST */
+	nv_wr32(priv, 0x41bfd0, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr | data2[0]);
+	nv_wr32(priv, 0x41bfe4, data2[1]);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
+
+	/* UNK78xx */
+	nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+				 priv->magic_not_rop_nr);
+	for (i = 0; i < 6; i++)
+		nv_wr32(priv, 0x40780c + (i * 4), data[i]);
+}
+
+void
+nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+	struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+	int i;
+
+	nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+
+	for (i = 0; oclass->hub[i]; i++)
+		nvc0_graph_mmio(priv, oclass->hub[i]);
+	for (i = 0; oclass->gpc[i]; i++)
+		nvc0_graph_mmio(priv, oclass->gpc[i]);
+
+	nv_wr32(priv, 0x404154, 0x00000000);
+
+	oclass->mods(priv, info);
+	oclass->unkn(priv);
+
+	nvc0_grctx_generate_tpcid(priv);
+	nvc0_grctx_generate_r406028(priv);
+	nve4_grctx_generate_r418bb8(priv);
+	nvc0_grctx_generate_r406800(priv);
+
+	for (i = 0; i < 8; i++)
+		nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+
+	nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
+	if (priv->gpc_nr == 1) {
+		nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
+		nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
+	} else {
+		nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
+		nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
+	}
+	nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
+
+	nvc0_graph_icmd(priv, oclass->icmd);
+	nv_wr32(priv, 0x404154, 0x00000400);
+	nvc0_graph_mthd(priv, oclass->mthd);
+	nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
+
+	nv_mask(priv, 0x418800, 0x00200000, 0x00200000);
+	nv_mask(priv, 0x41be10, 0x00800000, 0x00800000);
+}
+
+static struct nvc0_graph_init *
+nve4_grctx_init_hub[] = {
+	nvc0_grctx_init_base,
+	nve4_grctx_init_unk40xx,
+	nvc0_grctx_init_unk44xx,
+	nve4_grctx_init_unk46xx,
+	nve4_grctx_init_unk47xx,
+	nve4_grctx_init_unk58xx,
+	nve4_grctx_init_unk5bxx,
+	nve4_grctx_init_unk60xx,
+	nve4_grctx_init_unk64xx,
+	nve4_grctx_init_unk70xx,
+	nvc0_grctx_init_unk78xx,
+	nve4_grctx_init_unk80xx,
+	nve4_grctx_init_rop,
+	NULL
+};
+
+struct nvc0_graph_init *
+nve4_grctx_init_gpc[] = {
+	nve4_grctx_init_gpc_0,
+	nvc0_grctx_init_gpc_1,
+	nve4_grctx_init_tpc,
+	nve4_grctx_init_unk,
+	NULL
+};
+
+static struct nvc0_graph_mthd
+nve4_grctx_init_mthd[] = {
+	{ 0xa097, nve4_grctx_init_a097, },
+	{ 0x902d, nvc0_grctx_init_902d, },
+	{ 0x902d, nvc0_grctx_init_mthd_magic, },
+	{}
+};
+
+struct nouveau_oclass *
+nve4_grctx_oclass = &(struct nvc0_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xe4),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+	.main = nve4_grctx_generate_main,
+	.mods = nve4_grctx_generate_mods,
+	.unkn = nve4_grctx_generate_unkn,
+	.hub  = nve4_grctx_init_hub,
+	.gpc  = nve4_grctx_init_gpc,
+	.icmd = nve4_grctx_init_icmd,
+	.mthd = nve4_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
new file mode 100644
index 0000000..dcb2ebb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk40xx[] = {
+	{ 0x404004,   8, 0x04, 0x00000000 },
+	{ 0x404024,   1, 0x04, 0x0000e000 },
+	{ 0x404028,   8, 0x04, 0x00000000 },
+	{ 0x4040a8,   8, 0x04, 0x00000000 },
+	{ 0x4040c8,   1, 0x04, 0xf800008f },
+	{ 0x4040d0,   6, 0x04, 0x00000000 },
+	{ 0x4040e8,   1, 0x04, 0x00001000 },
+	{ 0x4040f8,   1, 0x04, 0x00000000 },
+	{ 0x404100,  10, 0x04, 0x00000000 },
+	{ 0x404130,   2, 0x04, 0x00000000 },
+	{ 0x404138,   1, 0x04, 0x20000040 },
+	{ 0x404150,   1, 0x04, 0x0000002e },
+	{ 0x404154,   1, 0x04, 0x00000400 },
+	{ 0x404158,   1, 0x04, 0x00000200 },
+	{ 0x404164,   1, 0x04, 0x00000055 },
+	{ 0x40417c,   2, 0x04, 0x00000000 },
+	{ 0x4041a0,   4, 0x04, 0x00000000 },
+	{ 0x404200,   1, 0x04, 0x0000a197 },
+	{ 0x404204,   1, 0x04, 0x0000a1c0 },
+	{ 0x404208,   1, 0x04, 0x0000a140 },
+	{ 0x40420c,   1, 0x04, 0x0000902d },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk44xx[] = {
+	{ 0x404404,  12, 0x04, 0x00000000 },
+	{ 0x404438,   1, 0x04, 0x00000000 },
+	{ 0x404460,   2, 0x04, 0x00000000 },
+	{ 0x404468,   1, 0x04, 0x00ffffff },
+	{ 0x40446c,   1, 0x04, 0x00000000 },
+	{ 0x404480,   1, 0x04, 0x00000001 },
+	{ 0x404498,   1, 0x04, 0x00000001 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk5bxx[] = {
+	{ 0x405b00,   1, 0x04, 0x00000000 },
+	{ 0x405b10,   1, 0x04, 0x00001000 },
+	{ 0x405b20,   1, 0x04, 0x04000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk60xx[] = {
+	{ 0x406020,   1, 0x04, 0x034103c1 },
+	{ 0x406028,   4, 0x04, 0x00000001 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk64xx[] = {
+	{ 0x4064a8,   1, 0x04, 0x00000000 },
+	{ 0x4064ac,   1, 0x04, 0x00003fff },
+	{ 0x4064b0,   3, 0x04, 0x00000000 },
+	{ 0x4064c0,   1, 0x04, 0x802000f0 },
+	{ 0x4064c4,   1, 0x04, 0x0192ffff },
+	{ 0x4064c8,   1, 0x04, 0x018007c0 },
+	{ 0x4064cc,   9, 0x04, 0x00000000 },
+	{ 0x4064fc,   1, 0x04, 0x0000022a },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk88xx[] = {
+	{ 0x408800,   1, 0x04, 0x12802a3c },
+	{ 0x408804,   1, 0x04, 0x00000040 },
+	{ 0x408808,   1, 0x04, 0x1003e005 },
+	{ 0x408840,   1, 0x04, 0x0000000b },
+	{ 0x408900,   1, 0x04, 0x3080b801 },
+	{ 0x408904,   1, 0x04, 0x62000001 },
+	{ 0x408908,   1, 0x04, 0x00c8102f },
+	{ 0x408980,   1, 0x04, 0x0000011d },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_gpc_0[] = {
+	{ 0x418380,   1, 0x04, 0x00000016 },
+	{ 0x418400,   1, 0x04, 0x38004e00 },
+	{ 0x418404,   1, 0x04, 0x71e0ffff },
+	{ 0x41840c,   1, 0x04, 0x00001008 },
+	{ 0x418410,   1, 0x04, 0x0fff0fff },
+	{ 0x418414,   1, 0x04, 0x02200fff },
+	{ 0x418450,   6, 0x04, 0x00000000 },
+	{ 0x418468,   1, 0x04, 0x00000001 },
+	{ 0x41846c,   2, 0x04, 0x00000000 },
+	{ 0x418600,   1, 0x04, 0x0000001f },
+	{ 0x418684,   1, 0x04, 0x0000000f },
+	{ 0x418700,   1, 0x04, 0x00000002 },
+	{ 0x418704,   1, 0x04, 0x00000080 },
+	{ 0x418708,   3, 0x04, 0x00000000 },
+	{ 0x418800,   1, 0x04, 0x7006860a },
+	{ 0x418808,   1, 0x04, 0x00000000 },
+	{ 0x41880c,   1, 0x04, 0x00000030 },
+	{ 0x418810,   1, 0x04, 0x00000000 },
+	{ 0x418828,   1, 0x04, 0x00000044 },
+	{ 0x418830,   1, 0x04, 0x10000001 },
+	{ 0x4188d8,   1, 0x04, 0x00000008 },
+	{ 0x4188e0,   1, 0x04, 0x01000000 },
+	{ 0x4188e8,   5, 0x04, 0x00000000 },
+	{ 0x4188fc,   1, 0x04, 0x20100018 },
+	{ 0x41891c,   1, 0x04, 0x00ff00ff },
+	{ 0x418924,   1, 0x04, 0x00000000 },
+	{ 0x418928,   1, 0x04, 0x00ffff00 },
+	{ 0x41892c,   1, 0x04, 0x0000ff00 },
+	{ 0x418b00,   1, 0x04, 0x00000006 },
+	{ 0x418b08,   1, 0x04, 0x0a418820 },
+	{ 0x418b0c,   1, 0x04, 0x062080e6 },
+	{ 0x418b10,   1, 0x04, 0x020398a4 },
+	{ 0x418b14,   1, 0x04, 0x0e629062 },
+	{ 0x418b18,   1, 0x04, 0x0a418820 },
+	{ 0x418b1c,   1, 0x04, 0x000000e6 },
+	{ 0x418bb8,   1, 0x04, 0x00000103 },
+	{ 0x418c08,   1, 0x04, 0x00000001 },
+	{ 0x418c10,   8, 0x04, 0x00000000 },
+	{ 0x418c40,   1, 0x04, 0xffffffff },
+	{ 0x418c6c,   1, 0x04, 0x00000001 },
+	{ 0x418c80,   1, 0x04, 0x20200004 },
+	{ 0x418c8c,   1, 0x04, 0x00000001 },
+	{ 0x418d24,   1, 0x04, 0x00000000 },
+	{ 0x419000,   1, 0x04, 0x00000780 },
+	{ 0x419004,   2, 0x04, 0x00000000 },
+	{ 0x419014,   1, 0x04, 0x00000004 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_tpc[] = {
+	{ 0x419848,   1, 0x04, 0x00000000 },
+	{ 0x419864,   1, 0x04, 0x00000129 },
+	{ 0x419888,   1, 0x04, 0x00000000 },
+	{ 0x419a00,   1, 0x04, 0x000000f0 },
+	{ 0x419a04,   1, 0x04, 0x00000001 },
+	{ 0x419a08,   1, 0x04, 0x00000021 },
+	{ 0x419a0c,   1, 0x04, 0x00020000 },
+	{ 0x419a10,   1, 0x04, 0x00000000 },
+	{ 0x419a14,   1, 0x04, 0x00000200 },
+	{ 0x419a1c,   1, 0x04, 0x0000c000 },
+	{ 0x419a20,   1, 0x04, 0x00020800 },
+	{ 0x419a30,   1, 0x04, 0x00000001 },
+	{ 0x419ac4,   1, 0x04, 0x0037f440 },
+	{ 0x419c00,   1, 0x04, 0x0000001a },
+	{ 0x419c04,   1, 0x04, 0x80000006 },
+	{ 0x419c08,   1, 0x04, 0x00000002 },
+	{ 0x419c20,   1, 0x04, 0x00000000 },
+	{ 0x419c24,   1, 0x04, 0x00084210 },
+	{ 0x419c28,   1, 0x04, 0x3efbefbe },
+	{ 0x419ce8,   1, 0x04, 0x00000000 },
+	{ 0x419cf4,   1, 0x04, 0x00000203 },
+	{ 0x419e04,   1, 0x04, 0x00000000 },
+	{ 0x419e08,   1, 0x04, 0x0000001d },
+	{ 0x419e0c,   1, 0x04, 0x00000000 },
+	{ 0x419e10,   1, 0x04, 0x00001c02 },
+	{ 0x419e44,   1, 0x04, 0x0013eff2 },
+	{ 0x419e48,   1, 0x04, 0x00000000 },
+	{ 0x419e4c,   1, 0x04, 0x0000007f },
+	{ 0x419e50,   2, 0x04, 0x00000000 },
+	{ 0x419e58,   1, 0x04, 0x00000001 },
+	{ 0x419e5c,   3, 0x04, 0x00000000 },
+	{ 0x419e68,   1, 0x04, 0x00000002 },
+	{ 0x419e6c,  12, 0x04, 0x00000000 },
+	{ 0x419eac,   1, 0x04, 0x00001fcf },
+	{ 0x419eb0,   1, 0x04, 0x0db00da0 },
+	{ 0x419eb8,   1, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0001304f },
+	{ 0x419f30,   4, 0x04, 0x00000000 },
+	{ 0x419f40,   1, 0x04, 0x00000018 },
+	{ 0x419f44,   3, 0x04, 0x00000000 },
+	{ 0x419f58,   1, 0x04, 0x00000000 },
+	{ 0x419f70,   1, 0x04, 0x00007300 },
+	{ 0x419f78,   1, 0x04, 0x000000eb },
+	{ 0x419f7c,   1, 0x04, 0x00000404 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk[] = {
+	{ 0x41be24,   1, 0x04, 0x00000006 },
+	{ 0x41bec0,   1, 0x04, 0x10000000 },
+	{ 0x41bec4,   1, 0x04, 0x00037f7f },
+	{ 0x41bee4,   1, 0x04, 0x00000000 },
+	{ 0x41bf00,   1, 0x04, 0x0a418820 },
+	{ 0x41bf04,   1, 0x04, 0x062080e6 },
+	{ 0x41bf08,   1, 0x04, 0x020398a4 },
+	{ 0x41bf0c,   1, 0x04, 0x0e629062 },
+	{ 0x41bf10,   1, 0x04, 0x0a418820 },
+	{ 0x41bf14,   1, 0x04, 0x000000e6 },
+	{ 0x41bfd0,   1, 0x04, 0x00900103 },
+	{ 0x41bfe0,   1, 0x04, 0x00400001 },
+	{ 0x41bfe4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static void
+nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+	u32 magic[GPC_MAX][4];
+	u32 offset;
+	int gpc;
+
+	mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+	mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+	mmio_list(0x40800c, 0x00000000,  8, 1);
+	mmio_list(0x408010, 0x80000000,  0, 0);
+	mmio_list(0x419004, 0x00000000,  8, 1);
+	mmio_list(0x419008, 0x00000000,  0, 0);
+	mmio_list(0x4064cc, 0x80000000,  0, 0);
+	mmio_list(0x408004, 0x00000000,  8, 0);
+	mmio_list(0x408008, 0x80000030,  0, 0);
+	mmio_list(0x418808, 0x00000000,  8, 0);
+	mmio_list(0x41880c, 0x80000030,  0, 0);
+	mmio_list(0x4064c8, 0x01800600,  0, 0);
+	mmio_list(0x418810, 0x80000000, 12, 2);
+	mmio_list(0x419848, 0x10000000, 12, 2);
+
+	mmio_list(0x405830, 0x02180648,  0, 0);
+	mmio_list(0x4064c4, 0x0192ffff,  0, 0);
+
+	for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+		u16 magic0 = 0x0218 * (priv->tpc_nr[gpc] - 1);
+		u16 magic1 = 0x0648 * (priv->tpc_nr[gpc] - 1);
+		u16 magic2 = 0x0218;
+		u16 magic3 = 0x0648;
+		magic[gpc][0]  = 0x10000000 | (magic0 << 16) | offset;
+		magic[gpc][1]  = 0x00000000 | (magic1 << 16);
+		offset += 0x0324 * (priv->tpc_nr[gpc] - 1);;
+		magic[gpc][2]  = 0x10000000 | (magic2 << 16) | offset;
+		magic[gpc][3]  = 0x00000000 | (magic3 << 16);
+		offset += 0x0324;
+	}
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
+		mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
+		offset += 0x07ff * (priv->tpc_nr[gpc] - 1);
+		mmio_list(GPC_UNIT(gpc, 0x32c0), magic[gpc][2], 0, 0);
+		mmio_list(GPC_UNIT(gpc, 0x32e4), magic[gpc][3] | offset, 0, 0);
+		offset += 0x07ff;
+	}
+
+	mmio_list(0x17e91c, 0x06060609, 0, 0);
+	mmio_list(0x17e920, 0x00090a05, 0, 0);
+}
+
+static struct nvc0_graph_init *
+nvf0_grctx_init_hub[] = {
+	nvc0_grctx_init_base,
+	nvf0_grctx_init_unk40xx,
+	nvf0_grctx_init_unk44xx,
+	nve4_grctx_init_unk46xx,
+	nve4_grctx_init_unk47xx,
+	nve4_grctx_init_unk58xx,
+	nvf0_grctx_init_unk5bxx,
+	nvf0_grctx_init_unk60xx,
+	nvf0_grctx_init_unk64xx,
+	nve4_grctx_init_unk80xx,
+	nvf0_grctx_init_unk88xx,
+	nvd9_grctx_init_rop,
+	NULL
+};
+
+struct nvc0_graph_init *
+nvf0_grctx_init_gpc[] = {
+	nvf0_grctx_init_gpc_0,
+	nvc0_grctx_init_gpc_1,
+	nvf0_grctx_init_tpc,
+	nvf0_grctx_init_unk,
+	NULL
+};
+
+static struct nvc0_graph_mthd
+nvf0_grctx_init_mthd[] = {
+	{ 0xa197, nvc1_grctx_init_9097, },
+	{ 0x902d, nvc0_grctx_init_902d, },
+	{ 0x902d, nvc0_grctx_init_mthd_magic, },
+	{}
+};
+
+struct nouveau_oclass *
+nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) {
+	.base.handle = NV_ENGCTX(GR, 0xf0),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_context_ctor,
+		.dtor = nvc0_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = _nouveau_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+	.main = nve4_grctx_generate_main,
+	.mods = nvf0_grctx_generate_mods,
+	.unkn = nve4_grctx_generate_unkn,
+	.hub  = nvf0_grctx_init_hub,
+	.gpc  = nvf0_grctx_init_gpc,
+	.icmd = nvc0_grctx_init_icmd,
+	.mthd = nvf0_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
similarity index 88%
rename from drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc
rename to drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
index e6b2288..5d24b6d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
@@ -23,42 +23,7 @@
  * Authors: Ben Skeggs
  */
 
-define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)')
-define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))')
-
-ifdef(`include_code', `
-// Error codes
-define(`E_BAD_COMMAND', 0x01)
-define(`E_CMD_OVERFLOW', 0x02)
-
-// Util macros to help with debugging ucode hangs etc
-define(`T_WAIT', 0)
-define(`T_MMCTX', 1)
-define(`T_STRWAIT', 2)
-define(`T_STRINIT', 3)
-define(`T_AUTO', 4)
-define(`T_CHAN', 5)
-define(`T_LOAD', 6)
-define(`T_SAVE', 7)
-define(`T_LCHAN', 8)
-define(`T_LCTXH', 9)
-
-define(`trace_set', `
-	mov $r8 0x83c
-	shl b32 $r8 6
-	clear b32 $r9
-	bset $r9 $1
-	iowr I[$r8 + 0x000] $r9		// CC_SCRATCH[7]
-')
-
-define(`trace_clr', `
-	mov $r8 0x85c
-	shl b32 $r8 6
-	clear b32 $r9
-	bset $r9 $1
-	iowr I[$r8 + 0x000] $r9		// CC_SCRATCH[7]
-')
-
+#ifdef INCLUDE_CODE
 // queue_put - add request to queue
 //
 // In : $r13 queue pointer
@@ -178,27 +143,37 @@
 	iowr I[$r8 + 0x000] $r0
 	ret
 
-// wait_done{z,o} - wait on FUC_DONE bit to become clear/set
+// wait_donez - wait on FUC_DONE bit to become clear
 //
 // In : $r10 bit to wait on
 //
-define(`wait_done', `
-$1:
+wait_donez:
+	trace_set(T_WAIT);
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
+	wait_donez_ne:
+		nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
+		xbit $r8 $r8 $r10
+		bra ne #wait_donez_ne
+	trace_clr(T_WAIT)
+	ret
+
+// wait_doneo - wait on FUC_DONE bit to become set
+//
+// In : $r10 bit to wait on
+//
+wait_doneo:
 	trace_set(T_WAIT);
 	mov $r8 0x818
 	shl b32 $r8 6
-	iowr I[$r8 + 0x000] $r10	// CC_SCRATCH[6] = wait bit
-	wait_done_$1:
+	iowr I[$r8 + 0x000] $r10
+	wait_doneo_e:
 		mov $r8 0x400
 		shl b32 $r8 6
-		iord $r8 I[$r8 + 0x000]	// DONE
+		iord $r8 I[$r8 + 0x000]
 		xbit $r8 $r8 $r10
-		bra $2 #wait_done_$1
+		bra e #wait_doneo_e
 	trace_clr(T_WAIT)
 	ret
-')
-wait_done(wait_donez, ne)
-wait_done(wait_doneo, e)
 
 // mmctx_size - determine size of a mmio list transfer
 //
@@ -397,4 +372,4 @@
 	sub b32 $r15 $r14 $r15
 	trace_clr(T_STRINIT)
 	ret
-')
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
new file mode 100644
index 0000000..5547c1b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
@@ -0,0 +1,404 @@
+/* fuc microcode for nvc0 PGRAPH/GPC
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* TODO
+ * - bracket certain functions with scratch writes, useful for debugging
+ * - watchdog timer around ctx operations
+ */
+
+#ifdef INCLUDE_DATA
+gpc_mmio_list_head:	.b32 #mmio_list_base
+gpc_mmio_list_tail:
+tpc_mmio_list_head:	.b32 #mmio_list_base
+tpc_mmio_list_tail:
+unk_mmio_list_head:	.b32 #mmio_list_base
+unk_mmio_list_tail:	.b32 #mmio_list_base
+
+gpc_id:			.b32 0
+
+tpc_count:		.b32 0
+tpc_mask:		.b32 0
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+unk_count:		.b32 0
+unk_mask:		.b32 0
+#endif
+
+cmd_queue:		queue_init
+
+mmio_list_base:
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see nvc0.fuc)
+//
+error:
+	push $r14
+	mov $r14 -0x67ec 	// 0x9814
+	sethi $r14 0x400000
+	call #nv_wr32		// HUB_CTXCTL_CC_SCRATCH[5] = error code
+	add b32 $r14 0x41c
+	mov $r15 1
+	call #nv_wr32		// HUB_CTXCTL_INTR_UP_SET
+	pop $r14
+	ret
+
+// GPC fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Input:
+//   CC_SCRATCH[1]: context base
+//
+// Output:
+//   CC_SCRATCH[0]:
+//	     31:31: set to signal completion
+//   CC_SCRATCH[1]:
+//	      31:0: GPC context size
+//
+init:
+	clear b32 $r0
+	mov $sp $r0
+
+	// enable fifo access
+	mov $r1 0x1200
+	mov $r2 2
+	iowr I[$r1 + 0x000] $r2		// FIFO_ENABLE
+
+	// setup i0 handler, and route all interrupts to it
+	mov $r1 #ih
+	mov $iv0 $r1
+	mov $r1 0x400
+	iowr I[$r1 + 0x300] $r0		// INTR_DISPATCH
+
+	// enable fifo interrupt
+	mov $r2 4
+	iowr I[$r1 + 0x000] $r2		// INTR_EN_SET
+
+	// enable interrupts
+	bset $flags ie0
+
+	// figure out which GPC we are, and how many TPCs we have
+	mov $r1 0x608
+	shl b32 $r1 6
+	iord $r2 I[$r1 + 0x000]		// UNITS
+	mov $r3 1
+	and $r2 0x1f
+	shl b32 $r3 $r2
+	sub b32 $r3 1
+	st b32 D[$r0 + #tpc_count] $r2
+	st b32 D[$r0 + #tpc_mask] $r3
+	add b32 $r1 0x400
+	iord $r2 I[$r1 + 0x000]		// MYINDEX
+	st b32 D[$r0 + #gpc_id] $r2
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+	// figure out which, and how many, UNKs are actually present
+	mov $r14 0x0c30
+	sethi $r14 0x500000
+	clear b32 $r2
+	clear b32 $r3
+	clear b32 $r4
+	init_unk_loop:
+		call #nv_rd32
+		cmp b32 $r15 0
+		bra z #init_unk_next
+			mov $r15 1
+			shl b32 $r15 $r2
+			or $r4 $r15
+			add b32 $r3 1
+		init_unk_next:
+		add b32 $r2 1
+		add b32 $r14 4
+		cmp b32 $r2 NV_PGRAPH_GPCX_UNK__SIZE
+		bra ne #init_unk_loop
+	init_unk_done:
+	st b32 D[$r0 + #unk_count] $r3
+	st b32 D[$r0 + #unk_mask] $r4
+#endif
+
+	// initialise context base, and size tracking
+	nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0)
+	clear b32 $r3		// track GPC context size here
+
+	// set mmctx base addresses now so we don't have to do it later,
+	// they don't currently ever change
+	mov $r4 0x700
+	shl b32 $r4 6
+	shr b32 $r5 $r2 8
+	iowr I[$r4 + 0x000] $r5		// MMCTX_SAVE_SWBASE
+	iowr I[$r4 + 0x100] $r5		// MMCTX_LOAD_SWBASE
+
+	// calculate GPC mmio context size
+	ld b32 $r14 D[$r0 + #gpc_mmio_list_head]
+	ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]
+	call #mmctx_size
+	add b32 $r2 $r15
+	add b32 $r3 $r15
+
+	// calculate per-TPC mmio context size
+	ld b32 $r14 D[$r0 + #tpc_mmio_list_head]
+	ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]
+	call #mmctx_size
+	ld b32 $r14 D[$r0 + #tpc_count]
+	mulu $r14 $r15
+	add b32 $r2 $r14
+	add b32 $r3 $r14
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+	// calculate per-UNK mmio context size
+	ld b32 $r14 D[$r0 + #unk_mmio_list_head]
+	ld b32 $r15 D[$r0 + #unk_mmio_list_tail]
+	call #mmctx_size
+	ld b32 $r14 D[$r0 + #unk_count]
+	mulu $r14 $r15
+	add b32 $r2 $r14
+	add b32 $r3 $r14
+#endif
+
+	// round up base/size to 256 byte boundary (for strand SWBASE)
+	add b32 $r4 0x1300
+	shr b32 $r3 2
+	iowr I[$r4 + 0x000] $r3		// MMCTX_LOAD_COUNT, wtf for?!?
+	shr b32 $r2 8
+	shr b32 $r3 6
+	add b32 $r2 1
+	add b32 $r3 1
+	shl b32 $r2 8
+	shl b32 $r3 8
+
+	// calculate size of strand context data
+	mov b32 $r15 $r2
+	call #strand_ctx_init
+	add b32 $r3 $r15
+
+	// save context size, and tell HUB we're done
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)
+	clear b32 $r2
+	bset $r2 31
+	nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(0), 0, $r2)
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+	bset $flags $p0
+	sleep $p0
+	mov $r13 #cmd_queue
+	call #queue_get
+	bra $p1 #main
+
+	// 0x0000-0x0003 are all context transfers
+	cmpu b32 $r14 0x04
+	bra nc #main_not_ctx_xfer
+		// fetch $flags and mask off $p1/$p2
+		mov $r1 $flags
+		mov $r2 0x0006
+		not b32 $r2
+		and $r1 $r2
+		// set $p1/$p2 according to transfer type
+		shl b32 $r14 1
+		or $r1 $r14
+		mov $flags $r1
+		// transfer context data
+		call #ctx_xfer
+		bra #main
+
+	main_not_ctx_xfer:
+	shl b32 $r15 $r14 16
+	or $r15 E_BAD_COMMAND
+	call #error
+	bra #main
+
+// interrupt handler
+ih:
+	push $r8
+	mov $r8 $flags
+	push $r8
+	push $r9
+	push $r10
+	push $r11
+	push $r13
+	push $r14
+	push $r15
+	clear b32 $r0
+
+	// incoming fifo command?
+	iord $r10 I[$r0 + 0x200]	// INTR
+	and $r11 $r10 0x00000004
+	bra e #ih_no_fifo
+		// queue incoming fifo command for later processing
+		mov $r11 0x1900
+		mov $r13 #cmd_queue
+		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
+		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
+		call #queue_put
+		add b32 $r11 0x400
+		mov $r14 1
+		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
+
+	// ack, and wake up main()
+	ih_no_fifo:
+	iowr I[$r0 + 0x100] $r10	// INTR_ACK
+
+	pop $r15
+	pop $r14
+	pop $r13
+	pop $r11
+	pop $r10
+	pop $r9
+	pop $r8
+	mov $flags $r8
+	pop $r8
+	bclr $flags $p0
+	iret
+
+// Set this GPC's bit in HUB_BAR, used to signal completion of various
+// activities to the HUB fuc
+//
+hub_barrier_done:
+	mov $r15 1
+	ld b32 $r14 D[$r0 + #gpc_id]
+	shl b32 $r15 $r14
+	mov $r14 -0x6be8 	// 0x409418 - HUB_BAR_SET
+	sethi $r14 0x400000
+	call #nv_wr32
+	ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off?  Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+	mov $r14 0x614
+	shl b32 $r14 6
+	mov $r15 0x020
+	iowr I[$r14] $r15	// GPC_RED_SWITCH = POWER
+	mov $r15 8
+	ctx_redswitch_delay:
+		sub b32 $r15 1
+		bra ne #ctx_redswitch_delay
+	mov $r15 0xa20
+	iowr I[$r14] $r15	// GPC_RED_SWITCH = UNK11, ENABLE, POWER
+	ret
+
+// Transfer GPC context data between GPU and storage area
+//
+// In: $r15 context base address
+//     $p1 clear on save, set on load
+//     $p2 set if opposite direction done/will be done, so:
+//		on save it means: "a load will follow this save"
+//		on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+	// set context base address
+	mov $r1 0xa04
+	shl b32 $r1 6
+	iowr I[$r1 + 0x000] $r15// MEM_BASE
+	bra not $p1 #ctx_xfer_not_load
+		call #ctx_redswitch
+	ctx_xfer_not_load:
+
+	// strands
+	mov $r1 0x4afc
+	sethi $r1 0x20000
+	mov $r2 0xc
+	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
+	call #strand_wait
+	mov $r2 0x47fc
+	sethi $r2 0x20000
+	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
+	xbit $r2 $flags $p1
+	add b32 $r2 3
+	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
+
+	// mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 2		// first
+	mov $r11 0x0000
+	sethi $r11 0x500000
+	ld b32 $r12 D[$r0 + #gpc_id]
+	shl b32 $r12 15
+	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn
+	ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
+	ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
+	mov $r14 0		// not multi
+	call #mmctx_xfer
+
+	// per-TPC mmio context
+	xbit $r10 $flags $p1	// direction
+#if !NV_PGRAPH_GPCX_UNK__SIZE
+	or $r10 4		// last
+#endif
+	mov $r11 0x4000
+	sethi $r11 0x500000	// base = NV_PGRAPH_GPC0_TPC0
+	ld b32 $r12 D[$r0 + #gpc_id]
+	shl b32 $r12 15
+	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_TPC0
+	ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
+	ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
+	ld b32 $r15 D[$r0 + #tpc_mask]
+	mov $r14 0x800		// stride = 0x800
+	call #mmctx_xfer
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+	// per-UNK mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 4		// last
+	mov $r11 0x3000
+	sethi $r11 0x500000	// base = NV_PGRAPH_GPC0_UNK0
+	ld b32 $r12 D[$r0 + #gpc_id]
+	shl b32 $r12 15
+	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_UNK0
+	ld b32 $r12 D[$r0 + #unk_mmio_list_head]
+	ld b32 $r13 D[$r0 + #unk_mmio_list_tail]
+	ld b32 $r15 D[$r0 + #unk_mask]
+	mov $r14 0x200		// stride = 0x200
+	call #mmctx_xfer
+#endif
+
+	// wait for strands to finish
+	call #strand_wait
+
+	// if load, or a save without a load following, do some
+	// unknown stuff that's done after finishing a block of
+	// strand commands
+	bra $p1 #ctx_xfer_post
+	bra not $p2 #ctx_xfer_done
+	ctx_xfer_post:
+		mov $r1 0x4afc
+		sethi $r1 0x20000
+		mov $r2 0xd
+		iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0d
+		call #strand_wait
+
+	// mark completion in HUB's barrier
+	ctx_xfer_done:
+	call #hub_barrier_done
+	ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
index f7055af..5ae06a2 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nvc0 PGRAPH/GPC
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -20,525 +19,24 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-/* To build:
- *    m4 gpcnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o gpcnvc0.fuc.h
- */
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000000
 
-/* TODO
- * - bracket certain functions with scratch writes, useful for debugging
- * - watchdog timer around ctx operations
- */
+#define CHIPSET GF100
+#include "macros.fuc"
 
 .section #nvc0_grgpc_data
-include(`nvc0.fuc')
-gpc_id:			.b32 0
-gpc_mmio_list_head:	.b32 0
-gpc_mmio_list_tail:	.b32 0
-
-tpc_count:		.b32 0
-tpc_mask:		.b32 0
-tpc_mmio_list_head:	.b32 0
-tpc_mmio_list_tail:	.b32 0
-
-cmd_queue:		queue_init
-
-// chipset descriptions
-chipsets:
-.b8  0xc0 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc0_tpc_mmio_tail
-.b8  0xc1 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc1_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc1_tpc_mmio_tail
-.b8  0xc3 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc3_tpc_mmio_tail
-.b8  0xc4 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc3_tpc_mmio_tail
-.b8  0xc8 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc0_tpc_mmio_tail
-.b8  0xce 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc3_tpc_mmio_tail
-.b8  0xcf 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvcf_tpc_mmio_tail
-.b8  0xd9 0 0 0
-.b16 #nvd9_gpc_mmio_head
-.b16 #nvd9_gpc_mmio_tail
-.b16 #nvd9_tpc_mmio_head
-.b16 #nvd9_tpc_mmio_tail
-.b8  0xd7 0 0 0
-.b16 #nvd9_gpc_mmio_head
-.b16 #nvd9_gpc_mmio_tail
-.b16 #nvd9_tpc_mmio_head
-.b16 #nvd9_tpc_mmio_tail
-.b8  0 0 0 0
-
-// GPC mmio lists
-nvc0_gpc_mmio_head:
-mmctx_data(0x000380, 1)
-mmctx_data(0x000400, 6)
-mmctx_data(0x000450, 9)
-mmctx_data(0x000600, 1)
-mmctx_data(0x000684, 1)
-mmctx_data(0x000700, 5)
-mmctx_data(0x000800, 1)
-mmctx_data(0x000808, 3)
-mmctx_data(0x000828, 1)
-mmctx_data(0x000830, 1)
-mmctx_data(0x0008d8, 1)
-mmctx_data(0x0008e0, 1)
-mmctx_data(0x0008e8, 6)
-mmctx_data(0x00091c, 1)
-mmctx_data(0x000924, 3)
-mmctx_data(0x000b00, 1)
-mmctx_data(0x000b08, 6)
-mmctx_data(0x000bb8, 1)
-mmctx_data(0x000c08, 1)
-mmctx_data(0x000c10, 8)
-mmctx_data(0x000c80, 1)
-mmctx_data(0x000c8c, 1)
-mmctx_data(0x001000, 3)
-mmctx_data(0x001014, 1)
-nvc0_gpc_mmio_tail:
-mmctx_data(0x000c6c, 1);
-nvc1_gpc_mmio_tail:
-
-nvd9_gpc_mmio_head:
-mmctx_data(0x000380, 1)
-mmctx_data(0x000400, 2)
-mmctx_data(0x00040c, 3)
-mmctx_data(0x000450, 9)
-mmctx_data(0x000600, 1)
-mmctx_data(0x000684, 1)
-mmctx_data(0x000700, 5)
-mmctx_data(0x000800, 1)
-mmctx_data(0x000808, 3)
-mmctx_data(0x000828, 1)
-mmctx_data(0x000830, 1)
-mmctx_data(0x0008d8, 1)
-mmctx_data(0x0008e0, 1)
-mmctx_data(0x0008e8, 6)
-mmctx_data(0x00091c, 1)
-mmctx_data(0x000924, 3)
-mmctx_data(0x000b00, 1)
-mmctx_data(0x000b08, 6)
-mmctx_data(0x000bb8, 1)
-mmctx_data(0x000c08, 1)
-mmctx_data(0x000c10, 8)
-mmctx_data(0x000c6c, 1)
-mmctx_data(0x000c80, 1)
-mmctx_data(0x000c8c, 1)
-mmctx_data(0x001000, 3)
-mmctx_data(0x001014, 1)
-nvd9_gpc_mmio_tail:
-
-// TPC mmio lists
-nvc0_tpc_mmio_head:
-mmctx_data(0x000018, 1)
-mmctx_data(0x00003c, 1)
-mmctx_data(0x000048, 1)
-mmctx_data(0x000064, 1)
-mmctx_data(0x000088, 1)
-mmctx_data(0x000200, 6)
-mmctx_data(0x00021c, 2)
-mmctx_data(0x000300, 6)
-mmctx_data(0x0003d0, 1)
-mmctx_data(0x0003e0, 2)
-mmctx_data(0x000400, 3)
-mmctx_data(0x000420, 1)
-mmctx_data(0x0004b0, 1)
-mmctx_data(0x0004e8, 1)
-mmctx_data(0x0004f4, 1)
-mmctx_data(0x000520, 2)
-mmctx_data(0x000604, 4)
-mmctx_data(0x000644, 20)
-mmctx_data(0x000698, 1)
-mmctx_data(0x000750, 2)
-nvc0_tpc_mmio_tail:
-mmctx_data(0x000758, 1)
-mmctx_data(0x0002c4, 1)
-mmctx_data(0x0006e0, 1)
-nvcf_tpc_mmio_tail:
-mmctx_data(0x0004bc, 1)
-nvc3_tpc_mmio_tail:
-mmctx_data(0x000544, 1)
-nvc1_tpc_mmio_tail:
-
-nvd9_tpc_mmio_head:
-mmctx_data(0x000018, 1)
-mmctx_data(0x00003c, 1)
-mmctx_data(0x000048, 1)
-mmctx_data(0x000064, 1)
-mmctx_data(0x000088, 1)
-mmctx_data(0x000200, 6)
-mmctx_data(0x00021c, 2)
-mmctx_data(0x0002c4, 1)
-mmctx_data(0x000300, 6)
-mmctx_data(0x0003d0, 1)
-mmctx_data(0x0003e0, 2)
-mmctx_data(0x000400, 3)
-mmctx_data(0x000420, 3)
-mmctx_data(0x0004b0, 1)
-mmctx_data(0x0004e8, 1)
-mmctx_data(0x0004f4, 1)
-mmctx_data(0x000520, 2)
-mmctx_data(0x000544, 1)
-mmctx_data(0x000604, 4)
-mmctx_data(0x000644, 20)
-mmctx_data(0x000698, 1)
-mmctx_data(0x0006e0, 1)
-mmctx_data(0x000750, 3)
-nvd9_tpc_mmio_tail:
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
 
 .section #nvc0_grgpc_code
+#define INCLUDE_CODE
 bra #init
-define(`include_code')
-include(`nvc0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nvc0.fuc)
-//
-error:
-	push $r14
-	mov $r14 -0x67ec 	// 0x9814
-	sethi $r14 0x400000
-	call #nv_wr32		// HUB_CTXCTL_CC_SCRATCH[5] = error code
-	add b32 $r14 0x41c
-	mov $r15 1
-	call #nv_wr32		// HUB_CTXCTL_INTR_UP_SET
-	pop $r14
-	ret
-
-// GPC fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//   CC_SCRATCH[1]: context base
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: GPC context size
-//
-init:
-	clear b32 $r0
-	mov $sp $r0
-
-	// enable fifo access
-	mov $r1 0x1200
-	mov $r2 2
-	iowr I[$r1 + 0x000] $r2		// FIFO_ENABLE
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	mov $r1 0x400
-	iowr I[$r1 + 0x300] $r0		// INTR_DISPATCH
-
-	// enable fifo interrupt
-	mov $r2 4
-	iowr I[$r1 + 0x000] $r2		// INTR_EN_SET
-
-	// enable interrupts
-	bset $flags ie0
-
-	// figure out which GPC we are, and how many TPCs we have
-	mov $r1 0x608
-	shl b32 $r1 6
-	iord $r2 I[$r1 + 0x000]		// UNITS
-	mov $r3 1
-	and $r2 0x1f
-	shl b32 $r3 $r2
-	sub b32 $r3 1
-	st b32 D[$r0 + #tpc_count] $r2
-	st b32 D[$r0 + #tpc_mask] $r3
-	add b32 $r1 0x400
-	iord $r2 I[$r1 + 0x000]		// MYINDEX
-	st b32 D[$r0 + #gpc_id] $r2
-
-	// find context data for this chipset
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
-	mov $r1 #chipsets - 12
-	init_find_chipset:
-		add b32 $r1 12
-		ld b32 $r3 D[$r1 + 0x00]
-		cmpu b32 $r3 $r2
-		bra e #init_context
-		cmpu b32 $r3 0
-		bra ne #init_find_chipset
-		// unknown chipset
-		ret
-
-	// initialise context base, and size tracking
-	init_context:
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x100]	// CC_SCRATCH[1], initial base
-	clear b32 $r3		// track GPC context size here
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't currently ever change
-	mov $r4 0x700
-	shl b32 $r4 6
-	shr b32 $r5 $r2 8
-	iowr I[$r4 + 0x000] $r5		// MMCTX_SAVE_SWBASE
-	iowr I[$r4 + 0x100] $r5		// MMCTX_LOAD_SWBASE
-
-	// calculate GPC mmio context size, store the chipset-specific
-	// mmio list pointers somewhere we can get at them later without
-	// re-parsing the chipset list
-	clear b32 $r14
-	clear b32 $r15
-	ld b16 $r14 D[$r1 + 4]
-	ld b16 $r15 D[$r1 + 6]
-	st b16 D[$r0 + #gpc_mmio_list_head] $r14
-	st b16 D[$r0 + #gpc_mmio_list_tail] $r15
-	call #mmctx_size
-	add b32 $r2 $r15
-	add b32 $r3 $r15
-
-	// calculate per-TPC mmio context size, store the list pointers
-	ld b16 $r14 D[$r1 + 8]
-	ld b16 $r15 D[$r1 + 10]
-	st b16 D[$r0 + #tpc_mmio_list_head] $r14
-	st b16 D[$r0 + #tpc_mmio_list_tail] $r15
-	call #mmctx_size
-	ld b32 $r14 D[$r0 + #tpc_count]
-	mulu $r14 $r15
-	add b32 $r2 $r14
-	add b32 $r3 $r14
-
-	// round up base/size to 256 byte boundary (for strand SWBASE)
-	add b32 $r4 0x1300
-	shr b32 $r3 2
-	iowr I[$r4 + 0x000] $r3		// MMCTX_LOAD_COUNT, wtf for?!?
-	shr b32 $r2 8
-	shr b32 $r3 6
-	add b32 $r2 1
-	add b32 $r3 1
-	shl b32 $r2 8
-	shl b32 $r3 8
-
-	// calculate size of strand context data
-	mov b32 $r15 $r2
-	call #strand_ctx_init
-	add b32 $r3 $r15
-
-	// save context size, and tell HUB we're done
-	mov $r1 0x800
-	shl b32 $r1 6
-	iowr I[$r1 + 0x100] $r3		// CC_SCRATCH[1]  = context size
-	add b32 $r1 0x800
-	clear b32 $r2
-	bset $r2 31
-	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call #queue_get
-	bra $p1 #main
-
-	// 0x0000-0x0003 are all context transfers
-	cmpu b32 $r14 0x04
-	bra nc #main_not_ctx_xfer
-		// fetch $flags and mask off $p1/$p2
-		mov $r1 $flags
-		mov $r2 0x0006
-		not b32 $r2
-		and $r1 $r2
-		// set $p1/$p2 according to transfer type
-		shl b32 $r14 1
-		or $r1 $r14
-		mov $flags $r1
-		// transfer context data
-		call #ctx_xfer
-		bra #main
-
-	main_not_ctx_xfer:
-	shl b32 $r15 $r14 16
-	or $r15 E_BAD_COMMAND
-	call #error
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-
-	// incoming fifo command?
-	iord $r10 I[$r0 + 0x200]	// INTR
-	and $r11 $r10 0x00000004
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r11 0x1900
-		mov $r13 #cmd_queue
-		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
-		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
-		call #queue_put
-		add b32 $r11 0x400
-		mov $r14 1
-		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
-
-	// ack, and wake up main()
-	ih_no_fifo:
-	iowr I[$r0 + 0x100] $r10	// INTR_ACK
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Set this GPC's bit in HUB_BAR, used to signal completion of various
-// activities to the HUB fuc
-//
-hub_barrier_done:
-	mov $r15 1
-	ld b32 $r14 D[$r0 + #gpc_id]
-	shl b32 $r15 $r14
-	mov $r14 -0x6be8 	// 0x409418 - HUB_BAR_SET
-	sethi $r14 0x400000
-	call #nv_wr32
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 0x614
-	shl b32 $r14 6
-	mov $r15 0x020
-	iowr I[$r14] $r15	// GPC_RED_SWITCH = POWER
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	mov $r15 0xa20
-	iowr I[$r14] $r15	// GPC_RED_SWITCH = UNK11, ENABLE, POWER
-	ret
-
-// Transfer GPC context data between GPU and storage area
-//
-// In: $r15 context base address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// set context base address
-	mov $r1 0xa04
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r15// MEM_BASE
-	bra not $p1 #ctx_xfer_not_load
-		call #ctx_redswitch
-	ctx_xfer_not_load:
-
-	// strands
-	mov $r1 0x4afc
-	sethi $r1 0x20000
-	mov $r2 0xc
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
-	call #strand_wait
-	mov $r2 0x47fc
-	sethi $r2 0x20000
-	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
-	xbit $r2 $flags $p1
-	add b32 $r2 3
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 2		// first
-	mov $r11 0x0000
-	sethi $r11 0x500000
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn
-	ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
-	mov $r14 0		// not multi
-	call #mmctx_xfer
-
-	// per-TPC mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 4		// last
-	mov $r11 0x4000
-	sethi $r11 0x500000	// base = NV_PGRAPH_GPC0_TPC0
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_TPC0
-	ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
-	ld b32 $r15 D[$r0 + #tpc_mask]
-	mov $r14 0x800		// stride = 0x800
-	call #mmctx_xfer
-
-	// wait for strands to finish
-	call #strand_wait
-
-	// if load, or a save without a load following, do some
-	// unknown stuff that's done after finishing a block of
-	// strand commands
-	bra $p1 #ctx_xfer_post
-	bra not $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r1 0x4afc
-		sethi $r1 0x20000
-		mov $r2 0xd
-		iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0d
-		call #strand_wait
-
-	// mark completion in HUB's barrier
-	ctx_xfer_done:
-	call #hub_barrier_done
-	ret
-
+#include "com.fuc"
+#include "gpc.fuc"
 .align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
index 96050dd..f2b0dea 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
@@ -1,17 +1,19 @@
 uint32_t nvc0_grgpc_data[] = {
-/* 0x0000: gpc_id */
+/* 0x0000: gpc_mmio_list_head */
+	0x00000064,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x00000064,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x00000064,
+/* 0x000c: unk_mmio_list_tail */
+	0x00000064,
+/* 0x0010: gpc_id */
 	0x00000000,
-/* 0x0004: gpc_mmio_list_head */
+/* 0x0014: tpc_count */
 	0x00000000,
-/* 0x0008: gpc_mmio_list_tail */
-	0x00000000,
-/* 0x000c: tpc_count */
-	0x00000000,
-/* 0x0010: tpc_mask */
-	0x00000000,
-/* 0x0014: tpc_mmio_list_head */
-	0x00000000,
-/* 0x0018: tpc_mmio_list_tail */
+/* 0x0018: tpc_mask */
 	0x00000000,
 /* 0x001c: cmd_queue */
 	0x00000000,
@@ -32,153 +34,17 @@
 	0x00000000,
 	0x00000000,
 	0x00000000,
-/* 0x0064: chipsets */
-	0x000000c0,
-	0x012800c8,
-	0x01e40194,
-	0x000000c1,
-	0x012c00c8,
-	0x01f80194,
-	0x000000c3,
-	0x012800c8,
-	0x01f40194,
-	0x000000c4,
-	0x012800c8,
-	0x01f40194,
-	0x000000c8,
-	0x012800c8,
-	0x01e40194,
-	0x000000ce,
-	0x012800c8,
-	0x01f40194,
-	0x000000cf,
-	0x012800c8,
-	0x01f00194,
-	0x000000d9,
-	0x0194012c,
-	0x025401f8,
-	0x00000000,
-/* 0x00c8: nvc0_gpc_mmio_head */
-	0x00000380,
-	0x14000400,
-	0x20000450,
-	0x00000600,
-	0x00000684,
-	0x10000700,
-	0x00000800,
-	0x08000808,
-	0x00000828,
-	0x00000830,
-	0x000008d8,
-	0x000008e0,
-	0x140008e8,
-	0x0000091c,
-	0x08000924,
-	0x00000b00,
-	0x14000b08,
-	0x00000bb8,
-	0x00000c08,
-	0x1c000c10,
-	0x00000c80,
-	0x00000c8c,
-	0x08001000,
-	0x00001014,
-/* 0x0128: nvc0_gpc_mmio_tail */
-	0x00000c6c,
-/* 0x012c: nvc1_gpc_mmio_tail */
-/* 0x012c: nvd9_gpc_mmio_head */
-	0x00000380,
-	0x04000400,
-	0x0800040c,
-	0x20000450,
-	0x00000600,
-	0x00000684,
-	0x10000700,
-	0x00000800,
-	0x08000808,
-	0x00000828,
-	0x00000830,
-	0x000008d8,
-	0x000008e0,
-	0x140008e8,
-	0x0000091c,
-	0x08000924,
-	0x00000b00,
-	0x14000b08,
-	0x00000bb8,
-	0x00000c08,
-	0x1c000c10,
-	0x00000c6c,
-	0x00000c80,
-	0x00000c8c,
-	0x08001000,
-	0x00001014,
-/* 0x0194: nvd9_gpc_mmio_tail */
-/* 0x0194: nvc0_tpc_mmio_head */
-	0x00000018,
-	0x0000003c,
-	0x00000048,
-	0x00000064,
-	0x00000088,
-	0x14000200,
-	0x0400021c,
-	0x14000300,
-	0x000003d0,
-	0x040003e0,
-	0x08000400,
-	0x00000420,
-	0x000004b0,
-	0x000004e8,
-	0x000004f4,
-	0x04000520,
-	0x0c000604,
-	0x4c000644,
-	0x00000698,
-	0x04000750,
-/* 0x01e4: nvc0_tpc_mmio_tail */
-	0x00000758,
-	0x000002c4,
-	0x000006e0,
-/* 0x01f0: nvcf_tpc_mmio_tail */
-	0x000004bc,
-/* 0x01f4: nvc3_tpc_mmio_tail */
-	0x00000544,
-/* 0x01f8: nvc1_tpc_mmio_tail */
-/* 0x01f8: nvd9_tpc_mmio_head */
-	0x00000018,
-	0x0000003c,
-	0x00000048,
-	0x00000064,
-	0x00000088,
-	0x14000200,
-	0x0400021c,
-	0x000002c4,
-	0x14000300,
-	0x000003d0,
-	0x040003e0,
-	0x08000400,
-	0x08000420,
-	0x000004b0,
-	0x000004e8,
-	0x000004f4,
-	0x04000520,
-	0x00000544,
-	0x0c000604,
-	0x4c000644,
-	0x00000698,
-	0x000006e0,
-	0x08000750,
 };
 
 uint32_t nvc0_grgpc_code[] = {
-	0x03060ef5,
+	0x03180ef5,
 /* 0x0004: queue_put */
 	0x9800d898,
 	0x86f001d9,
 	0x0489b808,
 	0xf00c1bf4,
 	0x21f502f7,
-	0x00f802ec,
+	0x00f802fe,
 /* 0x001c: queue_put_next */
 	0xb60798c4,
 	0x8dbb0384,
@@ -210,7 +76,7 @@
 	0xc800bccf,
 	0x1bf41fcc,
 	0x06a7f0fa,
-	0x010321f5,
+	0x010921f5,
 	0xf840bfcf,
 /* 0x008d: nv_wr32 */
 	0x28b7f100,
@@ -232,63 +98,66 @@
 	0x0684b604,
 	0xf80080d0,
 /* 0x00c9: wait_donez */
-	0x3c87f100,
-	0x0684b608,
-	0x99f094bd,
-	0x0089d000,
-	0x081887f1,
-	0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
-	0x87f1008a,
-	0x84b60400,
-	0x0088cf06,
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x07f104bd,
+	0x03f00600,
+	0x000ad002,
+/* 0x00e6: wait_donez_ne */
+	0x87f104bd,
+	0x83f00000,
+	0x0088cf01,
 	0xf4888aff,
-	0x87f1f31b,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00099,
-/* 0x0103: wait_doneo */
-	0xf100f800,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00099f0,
-	0x87f10089,
+	0x94bdf31b,
+	0xf10099f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0109: wait_doneo */
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x87f104bd,
 	0x84b60818,
 	0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x0124: wait_doneo_e */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
 	0xf30bf488,
-	0x085c87f1,
-	0xbd0684b6,
-	0x0099f094,
-	0xf80089d0,
-/* 0x013d: mmctx_size */
-/* 0x013f: nv_mmctx_size_loop */
-	0x9894bd00,
-	0x85b600e8,
-	0x0180b61a,
-	0xbb0284b6,
-	0xe0b60098,
-	0x04efb804,
-	0xb9eb1bf4,
-	0x00f8029f,
-/* 0x015c: mmctx_xfer */
-	0x083c87f1,
-	0xbd0684b6,
-	0x0199f094,
-	0xf10089d0,
+	0x99f094bd,
+	0x0007f100,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x0147: mmctx_size */
+	0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+	0x00e89894,
+	0xb61a85b6,
+	0x84b60180,
+	0x0098bb02,
+	0xb804e0b6,
+	0x1bf404ef,
+	0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+	0x94bd00f8,
+	0xf10199f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
 	0xb6071087,
 	0x94bd0684,
 	0xf405bbfd,
 	0x8bd0090b,
 	0x0099f000,
-/* 0x0180: mmctx_base_disabled */
+/* 0x018c: mmctx_base_disabled */
 	0xf405eefd,
 	0x8ed00c0b,
 	0xc08fd080,
-/* 0x018f: mmctx_multi_disabled */
+/* 0x019b: mmctx_multi_disabled */
 	0xb70199f0,
 	0xc8010080,
 	0xb4b600ab,
@@ -296,8 +165,8 @@
 	0xb601aec8,
 	0xbefd11e4,
 	0x008bd005,
-/* 0x01a8: mmctx_exec_loop */
-/* 0x01a8: mmctx_wait_free */
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
 	0xf0008ecf,
 	0x0bf41fe4,
 	0x00ce98fa,
@@ -306,76 +175,77 @@
 	0x04cdb804,
 	0xc8e81bf4,
 	0x1bf402ab,
-/* 0x01c9: mmctx_fini_wait */
+/* 0x01d5: mmctx_fini_wait */
 	0x008bcf18,
 	0xb01fb4f0,
 	0x1bf410b4,
 	0x02a7f0f7,
 	0xf4c921f4,
-/* 0x01de: mmctx_stop */
+/* 0x01ea: mmctx_stop */
 	0xabc81b0e,
 	0x10b4b600,
 	0xf00cb9f0,
 	0x8bd012b9,
-/* 0x01ed: mmctx_stop_wait */
+/* 0x01f9: mmctx_stop_wait */
 	0x008bcf00,
 	0xf412bbc8,
-/* 0x01f6: mmctx_done */
-	0x87f1fa1b,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00199,
-/* 0x0207: strand_wait */
-	0xf900f800,
-	0x02a7f0a0,
-	0xfcc921f4,
-/* 0x0213: strand_pre */
-	0xf100f8a0,
-	0xf04afc87,
-	0x97f00283,
-	0x0089d00c,
-	0x020721f5,
-/* 0x0226: strand_post */
-	0x87f100f8,
-	0x83f04afc,
-	0x0d97f002,
-	0xf50089d0,
-	0xf8020721,
-/* 0x0239: strand_set */
-	0xfca7f100,
-	0x02a3f04f,
-	0x0500aba2,
-	0xd00fc7f0,
-	0xc7f000ac,
-	0x00bcd00b,
-	0x020721f5,
-	0xf000aed0,
-	0xbcd00ac7,
-	0x0721f500,
-/* 0x0263: strand_ctx_init */
-	0xf100f802,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00399f0,
+/* 0x0202: mmctx_done */
+	0x94bdfa1b,
+	0xf10199f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0215: strand_wait */
+	0xf0a0f900,
+	0x21f402a7,
+	0xf8a0fcc9,
+/* 0x0221: strand_pre */
+	0xfc87f100,
+	0x0283f04a,
+	0xd00c97f0,
 	0x21f50089,
-	0xe7f00213,
-	0x3921f503,
+	0x00f80215,
+/* 0x0234: strand_post */
+	0x4afc87f1,
+	0xf00283f0,
+	0x89d00d97,
+	0x1521f500,
+/* 0x0247: strand_set */
+	0xf100f802,
+	0xf04ffca7,
+	0xaba202a3,
+	0xc7f00500,
+	0x00acd00f,
+	0xd00bc7f0,
+	0x21f500bc,
+	0xaed00215,
+	0x0ac7f000,
+	0xf500bcd0,
+	0xf8021521,
+/* 0x0271: strand_ctx_init */
+	0xf094bd00,
+	0x07f10399,
+	0x03f00f00,
+	0x0009d002,
+	0x21f504bd,
+	0xe7f00221,
+	0x4721f503,
 	0xfca7f102,
 	0x02a3f046,
 	0x0400aba0,
 	0xf040a0d0,
 	0xbcd001c7,
-	0x0721f500,
+	0x1521f500,
 	0x010c9202,
 	0xf000acd0,
 	0xbcd002c7,
-	0x0721f500,
-	0x2621f502,
+	0x1521f500,
+	0x3421f502,
 	0x8087f102,
 	0x0684b608,
 	0xb70089cf,
 	0x95220080,
-/* 0x02ba: ctx_init_strand_loop */
+/* 0x02ca: ctx_init_strand_loop */
 	0x8ed008fe,
 	0x408ed000,
 	0xb6808acf,
@@ -384,86 +254,74 @@
 	0xb60480b6,
 	0x1bf40192,
 	0x08e4b6e8,
-	0xf1f2efbc,
-	0xb6085c87,
-	0x94bd0684,
-	0xd00399f0,
-	0x00f80089,
-/* 0x02ec: error */
-	0xe7f1e0f9,
-	0xe3f09814,
-	0x8d21f440,
-	0x041ce0b7,
-	0xf401f7f0,
-	0xe0fc8d21,
-/* 0x0306: init */
-	0x04bd00f8,
-	0xf10004fe,
-	0xf0120017,
-	0x12d00227,
-	0x3e17f100,
-	0x0010fe04,
-	0x040017f1,
-	0xf0c010d0,
-	0x12d00427,
-	0x1031f400,
-	0x060817f1,
-	0xcf0614b6,
-	0x37f00012,
-	0x1f24f001,
-	0xb60432bb,
-	0x02800132,
-	0x04038003,
-	0x040010b7,
-	0x800012cf,
-	0x27f10002,
-	0x24b60800,
-	0x0022cf06,
-/* 0x035f: init_find_chipset */
-	0xb65817f0,
-	0x13980c10,
-	0x0432b800,
-	0xb00b0bf4,
-	0x1bf40034,
-/* 0x0373: init_context */
-	0xf100f8f1,
-	0xb6080027,
-	0x22cf0624,
-	0xf134bd40,
-	0xb6070047,
-	0x25950644,
-	0x0045d008,
-	0xbd4045d0,
-	0x58f4bde4,
-	0x1f58021e,
-	0x020e4003,
-	0xf5040f40,
-	0xbb013d21,
-	0x3fbb002f,
-	0x041e5800,
-	0x40051f58,
-	0x0f400a0e,
-	0x3d21f50c,
-	0x030e9801,
-	0xbb00effd,
-	0x3ebb002e,
-	0x0040b700,
-	0x0235b613,
-	0xb60043d0,
-	0x35b60825,
-	0x0120b606,
-	0xb60130b6,
-	0x34b60824,
-	0x022fb908,
-	0x026321f5,
-	0xf1003fbb,
-	0xb6080017,
-	0x13d00614,
-	0x0010b740,
-	0xf024bd08,
-	0x12d01f29,
-/* 0x0401: main */
-	0x0031f400,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x02fe: error */
+	0xe0f900f8,
+	0x9814e7f1,
+	0xf440e3f0,
+	0xe0b78d21,
+	0xf7f0041c,
+	0x8d21f401,
+	0x00f8e0fc,
+/* 0x0318: init */
+	0x04fe04bd,
+	0x0017f100,
+	0x0227f012,
+	0xf10012d0,
+	0xfe042617,
+	0x17f10010,
+	0x10d00400,
+	0x0427f0c0,
+	0xf40012d0,
+	0x17f11031,
+	0x14b60608,
+	0x0012cf06,
+	0xf00137f0,
+	0x32bb1f24,
+	0x0132b604,
+	0x80050280,
+	0x10b70603,
+	0x12cf0400,
+	0x04028000,
+	0x010027f1,
+	0xcf0223f0,
+	0x34bd0022,
+	0x070047f1,
+	0x950644b6,
+	0x45d00825,
+	0x4045d000,
+	0x98000e98,
+	0x21f5010f,
+	0x2fbb0147,
+	0x003fbb00,
+	0x98010e98,
+	0x21f5020f,
+	0x0e980147,
+	0x00effd05,
+	0xbb002ebb,
+	0x40b7003e,
+	0x35b61300,
+	0x0043d002,
+	0xb60825b6,
+	0x20b60635,
+	0x0130b601,
+	0xb60824b6,
+	0x2fb90834,
+	0x7121f502,
+	0x003fbb02,
+	0x010007f1,
+	0xd00203f0,
+	0x04bd0003,
+	0x29f024bd,
+	0x0007f11f,
+	0x0203f008,
+	0xbd0002d0,
+/* 0x03e9: main */
+	0x0031f404,
 	0xf00028f4,
 	0x21f41cd7,
 	0xf401f439,
@@ -474,94 +332,100 @@
 	0x01e4b604,
 	0xfe051efd,
 	0x21f50018,
-	0x0ef404c3,
-/* 0x0431: main_not_ctx_xfer */
+	0x0ef404ad,
+/* 0x0419: main_not_ctx_xfer */
 	0x10ef94d3,
 	0xf501f5f0,
-	0xf402ec21,
-/* 0x043e: ih */
+	0xf402fe21,
+/* 0x0426: ih */
 	0x80f9c60e,
 	0xf90188fe,
 	0xf990f980,
 	0xf9b0f9a0,
 	0xf9e0f9d0,
-	0x800acff0,
-	0xf404abc4,
-	0xb7f11d0b,
-	0xd7f01900,
-	0x40becf1c,
-	0xf400bfcf,
-	0xb0b70421,
-	0xe7f00400,
-	0x00bed001,
-/* 0x0474: ih_no_fifo */
-	0xfc400ad0,
-	0xfce0fcf0,
-	0xfcb0fcd0,
-	0xfc90fca0,
-	0x0088fe80,
-	0x32f480fc,
-/* 0x048f: hub_barrier_done */
-	0xf001f800,
-	0x0e9801f7,
-	0x04febb00,
-	0x9418e7f1,
-	0xf440e3f0,
-	0x00f88d21,
-/* 0x04a4: ctx_redswitch */
-	0x0614e7f1,
-	0xf006e4b6,
-	0xefd020f7,
-	0x08f7f000,
-/* 0x04b4: ctx_redswitch_delay */
-	0xf401f2b6,
-	0xf7f1fd1b,
-	0xefd00a20,
-/* 0x04c3: ctx_xfer */
-	0xf100f800,
-	0xb60a0417,
-	0x1fd00614,
-	0x0711f400,
-	0x04a421f5,
-/* 0x04d4: ctx_xfer_not_load */
-	0x4afc17f1,
-	0xf00213f0,
-	0x12d00c27,
-	0x0721f500,
-	0xfc27f102,
-	0x0223f047,
-	0xf00020d0,
-	0x20b6012c,
-	0x0012d003,
+	0xcf04bdf0,
+	0xabc4800a,
+	0x1d0bf404,
+	0x1900b7f1,
+	0xcf1cd7f0,
+	0xbfcf40be,
+	0x0421f400,
+	0x0400b0b7,
+	0xd001e7f0,
+/* 0x045e: ih_no_fifo */
+	0x0ad000be,
+	0xfcf0fc40,
+	0xfcd0fce0,
+	0xfca0fcb0,
+	0xfe80fc90,
+	0x80fc0088,
+	0xf80032f4,
+/* 0x0479: hub_barrier_done */
+	0x01f7f001,
+	0xbb040e98,
+	0xe7f104fe,
+	0xe3f09418,
+	0x8d21f440,
+/* 0x048e: ctx_redswitch */
+	0xe7f100f8,
+	0xe4b60614,
+	0x20f7f006,
+	0xf000efd0,
+/* 0x049e: ctx_redswitch_delay */
+	0xf2b608f7,
+	0xfd1bf401,
+	0x0a20f7f1,
+	0xf800efd0,
+/* 0x04ad: ctx_xfer */
+	0x0417f100,
+	0x0614b60a,
+	0xf4001fd0,
+	0x21f50711,
+/* 0x04be: ctx_xfer_not_load */
+	0x17f1048e,
+	0x13f04afc,
+	0x0c27f002,
+	0xf50012d0,
+	0xf1021521,
+	0xf047fc27,
+	0x20d00223,
+	0x012cf000,
+	0xd00320b6,
+	0xacf00012,
+	0x02a5f001,
+	0xf000b7f0,
+	0x0c9850b3,
+	0x0fc4b604,
+	0x9800bcbb,
+	0x0d98000c,
+	0x00e7f001,
+	0x016621f5,
 	0xf001acf0,
-	0xb7f002a5,
-	0x50b3f000,
-	0xb6000c98,
-	0xbcbb0fc4,
-	0x010c9800,
-	0xf0020d98,
-	0x21f500e7,
-	0xacf0015c,
-	0x04a5f001,
-	0x4000b7f1,
-	0x9850b3f0,
-	0xc4b6000c,
-	0x00bcbb0f,
-	0x98050c98,
-	0x0f98060d,
-	0x00e7f104,
-	0x5c21f508,
-	0x0721f501,
-	0x0601f402,
-/* 0x054b: ctx_xfer_post */
-	0xf11412f4,
-	0xf04afc17,
-	0x27f00213,
-	0x0012d00d,
-	0x020721f5,
-/* 0x055c: ctx_xfer_done */
-	0x048f21f5,
-	0x000000f8,
+	0xb7f104a5,
+	0xb3f04000,
+	0x040c9850,
+	0xbb0fc4b6,
+	0x0c9800bc,
+	0x020d9801,
+	0xf1060f98,
+	0xf50800e7,
+	0xf5016621,
+	0xf4021521,
+	0x12f40601,
+/* 0x0535: ctx_xfer_post */
+	0xfc17f114,
+	0x0213f04a,
+	0xd00d27f0,
+	0x21f50012,
+/* 0x0546: ctx_xfer_done */
+	0x21f50215,
+	0x00f80479,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
 	0x00000000,
 	0x00000000,
 	0x00000000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc
new file mode 100644
index 0000000..c2f754e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
+
+#define CHIPSET GF117
+#include "macros.fuc"
+
+.section #nvd7_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #nvd7_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
new file mode 100644
index 0000000..dd346c2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
@@ -0,0 +1,475 @@
+uint32_t nvd7_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+	0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+	0x0000006c,
+/* 0x0010: gpc_id */
+	0x00000000,
+/* 0x0014: tpc_count */
+	0x00000000,
+/* 0x0018: tpc_mask */
+	0x00000000,
+/* 0x001c: unk_count */
+	0x00000000,
+/* 0x0020: unk_mask */
+	0x00000000,
+/* 0x0024: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t nvd7_grgpc_code[] = {
+	0x03180ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f802fe,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0x0728b7f1,
+	0xb906b4b6,
+	0xc9f002ec,
+	0x00bcd01f,
+/* 0x0078: nv_rd32_wait */
+	0xc800bccf,
+	0x1bf41fcc,
+	0x06a7f0fa,
+	0x010921f5,
+	0xf840bfcf,
+/* 0x008d: nv_wr32 */
+	0x28b7f100,
+	0x06b4b607,
+	0xb980bfd0,
+	0xc9f002ec,
+	0x1ec9f01f,
+/* 0x00a3: nv_wr32_wait */
+	0xcf00bcd0,
+	0xccc800bc,
+	0xfa1bf41f,
+/* 0x00ae: watchdog_reset */
+	0x87f100f8,
+	0x84b60430,
+	0x1ff9f006,
+	0xf8008fd0,
+/* 0x00bd: watchdog_clear */
+	0x3087f100,
+	0x0684b604,
+	0xf80080d0,
+/* 0x00c9: wait_donez */
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x07f104bd,
+	0x03f00600,
+	0x000ad002,
+/* 0x00e6: wait_donez_ne */
+	0x87f104bd,
+	0x83f00000,
+	0x0088cf01,
+	0xf4888aff,
+	0x94bdf31b,
+	0xf10099f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0109: wait_doneo */
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x87f104bd,
+	0x84b60818,
+	0x008ad006,
+/* 0x0124: wait_doneo_e */
+	0x040087f1,
+	0xcf0684b6,
+	0x8aff0088,
+	0xf30bf488,
+	0x99f094bd,
+	0x0007f100,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x0147: mmctx_size */
+	0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+	0x00e89894,
+	0xb61a85b6,
+	0x84b60180,
+	0x0098bb02,
+	0xb804e0b6,
+	0x1bf404ef,
+	0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+	0x94bd00f8,
+	0xf10199f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
+	0xb6071087,
+	0x94bd0684,
+	0xf405bbfd,
+	0x8bd0090b,
+	0x0099f000,
+/* 0x018c: mmctx_base_disabled */
+	0xf405eefd,
+	0x8ed00c0b,
+	0xc08fd080,
+/* 0x019b: mmctx_multi_disabled */
+	0xb70199f0,
+	0xc8010080,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xb601aec8,
+	0xbefd11e4,
+	0x008bd005,
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
+	0xf0008ecf,
+	0x0bf41fe4,
+	0x00ce98fa,
+	0xd005e9fd,
+	0xc0b6c08e,
+	0x04cdb804,
+	0xc8e81bf4,
+	0x1bf402ab,
+/* 0x01d5: mmctx_fini_wait */
+	0x008bcf18,
+	0xb01fb4f0,
+	0x1bf410b4,
+	0x02a7f0f7,
+	0xf4c921f4,
+/* 0x01ea: mmctx_stop */
+	0xabc81b0e,
+	0x10b4b600,
+	0xf00cb9f0,
+	0x8bd012b9,
+/* 0x01f9: mmctx_stop_wait */
+	0x008bcf00,
+	0xf412bbc8,
+/* 0x0202: mmctx_done */
+	0x94bdfa1b,
+	0xf10199f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0215: strand_wait */
+	0xf0a0f900,
+	0x21f402a7,
+	0xf8a0fcc9,
+/* 0x0221: strand_pre */
+	0xfc87f100,
+	0x0283f04a,
+	0xd00c97f0,
+	0x21f50089,
+	0x00f80215,
+/* 0x0234: strand_post */
+	0x4afc87f1,
+	0xf00283f0,
+	0x89d00d97,
+	0x1521f500,
+/* 0x0247: strand_set */
+	0xf100f802,
+	0xf04ffca7,
+	0xaba202a3,
+	0xc7f00500,
+	0x00acd00f,
+	0xd00bc7f0,
+	0x21f500bc,
+	0xaed00215,
+	0x0ac7f000,
+	0xf500bcd0,
+	0xf8021521,
+/* 0x0271: strand_ctx_init */
+	0xf094bd00,
+	0x07f10399,
+	0x03f00f00,
+	0x0009d002,
+	0x21f504bd,
+	0xe7f00221,
+	0x4721f503,
+	0xfca7f102,
+	0x02a3f046,
+	0x0400aba0,
+	0xf040a0d0,
+	0xbcd001c7,
+	0x1521f500,
+	0x010c9202,
+	0xf000acd0,
+	0xbcd002c7,
+	0x1521f500,
+	0x3421f502,
+	0x8087f102,
+	0x0684b608,
+	0xb70089cf,
+	0x95220080,
+/* 0x02ca: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x02fe: error */
+	0xe0f900f8,
+	0x9814e7f1,
+	0xf440e3f0,
+	0xe0b78d21,
+	0xf7f0041c,
+	0x8d21f401,
+	0x00f8e0fc,
+/* 0x0318: init */
+	0x04fe04bd,
+	0x0017f100,
+	0x0227f012,
+	0xf10012d0,
+	0xfe047017,
+	0x17f10010,
+	0x10d00400,
+	0x0427f0c0,
+	0xf40012d0,
+	0x17f11031,
+	0x14b60608,
+	0x0012cf06,
+	0xf00137f0,
+	0x32bb1f24,
+	0x0132b604,
+	0x80050280,
+	0x10b70603,
+	0x12cf0400,
+	0x04028000,
+	0x0c30e7f1,
+	0xbd50e3f0,
+	0xbd34bd24,
+/* 0x0371: init_unk_loop */
+	0x6821f444,
+	0xf400f6b0,
+	0xf7f00f0b,
+	0x04f2bb01,
+	0xb6054ffd,
+/* 0x0386: init_unk_next */
+	0x20b60130,
+	0x04e0b601,
+	0xf40126b0,
+/* 0x0392: init_unk_done */
+	0x0380e21b,
+	0x08048007,
+	0x010027f1,
+	0xcf0223f0,
+	0x34bd0022,
+	0x070047f1,
+	0x950644b6,
+	0x45d00825,
+	0x4045d000,
+	0x98000e98,
+	0x21f5010f,
+	0x2fbb0147,
+	0x003fbb00,
+	0x98010e98,
+	0x21f5020f,
+	0x0e980147,
+	0x00effd05,
+	0xbb002ebb,
+	0x0e98003e,
+	0x030f9802,
+	0x014721f5,
+	0xfd070e98,
+	0x2ebb00ef,
+	0x003ebb00,
+	0x130040b7,
+	0xd00235b6,
+	0x25b60043,
+	0x0635b608,
+	0xb60120b6,
+	0x24b60130,
+	0x0834b608,
+	0xf5022fb9,
+	0xbb027121,
+	0x07f1003f,
+	0x03f00100,
+	0x0003d002,
+	0x24bd04bd,
+	0xf11f29f0,
+	0xf0080007,
+	0x02d00203,
+/* 0x0433: main */
+	0xf404bd00,
+	0x28f40031,
+	0x24d7f000,
+	0xf43921f4,
+	0xe4b0f401,
+	0x1e18f404,
+	0xf00181fe,
+	0x20bd0627,
+	0xb60412fd,
+	0x1efd01e4,
+	0x0018fe05,
+	0x04f721f5,
+/* 0x0463: main_not_ctx_xfer */
+	0x94d30ef4,
+	0xf5f010ef,
+	0xfe21f501,
+	0xc60ef402,
+/* 0x0470: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x800acf04,
+	0xf404abc4,
+	0xb7f11d0b,
+	0xd7f01900,
+	0x40becf24,
+	0xf400bfcf,
+	0xb0b70421,
+	0xe7f00400,
+	0x00bed001,
+/* 0x04a8: ih_no_fifo */
+	0xfc400ad0,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x04c3: hub_barrier_done */
+	0xf001f800,
+	0x0e9801f7,
+	0x04febb04,
+	0x9418e7f1,
+	0xf440e3f0,
+	0x00f88d21,
+/* 0x04d8: ctx_redswitch */
+	0x0614e7f1,
+	0xf006e4b6,
+	0xefd020f7,
+	0x08f7f000,
+/* 0x04e8: ctx_redswitch_delay */
+	0xf401f2b6,
+	0xf7f1fd1b,
+	0xefd00a20,
+/* 0x04f7: ctx_xfer */
+	0xf100f800,
+	0xb60a0417,
+	0x1fd00614,
+	0x0711f400,
+	0x04d821f5,
+/* 0x0508: ctx_xfer_not_load */
+	0x4afc17f1,
+	0xf00213f0,
+	0x12d00c27,
+	0x1521f500,
+	0xfc27f102,
+	0x0223f047,
+	0xf00020d0,
+	0x20b6012c,
+	0x0012d003,
+	0xf001acf0,
+	0xb7f002a5,
+	0x50b3f000,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x000c9800,
+	0xf0010d98,
+	0x21f500e7,
+	0xacf00166,
+	0x00b7f101,
+	0x50b3f040,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x010c9800,
+	0x98020d98,
+	0xe7f1060f,
+	0x21f50800,
+	0xacf00166,
+	0x04a5f001,
+	0x3000b7f1,
+	0x9850b3f0,
+	0xc4b6040c,
+	0x00bcbb0f,
+	0x98020c98,
+	0x0f98030d,
+	0x00e7f108,
+	0x6621f502,
+	0x1521f501,
+	0x0601f402,
+/* 0x05a3: ctx_xfer_post */
+	0xf11412f4,
+	0xf04afc17,
+	0x27f00213,
+	0x0012d00d,
+	0x021521f5,
+/* 0x05b4: ctx_xfer_done */
+	0x04c321f5,
+	0x000000f8,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
index 62ab231..6b906cd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nve0 PGRAPH/GPC
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -20,437 +19,24 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-/* To build:
- *    m4 nve0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grgpc.fuc.h
- */
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
 
-/* TODO
- * - bracket certain functions with scratch writes, useful for debugging
- * - watchdog timer around ctx operations
- */
+#define CHIPSET GK100
+#include "macros.fuc"
 
 .section #nve0_grgpc_data
-include(`nve0.fuc')
-gpc_id:			.b32 0
-gpc_mmio_list_head:	.b32 0
-gpc_mmio_list_tail:	.b32 0
-
-tpc_count:		.b32 0
-tpc_mask:		.b32 0
-tpc_mmio_list_head:	.b32 0
-tpc_mmio_list_tail:	.b32 0
-
-cmd_queue:		queue_init
-
-// chipset descriptions
-chipsets:
-.b8  0xe4 0 0 0
-.b16 #nve4_gpc_mmio_head
-.b16 #nve4_gpc_mmio_tail
-.b16 #nve4_tpc_mmio_head
-.b16 #nve4_tpc_mmio_tail
-.b8  0xe7 0 0 0
-.b16 #nve4_gpc_mmio_head
-.b16 #nve4_gpc_mmio_tail
-.b16 #nve4_tpc_mmio_head
-.b16 #nve4_tpc_mmio_tail
-.b8  0xe6 0 0 0
-.b16 #nve4_gpc_mmio_head
-.b16 #nve4_gpc_mmio_tail
-.b16 #nve4_tpc_mmio_head
-.b16 #nve4_tpc_mmio_tail
-.b8  0 0 0 0
-
-// GPC mmio lists
-nve4_gpc_mmio_head:
-mmctx_data(0x000380, 1)
-mmctx_data(0x000400, 2)
-mmctx_data(0x00040c, 3)
-mmctx_data(0x000450, 9)
-mmctx_data(0x000600, 1)
-mmctx_data(0x000684, 1)
-mmctx_data(0x000700, 5)
-mmctx_data(0x000800, 1)
-mmctx_data(0x000808, 3)
-mmctx_data(0x000828, 1)
-mmctx_data(0x000830, 1)
-mmctx_data(0x0008d8, 1)
-mmctx_data(0x0008e0, 1)
-mmctx_data(0x0008e8, 6)
-mmctx_data(0x00091c, 1)
-mmctx_data(0x000924, 3)
-mmctx_data(0x000b00, 1)
-mmctx_data(0x000b08, 6)
-mmctx_data(0x000bb8, 1)
-mmctx_data(0x000c08, 1)
-mmctx_data(0x000c10, 8)
-mmctx_data(0x000c40, 1)
-mmctx_data(0x000c6c, 1)
-mmctx_data(0x000c80, 1)
-mmctx_data(0x000c8c, 1)
-mmctx_data(0x001000, 3)
-mmctx_data(0x001014, 1)
-mmctx_data(0x003024, 1)
-mmctx_data(0x0030c0, 2)
-mmctx_data(0x0030e4, 1)
-mmctx_data(0x003100, 6)
-mmctx_data(0x0031d0, 1)
-mmctx_data(0x0031e0, 2)
-nve4_gpc_mmio_tail:
-
-// TPC mmio lists
-nve4_tpc_mmio_head:
-mmctx_data(0x000048, 1)
-mmctx_data(0x000064, 1)
-mmctx_data(0x000088, 1)
-mmctx_data(0x000200, 6)
-mmctx_data(0x00021c, 2)
-mmctx_data(0x000230, 1)
-mmctx_data(0x0002c4, 1)
-mmctx_data(0x000400, 3)
-mmctx_data(0x000420, 3)
-mmctx_data(0x0004e8, 1)
-mmctx_data(0x0004f4, 1)
-mmctx_data(0x000604, 4)
-mmctx_data(0x000644, 22)
-mmctx_data(0x0006ac, 2)
-mmctx_data(0x0006c8, 1)
-mmctx_data(0x000730, 8)
-mmctx_data(0x000758, 1)
-mmctx_data(0x000778, 1)
-nve4_tpc_mmio_tail:
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
 
 .section #nve0_grgpc_code
+#define INCLUDE_CODE
 bra #init
-define(`include_code')
-include(`nve0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nve0.fuc)
-//
-error:
-	push $r14
-	mov $r14 -0x67ec 	// 0x9814
-	sethi $r14 0x400000
-	call #nv_wr32		// HUB_CTXCTL_CC_SCRATCH[5] = error code
-	add b32 $r14 0x41c
-	mov $r15 1
-	call #nv_wr32		// HUB_CTXCTL_INTR_UP_SET
-	pop $r14
-	ret
-
-// GPC fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//   CC_SCRATCH[1]: context base
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: GPC context size
-//
-init:
-	clear b32 $r0
-	mov $sp $r0
-
-	// enable fifo access
-	mov $r1 0x1200
-	mov $r2 2
-	iowr I[$r1 + 0x000] $r2		// FIFO_ENABLE
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	mov $r1 0x400
-	iowr I[$r1 + 0x300] $r0		// INTR_DISPATCH
-
-	// enable fifo interrupt
-	mov $r2 4
-	iowr I[$r1 + 0x000] $r2		// INTR_EN_SET
-
-	// enable interrupts
-	bset $flags ie0
-
-	// figure out which GPC we are, and how many TPCs we have
-	mov $r1 0x608
-	shl b32 $r1 6
-	iord $r2 I[$r1 + 0x000]		// UNITS
-	mov $r3 1
-	and $r2 0x1f
-	shl b32 $r3 $r2
-	sub b32 $r3 1
-	st b32 D[$r0 + #tpc_count] $r2
-	st b32 D[$r0 + #tpc_mask] $r3
-	add b32 $r1 0x400
-	iord $r2 I[$r1 + 0x000]		// MYINDEX
-	st b32 D[$r0 + #gpc_id] $r2
-
-	// find context data for this chipset
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
-	mov $r1 #chipsets - 12
-	init_find_chipset:
-		add b32 $r1 12
-		ld b32 $r3 D[$r1 + 0x00]
-		cmpu b32 $r3 $r2
-		bra e #init_context
-		cmpu b32 $r3 0
-		bra ne #init_find_chipset
-		// unknown chipset
-		ret
-
-	// initialise context base, and size tracking
-	init_context:
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x100]	// CC_SCRATCH[1], initial base
-	clear b32 $r3		// track GPC context size here
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't currently ever change
-	mov $r4 0x700
-	shl b32 $r4 6
-	shr b32 $r5 $r2 8
-	iowr I[$r4 + 0x000] $r5		// MMCTX_SAVE_SWBASE
-	iowr I[$r4 + 0x100] $r5		// MMCTX_LOAD_SWBASE
-
-	// calculate GPC mmio context size, store the chipset-specific
-	// mmio list pointers somewhere we can get at them later without
-	// re-parsing the chipset list
-	clear b32 $r14
-	clear b32 $r15
-	ld b16 $r14 D[$r1 + 4]
-	ld b16 $r15 D[$r1 + 6]
-	st b16 D[$r0 + #gpc_mmio_list_head] $r14
-	st b16 D[$r0 + #gpc_mmio_list_tail] $r15
-	call #mmctx_size
-	add b32 $r2 $r15
-	add b32 $r3 $r15
-
-	// calculate per-TPC mmio context size, store the list pointers
-	ld b16 $r14 D[$r1 + 8]
-	ld b16 $r15 D[$r1 + 10]
-	st b16 D[$r0 + #tpc_mmio_list_head] $r14
-	st b16 D[$r0 + #tpc_mmio_list_tail] $r15
-	call #mmctx_size
-	ld b32 $r14 D[$r0 + #tpc_count]
-	mulu $r14 $r15
-	add b32 $r2 $r14
-	add b32 $r3 $r14
-
-	// round up base/size to 256 byte boundary (for strand SWBASE)
-	add b32 $r4 0x1300
-	shr b32 $r3 2
-	iowr I[$r4 + 0x000] $r3		// MMCTX_LOAD_COUNT, wtf for?!?
-	shr b32 $r2 8
-	shr b32 $r3 6
-	add b32 $r2 1
-	add b32 $r3 1
-	shl b32 $r2 8
-	shl b32 $r3 8
-
-	// calculate size of strand context data
-	mov b32 $r15 $r2
-	call #strand_ctx_init
-	add b32 $r3 $r15
-
-	// save context size, and tell HUB we're done
-	mov $r1 0x800
-	shl b32 $r1 6
-	iowr I[$r1 + 0x100] $r3		// CC_SCRATCH[1]  = context size
-	add b32 $r1 0x800
-	clear b32 $r2
-	bset $r2 31
-	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call #queue_get
-	bra $p1 #main
-
-	// 0x0000-0x0003 are all context transfers
-	cmpu b32 $r14 0x04
-	bra nc #main_not_ctx_xfer
-		// fetch $flags and mask off $p1/$p2
-		mov $r1 $flags
-		mov $r2 0x0006
-		not b32 $r2
-		and $r1 $r2
-		// set $p1/$p2 according to transfer type
-		shl b32 $r14 1
-		or $r1 $r14
-		mov $flags $r1
-		// transfer context data
-		call #ctx_xfer
-		bra #main
-
-	main_not_ctx_xfer:
-	shl b32 $r15 $r14 16
-	or $r15 E_BAD_COMMAND
-	call #error
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-
-	// incoming fifo command?
-	iord $r10 I[$r0 + 0x200]	// INTR
-	and $r11 $r10 0x00000004
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r11 0x1900
-		mov $r13 #cmd_queue
-		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
-		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
-		call #queue_put
-		add b32 $r11 0x400
-		mov $r14 1
-		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
-
-	// ack, and wake up main()
-	ih_no_fifo:
-	iowr I[$r0 + 0x100] $r10	// INTR_ACK
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Set this GPC's bit in HUB_BAR, used to signal completion of various
-// activities to the HUB fuc
-//
-hub_barrier_done:
-	mov $r15 1
-	ld b32 $r14 D[$r0 + #gpc_id]
-	shl b32 $r15 $r14
-	mov $r14 -0x6be8 	// 0x409418 - HUB_BAR_SET
-	sethi $r14 0x400000
-	call #nv_wr32
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 0x614
-	shl b32 $r14 6
-	mov $r15 0x020
-	iowr I[$r14] $r15	// GPC_RED_SWITCH = POWER
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	mov $r15 0xa20
-	iowr I[$r14] $r15	// GPC_RED_SWITCH = UNK11, ENABLE, POWER
-	ret
-
-// Transfer GPC context data between GPU and storage area
-//
-// In: $r15 context base address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// set context base address
-	mov $r1 0xa04
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r15// MEM_BASE
-	bra not $p1 #ctx_xfer_not_load
-		call #ctx_redswitch
-	ctx_xfer_not_load:
-
-	// strands
-	mov $r1 0x4afc
-	sethi $r1 0x20000
-	mov $r2 0xc
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
-	call #strand_wait
-	mov $r2 0x47fc
-	sethi $r2 0x20000
-	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
-	xbit $r2 $flags $p1
-	add b32 $r2 3
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 2		// first
-	mov $r11 0x0000
-	sethi $r11 0x500000
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn
-	ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
-	mov $r14 0		// not multi
-	call #mmctx_xfer
-
-	// per-TPC mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 4		// last
-	mov $r11 0x4000
-	sethi $r11 0x500000	// base = NV_PGRAPH_GPC0_TPC0
-	ld b32 $r12 D[$r0 + #gpc_id]
-	shl b32 $r12 15
-	add b32 $r11 $r12	// base = NV_PGRAPH_GPCn_TPC0
-	ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
-	ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
-	ld b32 $r15 D[$r0 + #tpc_mask]
-	mov $r14 0x800		// stride = 0x800
-	call #mmctx_xfer
-
-	// wait for strands to finish
-	call #strand_wait
-
-	// if load, or a save without a load following, do some
-	// unknown stuff that's done after finishing a block of
-	// strand commands
-	bra $p1 #ctx_xfer_post
-	bra not $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r1 0x4afc
-		sethi $r1 0x20000
-		mov $r2 0xd
-		iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0d
-		call #strand_wait
-
-	// mark completion in HUB's barrier
-	ctx_xfer_done:
-	call #hub_barrier_done
-	ret
-
+#include "com.fuc"
+#include "gpc.fuc"
 .align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
index 09ee470..7ff5ef6 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
@@ -1,19 +1,25 @@
 uint32_t nve0_grgpc_data[] = {
-/* 0x0000: gpc_id */
+/* 0x0000: gpc_mmio_list_head */
+	0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+	0x0000006c,
+/* 0x0010: gpc_id */
 	0x00000000,
-/* 0x0004: gpc_mmio_list_head */
+/* 0x0014: tpc_count */
 	0x00000000,
-/* 0x0008: gpc_mmio_list_tail */
+/* 0x0018: tpc_mask */
 	0x00000000,
-/* 0x000c: tpc_count */
+/* 0x001c: unk_count */
 	0x00000000,
-/* 0x0010: tpc_mask */
+/* 0x0020: unk_mask */
 	0x00000000,
-/* 0x0014: tpc_mmio_list_head */
-	0x00000000,
-/* 0x0018: tpc_mmio_list_tail */
-	0x00000000,
-/* 0x001c: cmd_queue */
+/* 0x0024: cmd_queue */
 	0x00000000,
 	0x00000000,
 	0x00000000,
@@ -32,82 +38,17 @@
 	0x00000000,
 	0x00000000,
 	0x00000000,
-/* 0x0064: chipsets */
-	0x000000e4,
-	0x0110008c,
-	0x01580110,
-	0x000000e7,
-	0x0110008c,
-	0x01580110,
-	0x000000e6,
-	0x0110008c,
-	0x01580110,
-	0x00000000,
-/* 0x008c: nve4_gpc_mmio_head */
-	0x00000380,
-	0x04000400,
-	0x0800040c,
-	0x20000450,
-	0x00000600,
-	0x00000684,
-	0x10000700,
-	0x00000800,
-	0x08000808,
-	0x00000828,
-	0x00000830,
-	0x000008d8,
-	0x000008e0,
-	0x140008e8,
-	0x0000091c,
-	0x08000924,
-	0x00000b00,
-	0x14000b08,
-	0x00000bb8,
-	0x00000c08,
-	0x1c000c10,
-	0x00000c40,
-	0x00000c6c,
-	0x00000c80,
-	0x00000c8c,
-	0x08001000,
-	0x00001014,
-	0x00003024,
-	0x040030c0,
-	0x000030e4,
-	0x14003100,
-	0x000031d0,
-	0x040031e0,
-/* 0x0110: nve4_gpc_mmio_tail */
-/* 0x0110: nve4_tpc_mmio_head */
-	0x00000048,
-	0x00000064,
-	0x00000088,
-	0x14000200,
-	0x0400021c,
-	0x00000230,
-	0x000002c4,
-	0x08000400,
-	0x08000420,
-	0x000004e8,
-	0x000004f4,
-	0x0c000604,
-	0x54000644,
-	0x040006ac,
-	0x000006c8,
-	0x1c000730,
-	0x00000758,
-	0x00000778,
 };
 
 uint32_t nve0_grgpc_code[] = {
-	0x03060ef5,
+	0x03180ef5,
 /* 0x0004: queue_put */
 	0x9800d898,
 	0x86f001d9,
 	0x0489b808,
 	0xf00c1bf4,
 	0x21f502f7,
-	0x00f802ec,
+	0x00f802fe,
 /* 0x001c: queue_put_next */
 	0xb60798c4,
 	0x8dbb0384,
@@ -139,7 +80,7 @@
 	0xc800bccf,
 	0x1bf41fcc,
 	0x06a7f0fa,
-	0x010321f5,
+	0x010921f5,
 	0xf840bfcf,
 /* 0x008d: nv_wr32 */
 	0x28b7f100,
@@ -161,63 +102,66 @@
 	0x0684b604,
 	0xf80080d0,
 /* 0x00c9: wait_donez */
-	0x3c87f100,
-	0x0684b608,
-	0x99f094bd,
-	0x0089d000,
-	0x081887f1,
-	0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
-	0x87f1008a,
-	0x84b60400,
-	0x0088cf06,
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x07f104bd,
+	0x03f00600,
+	0x000ad002,
+/* 0x00e6: wait_donez_ne */
+	0x87f104bd,
+	0x83f00000,
+	0x0088cf01,
 	0xf4888aff,
-	0x87f1f31b,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00099,
-/* 0x0103: wait_doneo */
-	0xf100f800,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00099f0,
-	0x87f10089,
+	0x94bdf31b,
+	0xf10099f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0109: wait_doneo */
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x87f104bd,
 	0x84b60818,
 	0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x0124: wait_doneo_e */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
 	0xf30bf488,
-	0x085c87f1,
-	0xbd0684b6,
-	0x0099f094,
-	0xf80089d0,
-/* 0x013d: mmctx_size */
-/* 0x013f: nv_mmctx_size_loop */
-	0x9894bd00,
-	0x85b600e8,
-	0x0180b61a,
-	0xbb0284b6,
-	0xe0b60098,
-	0x04efb804,
-	0xb9eb1bf4,
-	0x00f8029f,
-/* 0x015c: mmctx_xfer */
-	0x083c87f1,
-	0xbd0684b6,
-	0x0199f094,
-	0xf10089d0,
+	0x99f094bd,
+	0x0007f100,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x0147: mmctx_size */
+	0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+	0x00e89894,
+	0xb61a85b6,
+	0x84b60180,
+	0x0098bb02,
+	0xb804e0b6,
+	0x1bf404ef,
+	0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+	0x94bd00f8,
+	0xf10199f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
 	0xb6071087,
 	0x94bd0684,
 	0xf405bbfd,
 	0x8bd0090b,
 	0x0099f000,
-/* 0x0180: mmctx_base_disabled */
+/* 0x018c: mmctx_base_disabled */
 	0xf405eefd,
 	0x8ed00c0b,
 	0xc08fd080,
-/* 0x018f: mmctx_multi_disabled */
+/* 0x019b: mmctx_multi_disabled */
 	0xb70199f0,
 	0xc8010080,
 	0xb4b600ab,
@@ -225,8 +169,8 @@
 	0xb601aec8,
 	0xbefd11e4,
 	0x008bd005,
-/* 0x01a8: mmctx_exec_loop */
-/* 0x01a8: mmctx_wait_free */
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
 	0xf0008ecf,
 	0x0bf41fe4,
 	0x00ce98fa,
@@ -235,76 +179,77 @@
 	0x04cdb804,
 	0xc8e81bf4,
 	0x1bf402ab,
-/* 0x01c9: mmctx_fini_wait */
+/* 0x01d5: mmctx_fini_wait */
 	0x008bcf18,
 	0xb01fb4f0,
 	0x1bf410b4,
 	0x02a7f0f7,
 	0xf4c921f4,
-/* 0x01de: mmctx_stop */
+/* 0x01ea: mmctx_stop */
 	0xabc81b0e,
 	0x10b4b600,
 	0xf00cb9f0,
 	0x8bd012b9,
-/* 0x01ed: mmctx_stop_wait */
+/* 0x01f9: mmctx_stop_wait */
 	0x008bcf00,
 	0xf412bbc8,
-/* 0x01f6: mmctx_done */
-	0x87f1fa1b,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00199,
-/* 0x0207: strand_wait */
-	0xf900f800,
-	0x02a7f0a0,
-	0xfcc921f4,
-/* 0x0213: strand_pre */
-	0xf100f8a0,
-	0xf04afc87,
-	0x97f00283,
-	0x0089d00c,
-	0x020721f5,
-/* 0x0226: strand_post */
-	0x87f100f8,
-	0x83f04afc,
-	0x0d97f002,
-	0xf50089d0,
-	0xf8020721,
-/* 0x0239: strand_set */
-	0xfca7f100,
-	0x02a3f04f,
-	0x0500aba2,
-	0xd00fc7f0,
-	0xc7f000ac,
-	0x00bcd00b,
-	0x020721f5,
-	0xf000aed0,
-	0xbcd00ac7,
-	0x0721f500,
-/* 0x0263: strand_ctx_init */
-	0xf100f802,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00399f0,
+/* 0x0202: mmctx_done */
+	0x94bdfa1b,
+	0xf10199f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0215: strand_wait */
+	0xf0a0f900,
+	0x21f402a7,
+	0xf8a0fcc9,
+/* 0x0221: strand_pre */
+	0xfc87f100,
+	0x0283f04a,
+	0xd00c97f0,
 	0x21f50089,
-	0xe7f00213,
-	0x3921f503,
+	0x00f80215,
+/* 0x0234: strand_post */
+	0x4afc87f1,
+	0xf00283f0,
+	0x89d00d97,
+	0x1521f500,
+/* 0x0247: strand_set */
+	0xf100f802,
+	0xf04ffca7,
+	0xaba202a3,
+	0xc7f00500,
+	0x00acd00f,
+	0xd00bc7f0,
+	0x21f500bc,
+	0xaed00215,
+	0x0ac7f000,
+	0xf500bcd0,
+	0xf8021521,
+/* 0x0271: strand_ctx_init */
+	0xf094bd00,
+	0x07f10399,
+	0x03f00f00,
+	0x0009d002,
+	0x21f504bd,
+	0xe7f00221,
+	0x4721f503,
 	0xfca7f102,
 	0x02a3f046,
 	0x0400aba0,
 	0xf040a0d0,
 	0xbcd001c7,
-	0x0721f500,
+	0x1521f500,
 	0x010c9202,
 	0xf000acd0,
 	0xbcd002c7,
-	0x0721f500,
-	0x2621f502,
+	0x1521f500,
+	0x3421f502,
 	0x8087f102,
 	0x0684b608,
 	0xb70089cf,
 	0x95220080,
-/* 0x02ba: ctx_init_strand_loop */
+/* 0x02ca: ctx_init_strand_loop */
 	0x8ed008fe,
 	0x408ed000,
 	0xb6808acf,
@@ -313,150 +258,160 @@
 	0xb60480b6,
 	0x1bf40192,
 	0x08e4b6e8,
-	0xf1f2efbc,
-	0xb6085c87,
-	0x94bd0684,
-	0xd00399f0,
-	0x00f80089,
-/* 0x02ec: error */
-	0xe7f1e0f9,
-	0xe3f09814,
-	0x8d21f440,
-	0x041ce0b7,
-	0xf401f7f0,
-	0xe0fc8d21,
-/* 0x0306: init */
-	0x04bd00f8,
-	0xf10004fe,
-	0xf0120017,
-	0x12d00227,
-	0x3e17f100,
-	0x0010fe04,
-	0x040017f1,
-	0xf0c010d0,
-	0x12d00427,
-	0x1031f400,
-	0x060817f1,
-	0xcf0614b6,
-	0x37f00012,
-	0x1f24f001,
-	0xb60432bb,
-	0x02800132,
-	0x04038003,
-	0x040010b7,
-	0x800012cf,
-	0x27f10002,
-	0x24b60800,
-	0x0022cf06,
-/* 0x035f: init_find_chipset */
-	0xb65817f0,
-	0x13980c10,
-	0x0432b800,
-	0xb00b0bf4,
-	0x1bf40034,
-/* 0x0373: init_context */
-	0xf100f8f1,
-	0xb6080027,
-	0x22cf0624,
-	0xf134bd40,
-	0xb6070047,
-	0x25950644,
-	0x0045d008,
-	0xbd4045d0,
-	0x58f4bde4,
-	0x1f58021e,
-	0x020e4003,
-	0xf5040f40,
-	0xbb013d21,
-	0x3fbb002f,
-	0x041e5800,
-	0x40051f58,
-	0x0f400a0e,
-	0x3d21f50c,
-	0x030e9801,
-	0xbb00effd,
-	0x3ebb002e,
-	0x0040b700,
-	0x0235b613,
-	0xb60043d0,
-	0x35b60825,
-	0x0120b606,
-	0xb60130b6,
-	0x34b60824,
-	0x022fb908,
-	0x026321f5,
-	0xf1003fbb,
-	0xb6080017,
-	0x13d00614,
-	0x0010b740,
-	0xf024bd08,
-	0x12d01f29,
-/* 0x0401: main */
-	0x0031f400,
-	0xf00028f4,
-	0x21f41cd7,
-	0xf401f439,
-	0xf404e4b0,
-	0x81fe1e18,
-	0x0627f001,
-	0x12fd20bd,
-	0x01e4b604,
-	0xfe051efd,
-	0x21f50018,
-	0x0ef404c3,
-/* 0x0431: main_not_ctx_xfer */
-	0x10ef94d3,
-	0xf501f5f0,
-	0xf402ec21,
-/* 0x043e: ih */
-	0x80f9c60e,
-	0xf90188fe,
-	0xf990f980,
-	0xf9b0f9a0,
-	0xf9e0f9d0,
-	0x800acff0,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x02fe: error */
+	0xe0f900f8,
+	0x9814e7f1,
+	0xf440e3f0,
+	0xe0b78d21,
+	0xf7f0041c,
+	0x8d21f401,
+	0x00f8e0fc,
+/* 0x0318: init */
+	0x04fe04bd,
+	0x0017f100,
+	0x0227f012,
+	0xf10012d0,
+	0xfe047017,
+	0x17f10010,
+	0x10d00400,
+	0x0427f0c0,
+	0xf40012d0,
+	0x17f11031,
+	0x14b60608,
+	0x0012cf06,
+	0xf00137f0,
+	0x32bb1f24,
+	0x0132b604,
+	0x80050280,
+	0x10b70603,
+	0x12cf0400,
+	0x04028000,
+	0x0c30e7f1,
+	0xbd50e3f0,
+	0xbd34bd24,
+/* 0x0371: init_unk_loop */
+	0x6821f444,
+	0xf400f6b0,
+	0xf7f00f0b,
+	0x04f2bb01,
+	0xb6054ffd,
+/* 0x0386: init_unk_next */
+	0x20b60130,
+	0x04e0b601,
+	0xf40126b0,
+/* 0x0392: init_unk_done */
+	0x0380e21b,
+	0x08048007,
+	0x010027f1,
+	0xcf0223f0,
+	0x34bd0022,
+	0x070047f1,
+	0x950644b6,
+	0x45d00825,
+	0x4045d000,
+	0x98000e98,
+	0x21f5010f,
+	0x2fbb0147,
+	0x003fbb00,
+	0x98010e98,
+	0x21f5020f,
+	0x0e980147,
+	0x00effd05,
+	0xbb002ebb,
+	0x0e98003e,
+	0x030f9802,
+	0x014721f5,
+	0xfd070e98,
+	0x2ebb00ef,
+	0x003ebb00,
+	0x130040b7,
+	0xd00235b6,
+	0x25b60043,
+	0x0635b608,
+	0xb60120b6,
+	0x24b60130,
+	0x0834b608,
+	0xf5022fb9,
+	0xbb027121,
+	0x07f1003f,
+	0x03f00100,
+	0x0003d002,
+	0x24bd04bd,
+	0xf11f29f0,
+	0xf0080007,
+	0x02d00203,
+/* 0x0433: main */
+	0xf404bd00,
+	0x28f40031,
+	0x24d7f000,
+	0xf43921f4,
+	0xe4b0f401,
+	0x1e18f404,
+	0xf00181fe,
+	0x20bd0627,
+	0xb60412fd,
+	0x1efd01e4,
+	0x0018fe05,
+	0x04f721f5,
+/* 0x0463: main_not_ctx_xfer */
+	0x94d30ef4,
+	0xf5f010ef,
+	0xfe21f501,
+	0xc60ef402,
+/* 0x0470: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x800acf04,
 	0xf404abc4,
 	0xb7f11d0b,
 	0xd7f01900,
-	0x40becf1c,
+	0x40becf24,
 	0xf400bfcf,
 	0xb0b70421,
 	0xe7f00400,
 	0x00bed001,
-/* 0x0474: ih_no_fifo */
+/* 0x04a8: ih_no_fifo */
 	0xfc400ad0,
 	0xfce0fcf0,
 	0xfcb0fcd0,
 	0xfc90fca0,
 	0x0088fe80,
 	0x32f480fc,
-/* 0x048f: hub_barrier_done */
+/* 0x04c3: hub_barrier_done */
 	0xf001f800,
 	0x0e9801f7,
-	0x04febb00,
+	0x04febb04,
 	0x9418e7f1,
 	0xf440e3f0,
 	0x00f88d21,
-/* 0x04a4: ctx_redswitch */
+/* 0x04d8: ctx_redswitch */
 	0x0614e7f1,
 	0xf006e4b6,
 	0xefd020f7,
 	0x08f7f000,
-/* 0x04b4: ctx_redswitch_delay */
+/* 0x04e8: ctx_redswitch_delay */
 	0xf401f2b6,
 	0xf7f1fd1b,
 	0xefd00a20,
-/* 0x04c3: ctx_xfer */
+/* 0x04f7: ctx_xfer */
 	0xf100f800,
 	0xb60a0417,
 	0x1fd00614,
 	0x0711f400,
-	0x04a421f5,
-/* 0x04d4: ctx_xfer_not_load */
+	0x04d821f5,
+/* 0x0508: ctx_xfer_not_load */
 	0x4afc17f1,
 	0xf00213f0,
 	0x12d00c27,
-	0x0721f500,
+	0x1521f500,
 	0xfc27f102,
 	0x0223f047,
 	0xf00020d0,
@@ -465,31 +420,40 @@
 	0xf001acf0,
 	0xb7f002a5,
 	0x50b3f000,
-	0xb6000c98,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x000c9800,
+	0xf0010d98,
+	0x21f500e7,
+	0xacf00166,
+	0x00b7f101,
+	0x50b3f040,
+	0xb6040c98,
 	0xbcbb0fc4,
 	0x010c9800,
-	0xf0020d98,
-	0x21f500e7,
-	0xacf0015c,
+	0x98020d98,
+	0xe7f1060f,
+	0x21f50800,
+	0xacf00166,
 	0x04a5f001,
-	0x4000b7f1,
+	0x3000b7f1,
 	0x9850b3f0,
-	0xc4b6000c,
+	0xc4b6040c,
 	0x00bcbb0f,
-	0x98050c98,
-	0x0f98060d,
-	0x00e7f104,
-	0x5c21f508,
-	0x0721f501,
+	0x98020c98,
+	0x0f98030d,
+	0x00e7f108,
+	0x6621f502,
+	0x1521f501,
 	0x0601f402,
-/* 0x054b: ctx_xfer_post */
+/* 0x05a3: ctx_xfer_post */
 	0xf11412f4,
 	0xf04afc17,
 	0x27f00213,
 	0x0012d00d,
-	0x020721f5,
-/* 0x055c: ctx_xfer_done */
-	0x048f21f5,
+	0x021521f5,
+/* 0x05b4: ctx_xfer_done */
+	0x04c321f5,
 	0x000000f8,
 	0x00000000,
 	0x00000000,
@@ -508,26 +472,4 @@
 	0x00000000,
 	0x00000000,
 	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
 };
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc
new file mode 100644
index 0000000..90bbe52
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000002
+
+#define CHIPSET GK110
+#include "macros.fuc"
+
+.section #nvf0_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #nvf0_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
new file mode 100644
index 0000000..f870507
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
@@ -0,0 +1,475 @@
+uint32_t nvf0_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+	0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+	0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+	0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+	0x0000006c,
+/* 0x0010: gpc_id */
+	0x00000000,
+/* 0x0014: tpc_count */
+	0x00000000,
+/* 0x0018: tpc_mask */
+	0x00000000,
+/* 0x001c: unk_count */
+	0x00000000,
+/* 0x0020: unk_mask */
+	0x00000000,
+/* 0x0024: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
+
+uint32_t nvf0_grgpc_code[] = {
+	0x03180ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f802fe,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0x0728b7f1,
+	0xb906b4b6,
+	0xc9f002ec,
+	0x00bcd01f,
+/* 0x0078: nv_rd32_wait */
+	0xc800bccf,
+	0x1bf41fcc,
+	0x06a7f0fa,
+	0x010921f5,
+	0xf840bfcf,
+/* 0x008d: nv_wr32 */
+	0x28b7f100,
+	0x06b4b607,
+	0xb980bfd0,
+	0xc9f002ec,
+	0x1ec9f01f,
+/* 0x00a3: nv_wr32_wait */
+	0xcf00bcd0,
+	0xccc800bc,
+	0xfa1bf41f,
+/* 0x00ae: watchdog_reset */
+	0x87f100f8,
+	0x84b60430,
+	0x1ff9f006,
+	0xf8008fd0,
+/* 0x00bd: watchdog_clear */
+	0x3087f100,
+	0x0684b604,
+	0xf80080d0,
+/* 0x00c9: wait_donez */
+	0xf094bd00,
+	0x07f10099,
+	0x03f03700,
+	0x0009d002,
+	0x07f104bd,
+	0x03f00600,
+	0x000ad002,
+/* 0x00e6: wait_donez_ne */
+	0x87f104bd,
+	0x83f00000,
+	0x0088cf01,
+	0xf4888aff,
+	0x94bdf31b,
+	0xf10099f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0109: wait_doneo */
+	0xf094bd00,
+	0x07f10099,
+	0x03f03700,
+	0x0009d002,
+	0x87f104bd,
+	0x84b60818,
+	0x008ad006,
+/* 0x0124: wait_doneo_e */
+	0x040087f1,
+	0xcf0684b6,
+	0x8aff0088,
+	0xf30bf488,
+	0x99f094bd,
+	0x0007f100,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x0147: mmctx_size */
+	0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+	0x00e89894,
+	0xb61a85b6,
+	0x84b60180,
+	0x0098bb02,
+	0xb804e0b6,
+	0x1bf404ef,
+	0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+	0x94bd00f8,
+	0xf10199f0,
+	0xf0370007,
+	0x09d00203,
+	0xf104bd00,
+	0xb6071087,
+	0x94bd0684,
+	0xf405bbfd,
+	0x8bd0090b,
+	0x0099f000,
+/* 0x018c: mmctx_base_disabled */
+	0xf405eefd,
+	0x8ed00c0b,
+	0xc08fd080,
+/* 0x019b: mmctx_multi_disabled */
+	0xb70199f0,
+	0xc8010080,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xb601aec8,
+	0xbefd11e4,
+	0x008bd005,
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
+	0xf0008ecf,
+	0x0bf41fe4,
+	0x00ce98fa,
+	0xd005e9fd,
+	0xc0b6c08e,
+	0x04cdb804,
+	0xc8e81bf4,
+	0x1bf402ab,
+/* 0x01d5: mmctx_fini_wait */
+	0x008bcf18,
+	0xb01fb4f0,
+	0x1bf410b4,
+	0x02a7f0f7,
+	0xf4c921f4,
+/* 0x01ea: mmctx_stop */
+	0xabc81b0e,
+	0x10b4b600,
+	0xf00cb9f0,
+	0x8bd012b9,
+/* 0x01f9: mmctx_stop_wait */
+	0x008bcf00,
+	0xf412bbc8,
+/* 0x0202: mmctx_done */
+	0x94bdfa1b,
+	0xf10199f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0215: strand_wait */
+	0xf0a0f900,
+	0x21f402a7,
+	0xf8a0fcc9,
+/* 0x0221: strand_pre */
+	0xfc87f100,
+	0x0283f04a,
+	0xd00c97f0,
+	0x21f50089,
+	0x00f80215,
+/* 0x0234: strand_post */
+	0x4afc87f1,
+	0xf00283f0,
+	0x89d00d97,
+	0x1521f500,
+/* 0x0247: strand_set */
+	0xf100f802,
+	0xf04ffca7,
+	0xaba202a3,
+	0xc7f00500,
+	0x00acd00f,
+	0xd00bc7f0,
+	0x21f500bc,
+	0xaed00215,
+	0x0ac7f000,
+	0xf500bcd0,
+	0xf8021521,
+/* 0x0271: strand_ctx_init */
+	0xf094bd00,
+	0x07f10399,
+	0x03f03700,
+	0x0009d002,
+	0x21f504bd,
+	0xe7f00221,
+	0x4721f503,
+	0xfca7f102,
+	0x02a3f046,
+	0x0400aba0,
+	0xf040a0d0,
+	0xbcd001c7,
+	0x1521f500,
+	0x010c9202,
+	0xf000acd0,
+	0xbcd002c7,
+	0x1521f500,
+	0x3421f502,
+	0x8087f102,
+	0x0684b608,
+	0xb70089cf,
+	0x95220080,
+/* 0x02ca: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x02fe: error */
+	0xe0f900f8,
+	0x9814e7f1,
+	0xf440e3f0,
+	0xe0b78d21,
+	0xf7f0041c,
+	0x8d21f401,
+	0x00f8e0fc,
+/* 0x0318: init */
+	0x04fe04bd,
+	0x0017f100,
+	0x0227f012,
+	0xf10012d0,
+	0xfe047017,
+	0x17f10010,
+	0x10d00400,
+	0x0427f0c0,
+	0xf40012d0,
+	0x17f11031,
+	0x14b60608,
+	0x0012cf06,
+	0xf00137f0,
+	0x32bb1f24,
+	0x0132b604,
+	0x80050280,
+	0x10b70603,
+	0x12cf0400,
+	0x04028000,
+	0x0c30e7f1,
+	0xbd50e3f0,
+	0xbd34bd24,
+/* 0x0371: init_unk_loop */
+	0x6821f444,
+	0xf400f6b0,
+	0xf7f00f0b,
+	0x04f2bb01,
+	0xb6054ffd,
+/* 0x0386: init_unk_next */
+	0x20b60130,
+	0x04e0b601,
+	0xf40226b0,
+/* 0x0392: init_unk_done */
+	0x0380e21b,
+	0x08048007,
+	0x010027f1,
+	0xcf0223f0,
+	0x34bd0022,
+	0x070047f1,
+	0x950644b6,
+	0x45d00825,
+	0x4045d000,
+	0x98000e98,
+	0x21f5010f,
+	0x2fbb0147,
+	0x003fbb00,
+	0x98010e98,
+	0x21f5020f,
+	0x0e980147,
+	0x00effd05,
+	0xbb002ebb,
+	0x0e98003e,
+	0x030f9802,
+	0x014721f5,
+	0xfd070e98,
+	0x2ebb00ef,
+	0x003ebb00,
+	0x130040b7,
+	0xd00235b6,
+	0x25b60043,
+	0x0635b608,
+	0xb60120b6,
+	0x24b60130,
+	0x0834b608,
+	0xf5022fb9,
+	0xbb027121,
+	0x07f1003f,
+	0x03f00100,
+	0x0003d002,
+	0x24bd04bd,
+	0xf11f29f0,
+	0xf0300007,
+	0x02d00203,
+/* 0x0433: main */
+	0xf404bd00,
+	0x28f40031,
+	0x24d7f000,
+	0xf43921f4,
+	0xe4b0f401,
+	0x1e18f404,
+	0xf00181fe,
+	0x20bd0627,
+	0xb60412fd,
+	0x1efd01e4,
+	0x0018fe05,
+	0x04f721f5,
+/* 0x0463: main_not_ctx_xfer */
+	0x94d30ef4,
+	0xf5f010ef,
+	0xfe21f501,
+	0xc60ef402,
+/* 0x0470: ih */
+	0x88fe80f9,
+	0xf980f901,
+	0xf9a0f990,
+	0xf9d0f9b0,
+	0xbdf0f9e0,
+	0x800acf04,
+	0xf404abc4,
+	0xb7f11d0b,
+	0xd7f01900,
+	0x40becf24,
+	0xf400bfcf,
+	0xb0b70421,
+	0xe7f00400,
+	0x00bed001,
+/* 0x04a8: ih_no_fifo */
+	0xfc400ad0,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x04c3: hub_barrier_done */
+	0xf001f800,
+	0x0e9801f7,
+	0x04febb04,
+	0x9418e7f1,
+	0xf440e3f0,
+	0x00f88d21,
+/* 0x04d8: ctx_redswitch */
+	0x0614e7f1,
+	0xf006e4b6,
+	0xefd020f7,
+	0x08f7f000,
+/* 0x04e8: ctx_redswitch_delay */
+	0xf401f2b6,
+	0xf7f1fd1b,
+	0xefd00a20,
+/* 0x04f7: ctx_xfer */
+	0xf100f800,
+	0xb60a0417,
+	0x1fd00614,
+	0x0711f400,
+	0x04d821f5,
+/* 0x0508: ctx_xfer_not_load */
+	0x4afc17f1,
+	0xf00213f0,
+	0x12d00c27,
+	0x1521f500,
+	0xfc27f102,
+	0x0223f047,
+	0xf00020d0,
+	0x20b6012c,
+	0x0012d003,
+	0xf001acf0,
+	0xb7f002a5,
+	0x50b3f000,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x000c9800,
+	0xf0010d98,
+	0x21f500e7,
+	0xacf00166,
+	0x00b7f101,
+	0x50b3f040,
+	0xb6040c98,
+	0xbcbb0fc4,
+	0x010c9800,
+	0x98020d98,
+	0xe7f1060f,
+	0x21f50800,
+	0xacf00166,
+	0x04a5f001,
+	0x3000b7f1,
+	0x9850b3f0,
+	0xc4b6040c,
+	0x00bcbb0f,
+	0x98020c98,
+	0x0f98030d,
+	0x00e7f108,
+	0x6621f502,
+	0x1521f501,
+	0x0601f402,
+/* 0x05a3: ctx_xfer_post */
+	0xf11412f4,
+	0xf04afc17,
+	0x27f00213,
+	0x0012d00d,
+	0x021521f5,
+/* 0x05b4: ctx_xfer_done */
+	0x04c321f5,
+	0x000000f8,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
new file mode 100644
index 0000000..b82d2ae
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
@@ -0,0 +1,724 @@
+/* fuc microcode for nvc0 PGRAPH/HUB
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_DATA
+hub_mmio_list_head:	.b32 #hub_mmio_list_base
+hub_mmio_list_tail:	.b32 #hub_mmio_list_next
+
+gpc_count:		.b32 0
+rop_count:		.b32 0
+cmd_queue:		queue_init
+
+ctx_current:		.b32 0
+
+.align 256
+chan_data:
+chan_mmio_count:	.b32 0
+chan_mmio_address:	.b32 0
+
+.align 256
+xfer_data: 		.skip 256
+
+hub_mmio_list_base:
+.b32 0x0417e91c // 0x17e91c, 2
+hub_mmio_list_next:
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see nvc0.fuc)
+//
+error:
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), 0, $r15)
+	mov $r15 1
+	nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r15)
+	ret
+
+// HUB fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Output:
+//   CC_SCRATCH[0]:
+//	     31:31: set to signal completion
+//   CC_SCRATCH[1]:
+//	      31:0: total PGRAPH context size
+//
+init:
+	clear b32 $r0
+	mov $sp $r0
+	mov $xdbase $r0
+
+	// enable fifo access
+	mov $r1 0x1200
+	mov $r2 2
+	iowr I[$r1 + 0x000] $r2	// FIFO_ENABLE
+
+	// setup i0 handler, and route all interrupts to it
+	mov $r1 #ih
+	mov $iv0 $r1
+	mov $r1 0x400
+	iowr I[$r1 + 0x300] $r0	// INTR_DISPATCH
+
+	// route HUB_CHANNEL_SWITCH to fuc interrupt 8
+	mov $r3 0x404
+	shl b32 $r3 6
+	mov $r2 0x2003		// { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
+	iowr I[$r3 + 0x000] $r2
+
+	// not sure what these are, route them because NVIDIA does, and
+	// the IRQ handler will signal the host if we ever get one.. we
+	// may find out if/why we need to handle these if so..
+	//
+	mov $r2 0x2004
+	iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
+	mov $r2 0x200b
+	iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
+	mov $r2 0x200c
+	iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
+
+	// enable all INTR_UP interrupts
+	mov $r2 0xc24
+	shl b32 $r2 6
+	not b32 $r3 $r0
+	iowr I[$r2] $r3
+
+	// enable fifo, ctxsw, 9, 10, 15 interrupts
+	mov $r2 -0x78fc		// 0x8704
+	sethi $r2 0
+	iowr I[$r1 + 0x000] $r2	// INTR_EN_SET
+
+	// fifo level triggered, rest edge
+	sub b32 $r1 0x100
+	mov $r2 4
+	iowr I[$r1] $r2
+
+	// enable interrupts
+	bset $flags ie0
+
+	// fetch enabled GPC/ROP counts
+	mov $r14 -0x69fc	// 0x409604
+	sethi $r14 0x400000
+	call #nv_rd32
+	extr $r1 $r15 16:20
+	st b32 D[$r0 + #rop_count] $r1
+	and $r15 0x1f
+	st b32 D[$r0 + #gpc_count] $r15
+
+	// set BAR_REQMASK to GPC mask
+	mov $r1 1
+	shl b32 $r1 $r15
+	sub b32 $r1 1
+	mov $r2 0x40c
+	shl b32 $r2 6
+	iowr I[$r2 + 0x000] $r1
+	iowr I[$r2 + 0x100] $r1
+
+	// context size calculation, reserve first 256 bytes for use by fuc
+	mov $r1 256
+
+	// calculate size of mmio context data
+	ld b32 $r14 D[$r0 + #hub_mmio_list_head]
+	ld b32 $r15 D[$r0 + #hub_mmio_list_tail]
+	call #mmctx_size
+
+	// set mmctx base addresses now so we don't have to do it later,
+	// they don't (currently) ever change
+	mov $r3 0x700
+	shl b32 $r3 6
+	shr b32 $r4 $r1 8
+	iowr I[$r3 + 0x000] $r4		// MMCTX_SAVE_SWBASE
+	iowr I[$r3 + 0x100] $r4		// MMCTX_LOAD_SWBASE
+	add b32 $r3 0x1300
+	add b32 $r1 $r15
+	shr b32 $r15 2
+	iowr I[$r3 + 0x000] $r15	// MMCTX_LOAD_COUNT, wtf for?!?
+
+	// strands, base offset needs to be aligned to 256 bytes
+	shr b32 $r1 8
+	add b32 $r1 1
+	shl b32 $r1 8
+	mov b32 $r15 $r1
+	call #strand_ctx_init
+	add b32 $r1 $r15
+
+	// initialise each GPC in sequence by passing in the offset of its
+	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
+	// has previously been uploaded by the host) running.
+	//
+	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
+	// when it has completed, and return the size of its context data
+	// in GPCn_CC_SCRATCH[1]
+	//
+	ld b32 $r3 D[$r0 + #gpc_count]
+	mov $r4 0x2000
+	sethi $r4 0x500000
+	init_gpc:
+		// setup, and start GPC ucode running
+		add b32 $r14 $r4 0x804
+		mov b32 $r15 $r1
+		call #nv_wr32			// CC_SCRATCH[1] = ctx offset
+		add b32 $r14 $r4 0x10c
+		clear b32 $r15
+		call #nv_wr32
+		add b32 $r14 $r4 0x104
+		call #nv_wr32			// ENTRY
+		add b32 $r14 $r4 0x100
+		mov $r15 2			// CTRL_START_TRIGGER
+		call #nv_wr32			// CTRL
+
+		// wait for it to complete, and adjust context size
+		add b32 $r14 $r4 0x800
+		init_gpc_wait:
+			call #nv_rd32
+			xbit $r15 $r15 31
+			bra e #init_gpc_wait
+		add b32 $r14 $r4 0x804
+		call #nv_rd32
+		add b32 $r1 $r15
+
+		// next!
+		add b32 $r4 0x8000
+		sub b32 $r3 1
+		bra ne #init_gpc
+
+	// save context size, and tell host we're ready
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(1), 0, $r1)
+	clear b32 $r1
+	bset $r1 31
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r1)
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+	// sleep until we have something to do
+	bset $flags $p0
+	sleep $p0
+	mov $r13 #cmd_queue
+	call #queue_get
+	bra $p1 #main
+
+	// context switch, requested by GPU?
+	cmpu b32 $r14 0x4001
+	bra ne #main_not_ctx_switch
+		trace_set(T_AUTO)
+		mov $r1 0xb00
+		shl b32 $r1 6
+		iord $r2 I[$r1 + 0x100]		// CHAN_NEXT
+		iord $r1 I[$r1 + 0x000]		// CHAN_CUR
+
+		xbit $r3 $r1 31
+		bra e #chsw_no_prev
+			xbit $r3 $r2 31
+			bra e #chsw_prev_no_next
+				push $r2
+				mov b32 $r2 $r1
+				trace_set(T_SAVE)
+				bclr $flags $p1
+				bset $flags $p2
+				call #ctx_xfer
+				trace_clr(T_SAVE);
+				pop $r2
+				trace_set(T_LOAD);
+				bset $flags $p1
+				call #ctx_xfer
+				trace_clr(T_LOAD);
+				bra #chsw_done
+			chsw_prev_no_next:
+				push $r2
+				mov b32 $r2 $r1
+				bclr $flags $p1
+				bclr $flags $p2
+				call #ctx_xfer
+				pop $r2
+				mov $r1 0xb00
+				shl b32 $r1 6
+				iowr I[$r1] $r2
+				bra #chsw_done
+		chsw_no_prev:
+			xbit $r3 $r2 31
+			bra e #chsw_done
+				bset $flags $p1
+				bclr $flags $p2
+				call #ctx_xfer
+
+		// ack the context switch request
+		chsw_done:
+		mov $r1 0xb0c
+		shl b32 $r1 6
+		mov $r2 1
+		iowr I[$r1 + 0x000] $r2		// 0x409b0c
+		trace_clr(T_AUTO)
+		bra #main
+
+	// request to set current channel? (*not* a context switch)
+	main_not_ctx_switch:
+	cmpu b32 $r14 0x0001
+	bra ne #main_not_ctx_chan
+		mov b32 $r2 $r15
+		call #ctx_chan
+		bra #main_done
+
+	// request to store current channel context?
+	main_not_ctx_chan:
+	cmpu b32 $r14 0x0002
+	bra ne #main_not_ctx_save
+		trace_set(T_SAVE)
+		bclr $flags $p1
+		bclr $flags $p2
+		call #ctx_xfer
+		trace_clr(T_SAVE)
+		bra #main_done
+
+	main_not_ctx_save:
+		shl b32 $r15 $r14 16
+		or $r15 E_BAD_COMMAND
+		call #error
+		bra #main
+
+	main_done:
+	clear b32 $r2
+	bset $r2 31
+	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r2)
+	bra #main
+
+// interrupt handler
+ih:
+	push $r8
+	mov $r8 $flags
+	push $r8
+	push $r9
+	push $r10
+	push $r11
+	push $r13
+	push $r14
+	push $r15
+	clear b32 $r0
+
+	// incoming fifo command?
+	iord $r10 I[$r0 + 0x200]	// INTR
+	and $r11 $r10 0x00000004
+	bra e #ih_no_fifo
+		// queue incoming fifo command for later processing
+		mov $r11 0x1900
+		mov $r13 #cmd_queue
+		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
+		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
+		call #queue_put
+		add b32 $r11 0x400
+		mov $r14 1
+		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
+
+	// context switch request?
+	ih_no_fifo:
+	and $r11 $r10 0x00000100
+	bra e #ih_no_ctxsw
+		// enqueue a context switch for later processing
+		mov $r13 #cmd_queue
+		mov $r14 0x4001
+		call #queue_put
+
+	// anything we didn't handle, bring it to the host's attention
+	ih_no_ctxsw:
+	mov $r11 0x104
+	not b32 $r11
+	and $r11 $r10 $r11
+	bra e #ih_no_other
+		mov $r10 0xc1c
+		shl b32 $r10 6
+		iowr I[$r10] $r11	// INTR_UP_SET
+
+	// ack, and wake up main()
+	ih_no_other:
+	iowr I[$r0 + 0x100] $r10	// INTR_ACK
+
+	pop $r15
+	pop $r14
+	pop $r13
+	pop $r11
+	pop $r10
+	pop $r9
+	pop $r8
+	mov $flags $r8
+	pop $r8
+	bclr $flags $p0
+	iret
+
+#if CHIPSET < GK100
+// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
+ctx_4160s:
+	mov $r14 0x4160
+	sethi $r14 0x400000
+	mov $r15 1
+	call #nv_wr32
+	ctx_4160s_wait:
+		call #nv_rd32
+		xbit $r15 $r15 4
+		bra e #ctx_4160s_wait
+	ret
+
+// Without clearing again at end of xfer, some things cause PGRAPH
+// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
+// still function with it set however...
+ctx_4160c:
+	mov $r14 0x4160
+	sethi $r14 0x400000
+	clear b32 $r15
+	call #nv_wr32
+	ret
+#endif
+
+// Again, not real sure
+//
+// In: $r15 value to set 0x404170 to
+//
+ctx_4170s:
+	mov $r14 0x4170
+	sethi $r14 0x400000
+	or $r15 0x10
+	call #nv_wr32
+	ret
+
+// Waits for a ctx_4170s() call to complete
+//
+ctx_4170w:
+	mov $r14 0x4170
+	sethi $r14 0x400000
+	call #nv_rd32
+	and $r15 0x10
+	bra ne #ctx_4170w
+	ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off?  Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+	mov $r14 0x614
+	shl b32 $r14 6
+	mov $r15 0x270
+	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
+	mov $r15 8
+	ctx_redswitch_delay:
+		sub b32 $r15 1
+		bra ne #ctx_redswitch_delay
+	mov $r15 0x770
+	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
+	ret
+
+// Not a clue what this is for, except that unless the value is 0x10, the
+// strand context is saved (and presumably restored) incorrectly..
+//
+// In: $r15 value to set to (0x00/0x10 are used)
+//
+ctx_86c:
+	mov $r14 0x86c
+	shl b32 $r14 6
+	iowr I[$r14] $r15	// HUB(0x86c) = val
+	mov $r14 -0x75ec
+	sethi $r14 0x400000
+	call #nv_wr32		// ROP(0xa14) = val
+	mov $r14 -0x5794
+	sethi $r14 0x410000
+	call #nv_wr32		// GPC(0x86c) = val
+	ret
+
+// ctx_load - load's a channel's ctxctl data, and selects its vm
+//
+// In: $r2 channel address
+//
+ctx_load:
+	trace_set(T_CHAN)
+
+	// switch to channel, somewhat magic in parts..
+	mov $r10 12		// DONE_UNK12
+	call #wait_donez
+	mov $r1 0xa24
+	shl b32 $r1 6
+	iowr I[$r1 + 0x000] $r0	// 0x409a24
+	mov $r3 0xb00
+	shl b32 $r3 6
+	iowr I[$r3 + 0x100] $r2	// CHAN_NEXT
+	mov $r1 0xa0c
+	shl b32 $r1 6
+	mov $r4 7
+	iowr I[$r1 + 0x000] $r2 // MEM_CHAN
+	iowr I[$r1 + 0x100] $r4	// MEM_CMD
+	ctx_chan_wait_0:
+		iord $r4 I[$r1 + 0x100]
+		and $r4 0x1f
+		bra ne #ctx_chan_wait_0
+	iowr I[$r3 + 0x000] $r2	// CHAN_CUR
+
+	// load channel header, fetch PGRAPH context pointer
+	mov $xtargets $r0
+	bclr $r2 31
+	shl b32 $r2 4
+	add b32 $r2 2
+
+	trace_set(T_LCHAN)
+	mov $r1 0xa04
+	shl b32 $r1 6
+	iowr I[$r1 + 0x000] $r2		// MEM_BASE
+	mov $r1 0xa20
+	shl b32 $r1 6
+	mov $r2 0x0002
+	sethi $r2 0x80000000
+	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vram
+	mov $r1 0x10			// chan + 0x0210
+	mov $r2 #xfer_data
+	sethi $r2 0x00020000		// 16 bytes
+	xdld $r1 $r2
+	xdwait
+	trace_clr(T_LCHAN)
+
+	// update current context
+	ld b32 $r1 D[$r0 + #xfer_data + 4]
+	shl b32 $r1 24
+	ld b32 $r2 D[$r0 + #xfer_data + 0]
+	shr b32 $r2 8
+	or $r1 $r2
+	st b32 D[$r0 + #ctx_current] $r1
+
+	// set transfer base to start of context, and fetch context header
+	trace_set(T_LCTXH)
+	mov $r2 0xa04
+	shl b32 $r2 6
+	iowr I[$r2 + 0x000] $r1		// MEM_BASE
+	mov $r2 1
+	mov $r1 0xa20
+	shl b32 $r1 6
+	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vm
+	mov $r1 #chan_data
+	sethi $r1 0x00060000		// 256 bytes
+	xdld $r0 $r1
+	xdwait
+	trace_clr(T_LCTXH)
+
+	trace_clr(T_CHAN)
+	ret
+
+// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
+//            the active channel for ctxctl, but not actually transfer
+//            any context data.  intended for use only during initial
+//            context construction.
+//
+// In: $r2 channel address
+//
+ctx_chan:
+#if CHIPSET < GK100
+	call #ctx_4160s
+#endif
+	call #ctx_load
+	mov $r10 12			// DONE_UNK12
+	call #wait_donez
+	mov $r1 0xa10
+	shl b32 $r1 6
+	mov $r2 5
+	iowr I[$r1 + 0x000] $r2		// MEM_CMD = 5 (???)
+	ctx_chan_wait:
+		iord $r2 I[$r1 + 0x000]
+		or $r2 $r2
+		bra ne #ctx_chan_wait
+#if CHIPSET < GK100
+	call #ctx_4160c
+#endif
+	ret
+
+// Execute per-context state overrides list
+//
+// Only executed on the first load of a channel.  Might want to look into
+// removing this and having the host directly modify the channel's context
+// to change this state...  The nouveau DRM already builds this list as
+// it's definitely needed for NVIDIA's, so we may as well use it for now
+//
+// Input: $r1 mmio list length
+//
+ctx_mmio_exec:
+	// set transfer base to be the mmio list
+	ld b32 $r3 D[$r0 + #chan_mmio_address]
+	mov $r2 0xa04
+	shl b32 $r2 6
+	iowr I[$r2 + 0x000] $r3		// MEM_BASE
+
+	clear b32 $r3
+	ctx_mmio_loop:
+		// fetch next 256 bytes of mmio list if necessary
+		and $r4 $r3 0xff
+		bra ne #ctx_mmio_pull
+			mov $r5 #xfer_data
+			sethi $r5 0x00060000	// 256 bytes
+			xdld $r3 $r5
+			xdwait
+
+		// execute a single list entry
+		ctx_mmio_pull:
+		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
+		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
+		call #nv_wr32
+
+		// next!
+		add b32 $r3 8
+		sub b32 $r1 1
+		bra ne #ctx_mmio_loop
+
+	// set transfer base back to the current context
+	ctx_mmio_done:
+	ld b32 $r3 D[$r0 + #ctx_current]
+	iowr I[$r2 + 0x000] $r3		// MEM_BASE
+
+	// disable the mmio list now, we don't need/want to execute it again
+	st b32 D[$r0 + #chan_mmio_count] $r0
+	mov $r1 #chan_data
+	sethi $r1 0x00060000		// 256 bytes
+	xdst $r0 $r1
+	xdwait
+	ret
+
+// Transfer HUB context data between GPU and storage area
+//
+// In: $r2 channel address
+//     $p1 clear on save, set on load
+//     $p2 set if opposite direction done/will be done, so:
+//		on save it means: "a load will follow this save"
+//		on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+	// according to mwk, some kind of wait for idle
+	mov $r15 0xc00
+	shl b32 $r15 6
+	mov $r14 4
+	iowr I[$r15 + 0x200] $r14
+	ctx_xfer_idle:
+		iord $r14 I[$r15 + 0x000]
+		and $r14 0x2000
+		bra ne #ctx_xfer_idle
+
+	bra not $p1 #ctx_xfer_pre
+	bra $p2 #ctx_xfer_pre_load
+	ctx_xfer_pre:
+		mov $r15 0x10
+		call #ctx_86c
+#if CHIPSET < GK100
+		call #ctx_4160s
+#endif
+		bra not $p1 #ctx_xfer_exec
+
+	ctx_xfer_pre_load:
+		mov $r15 2
+		call #ctx_4170s
+		call #ctx_4170w
+		call #ctx_redswitch
+		clear b32 $r15
+		call #ctx_4170s
+		call #ctx_load
+
+	// fetch context pointer, and initiate xfer on all GPCs
+	ctx_xfer_exec:
+	ld b32 $r1 D[$r0 + #ctx_current]
+	mov $r2 0x414
+	shl b32 $r2 6
+	iowr I[$r2 + 0x000] $r0	// BAR_STATUS = reset
+	mov $r14 -0x5b00
+	sethi $r14 0x410000
+	mov b32 $r15 $r1
+	call #nv_wr32		// GPC_BCAST_WRCMD_DATA = ctx pointer
+	add b32 $r14 4
+	xbit $r15 $flags $p1
+	xbit $r2 $flags $p2
+	shl b32 $r2 1
+	or $r15 $r2
+	call #nv_wr32		// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
+
+	// strands
+	mov $r1 0x4afc
+	sethi $r1 0x20000
+	mov $r2 0xc
+	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
+	call #strand_wait
+	mov $r2 0x47fc
+	sethi $r2 0x20000
+	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
+	xbit $r2 $flags $p1
+	add b32 $r2 3
+	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
+
+	// mmio context
+	xbit $r10 $flags $p1	// direction
+	or $r10 6		// first, last
+	mov $r11 0		// base = 0
+	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
+	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
+	mov $r14 0		// not multi
+	call #mmctx_xfer
+
+	// wait for GPCs to all complete
+	mov $r10 8		// DONE_BAR
+	call #wait_doneo
+
+	// wait for strand xfer to complete
+	call #strand_wait
+
+	// post-op
+	bra $p1 #ctx_xfer_post
+		mov $r10 12		// DONE_UNK12
+		call #wait_donez
+		mov $r1 0xa10
+		shl b32 $r1 6
+		mov $r2 5
+		iowr I[$r1] $r2		// MEM_CMD
+		ctx_xfer_post_save_wait:
+			iord $r2 I[$r1]
+			or $r2 $r2
+			bra ne #ctx_xfer_post_save_wait
+
+	bra $p2 #ctx_xfer_done
+	ctx_xfer_post:
+		mov $r15 2
+		call #ctx_4170s
+		clear b32 $r15
+		call #ctx_86c
+		call #strand_post
+		call #ctx_4170w
+		clear b32 $r15
+		call #ctx_4170s
+
+		bra not $p1 #ctx_xfer_no_post_mmio
+		ld b32 $r1 D[$r0 + #chan_mmio_count]
+		or $r1 $r1
+		bra e #ctx_xfer_no_post_mmio
+			call #ctx_mmio_exec
+
+		ctx_xfer_no_post_mmio:
+#if CHIPSET < GK100
+		call #ctx_4160c
+#endif
+
+	ctx_xfer_done:
+	ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
index 7fbdebb..3ff52ba 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nvc0 PGRAPH/HUB
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -20,850 +19,22 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-/* To build:
- *    m4 hubnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o hubnvc0.fuc.h
- */
+#define CHIPSET GF100
+#include "macros.fuc"
 
 .section #nvc0_grhub_data
-include(`nvc0.fuc')
-gpc_count:		.b32 0
-rop_count:		.b32 0
-cmd_queue:		queue_init
-hub_mmio_list_head:	.b32 0
-hub_mmio_list_tail:	.b32 0
-
-ctx_current:		.b32 0
-
-chipsets:
-.b8  0xc0 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8  0xc1 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc1_hub_mmio_tail
-.b8  0xc3 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8  0xc4 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8  0xc8 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8  0xce 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8  0xcf 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8  0xd9 0 0 0
-.b16 #nvd9_hub_mmio_head
-.b16 #nvd9_hub_mmio_tail
-.b8  0xd7 0 0 0
-.b16 #nvd9_hub_mmio_head
-.b16 #nvd9_hub_mmio_tail
-.b8  0 0 0 0
-
-nvc0_hub_mmio_head:
-mmctx_data(0x17e91c, 2)
-mmctx_data(0x400204, 2)
-mmctx_data(0x404004, 11)
-mmctx_data(0x404044, 1)
-mmctx_data(0x404094, 14)
-mmctx_data(0x4040d0, 7)
-mmctx_data(0x4040f8, 1)
-mmctx_data(0x404130, 3)
-mmctx_data(0x404150, 3)
-mmctx_data(0x404164, 2)
-mmctx_data(0x404174, 3)
-mmctx_data(0x404200, 8)
-mmctx_data(0x404404, 14)
-mmctx_data(0x404460, 4)
-mmctx_data(0x404480, 1)
-mmctx_data(0x404498, 1)
-mmctx_data(0x404604, 4)
-mmctx_data(0x404618, 32)
-mmctx_data(0x404698, 21)
-mmctx_data(0x4046f0, 2)
-mmctx_data(0x404700, 22)
-mmctx_data(0x405800, 1)
-mmctx_data(0x405830, 3)
-mmctx_data(0x405854, 1)
-mmctx_data(0x405870, 4)
-mmctx_data(0x405a00, 2)
-mmctx_data(0x405a18, 1)
-mmctx_data(0x406020, 1)
-mmctx_data(0x406028, 4)
-mmctx_data(0x4064a8, 2)
-mmctx_data(0x4064b4, 2)
-mmctx_data(0x407804, 1)
-mmctx_data(0x40780c, 6)
-mmctx_data(0x4078bc, 1)
-mmctx_data(0x408000, 7)
-mmctx_data(0x408064, 1)
-mmctx_data(0x408800, 3)
-mmctx_data(0x408900, 4)
-mmctx_data(0x408980, 1)
-nvc0_hub_mmio_tail:
-mmctx_data(0x4064c0, 2)
-nvc1_hub_mmio_tail:
-
-nvd9_hub_mmio_head:
-mmctx_data(0x17e91c, 2)
-mmctx_data(0x400204, 2)
-mmctx_data(0x404004, 10)
-mmctx_data(0x404044, 1)
-mmctx_data(0x404094, 14)
-mmctx_data(0x4040d0, 7)
-mmctx_data(0x4040f8, 1)
-mmctx_data(0x404130, 3)
-mmctx_data(0x404150, 3)
-mmctx_data(0x404164, 2)
-mmctx_data(0x404178, 2)
-mmctx_data(0x404200, 8)
-mmctx_data(0x404404, 14)
-mmctx_data(0x404460, 4)
-mmctx_data(0x404480, 1)
-mmctx_data(0x404498, 1)
-mmctx_data(0x404604, 4)
-mmctx_data(0x404618, 32)
-mmctx_data(0x404698, 21)
-mmctx_data(0x4046f0, 2)
-mmctx_data(0x404700, 22)
-mmctx_data(0x405800, 1)
-mmctx_data(0x405830, 3)
-mmctx_data(0x405854, 1)
-mmctx_data(0x405870, 4)
-mmctx_data(0x405a00, 2)
-mmctx_data(0x405a18, 1)
-mmctx_data(0x406020, 1)
-mmctx_data(0x406028, 4)
-mmctx_data(0x4064a8, 2)
-mmctx_data(0x4064b4, 5)
-mmctx_data(0x407804, 1)
-mmctx_data(0x40780c, 6)
-mmctx_data(0x4078bc, 1)
-mmctx_data(0x408000, 7)
-mmctx_data(0x408064, 1)
-mmctx_data(0x408800, 3)
-mmctx_data(0x408900, 4)
-mmctx_data(0x408980, 1)
-nvd9_hub_mmio_tail:
-
-.align 256
-chan_data:
-chan_mmio_count:	.b32 0
-chan_mmio_address:	.b32 0
-
-.align 256
-xfer_data: 		.b32 0
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
 
 .section #nvc0_grhub_code
+#define INCLUDE_CODE
 bra #init
-define(`include_code')
-include(`nvc0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nvc0.fuc)
-//
-error:
-	push $r14
-	mov $r14 0x814
-	shl b32 $r14 6
-	iowr I[$r14 + 0x000] $r15	// CC_SCRATCH[5] = error code
-	mov $r14 0xc1c
-	shl b32 $r14 6
-	mov $r15 1
-	iowr I[$r14 + 0x000] $r15	// INTR_UP_SET
-	pop $r14
-	ret
-
-// HUB fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: total PGRAPH context size
-//
-init:
-	clear b32 $r0
-	mov $sp $r0
-	mov $xdbase $r0
-
-	// enable fifo access
-	mov $r1 0x1200
-	mov $r2 2
-	iowr I[$r1 + 0x000] $r2	// FIFO_ENABLE
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	mov $r1 0x400
-	iowr I[$r1 + 0x300] $r0	// INTR_DISPATCH
-
-	// route HUB_CHANNEL_SWITCH to fuc interrupt 8
-	mov $r3 0x404
-	shl b32 $r3 6
-	mov $r2 0x2003		// { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
-	iowr I[$r3 + 0x000] $r2
-
-	// not sure what these are, route them because NVIDIA does, and
-	// the IRQ handler will signal the host if we ever get one.. we
-	// may find out if/why we need to handle these if so..
-	//
-	mov $r2 0x2004
-	iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
-	mov $r2 0x200b
-	iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
-	mov $r2 0x200c
-	iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
-
-	// enable all INTR_UP interrupts
-	mov $r2 0xc24
-	shl b32 $r2 6
-	not b32 $r3 $r0
-	iowr I[$r2] $r3
-
-	// enable fifo, ctxsw, 9, 10, 15 interrupts
-	mov $r2 -0x78fc		// 0x8704
-	sethi $r2 0
-	iowr I[$r1 + 0x000] $r2	// INTR_EN_SET
-
-	// fifo level triggered, rest edge
-	sub b32 $r1 0x100
-	mov $r2 4
-	iowr I[$r1] $r2
-
-	// enable interrupts
-	bset $flags ie0
-
-	// fetch enabled GPC/ROP counts
-	mov $r14 -0x69fc	// 0x409604
-	sethi $r14 0x400000
-	call #nv_rd32
-	extr $r1 $r15 16:20
-	st b32 D[$r0 + #rop_count] $r1
-	and $r15 0x1f
-	st b32 D[$r0 + #gpc_count] $r15
-
-	// set BAR_REQMASK to GPC mask
-	mov $r1 1
-	shl b32 $r1 $r15
-	sub b32 $r1 1
-	mov $r2 0x40c
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r1
-	iowr I[$r2 + 0x100] $r1
-
-	// find context data for this chipset
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
-	mov $r15 #chipsets - 8
-	init_find_chipset:
-		add b32 $r15 8
-		ld b32 $r3 D[$r15 + 0x00]
-		cmpu b32 $r3 $r2
-		bra e #init_context
-		cmpu b32 $r3 0
-		bra ne #init_find_chipset
-		// unknown chipset
-		ret
-
-	// context size calculation, reserve first 256 bytes for use by fuc
-	init_context:
-	mov $r1 256
-
-	// calculate size of mmio context data
-	ld b16 $r14 D[$r15 + 4]
-	ld b16 $r15 D[$r15 + 6]
-	sethi $r14 0
-	st b32 D[$r0 + #hub_mmio_list_head] $r14
-	st b32 D[$r0 + #hub_mmio_list_tail] $r15
-	call #mmctx_size
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't (currently) ever change
-	mov $r3 0x700
-	shl b32 $r3 6
-	shr b32 $r4 $r1 8
-	iowr I[$r3 + 0x000] $r4		// MMCTX_SAVE_SWBASE
-	iowr I[$r3 + 0x100] $r4		// MMCTX_LOAD_SWBASE
-	add b32 $r3 0x1300
-	add b32 $r1 $r15
-	shr b32 $r15 2
-	iowr I[$r3 + 0x000] $r15	// MMCTX_LOAD_COUNT, wtf for?!?
-
-	// strands, base offset needs to be aligned to 256 bytes
-	shr b32 $r1 8
-	add b32 $r1 1
-	shl b32 $r1 8
-	mov b32 $r15 $r1
-	call #strand_ctx_init
-	add b32 $r1 $r15
-
-	// initialise each GPC in sequence by passing in the offset of its
-	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
-	// has previously been uploaded by the host) running.
-	//
-	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
-	// when it has completed, and return the size of its context data
-	// in GPCn_CC_SCRATCH[1]
-	//
-	ld b32 $r3 D[$r0 + #gpc_count]
-	mov $r4 0x2000
-	sethi $r4 0x500000
-	init_gpc:
-		// setup, and start GPC ucode running
-		add b32 $r14 $r4 0x804
-		mov b32 $r15 $r1
-		call #nv_wr32			// CC_SCRATCH[1] = ctx offset
-		add b32 $r14 $r4 0x800
-		mov b32 $r15 $r2
-		call #nv_wr32			// CC_SCRATCH[0] = chipset
-		add b32 $r14 $r4 0x10c
-		clear b32 $r15
-		call #nv_wr32
-		add b32 $r14 $r4 0x104
-		call #nv_wr32			// ENTRY
-		add b32 $r14 $r4 0x100
-		mov $r15 2			// CTRL_START_TRIGGER
-		call #nv_wr32			// CTRL
-
-		// wait for it to complete, and adjust context size
-		add b32 $r14 $r4 0x800
-		init_gpc_wait:
-			call #nv_rd32
-			xbit $r15 $r15 31
-			bra e #init_gpc_wait
-		add b32 $r14 $r4 0x804
-		call #nv_rd32
-		add b32 $r1 $r15
-
-		// next!
-		add b32 $r4 0x8000
-		sub b32 $r3 1
-		bra ne #init_gpc
-
-	// save context size, and tell host we're ready
-	mov $r2 0x800
-	shl b32 $r2 6
-	iowr I[$r2 + 0x100] $r1		// CC_SCRATCH[1]  = context size
-	add b32 $r2 0x800
-	clear b32 $r1
-	bset $r1 31
-	iowr I[$r2 + 0x000] $r1		// CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	// sleep until we have something to do
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call #queue_get
-	bra $p1 #main
-
-	// context switch, requested by GPU?
-	cmpu b32 $r14 0x4001
-	bra ne #main_not_ctx_switch
-		trace_set(T_AUTO)
-		mov $r1 0xb00
-		shl b32 $r1 6
-		iord $r2 I[$r1 + 0x100]		// CHAN_NEXT
-		iord $r1 I[$r1 + 0x000]		// CHAN_CUR
-
-		xbit $r3 $r1 31
-		bra e #chsw_no_prev
-			xbit $r3 $r2 31
-			bra e #chsw_prev_no_next
-				push $r2
-				mov b32 $r2 $r1
-				trace_set(T_SAVE)
-				bclr $flags $p1
-				bset $flags $p2
-				call #ctx_xfer
-				trace_clr(T_SAVE);
-				pop $r2
-				trace_set(T_LOAD);
-				bset $flags $p1
-				call #ctx_xfer
-				trace_clr(T_LOAD);
-				bra #chsw_done
-			chsw_prev_no_next:
-				push $r2
-				mov b32 $r2 $r1
-				bclr $flags $p1
-				bclr $flags $p2
-				call #ctx_xfer
-				pop $r2
-				mov $r1 0xb00
-				shl b32 $r1 6
-				iowr I[$r1] $r2
-				bra #chsw_done
-		chsw_no_prev:
-			xbit $r3 $r2 31
-			bra e #chsw_done
-				bset $flags $p1
-				bclr $flags $p2
-				call #ctx_xfer
-
-		// ack the context switch request
-		chsw_done:
-		mov $r1 0xb0c
-		shl b32 $r1 6
-		mov $r2 1
-		iowr I[$r1 + 0x000] $r2		// 0x409b0c
-		trace_clr(T_AUTO)
-		bra #main
-
-	// request to set current channel? (*not* a context switch)
-	main_not_ctx_switch:
-	cmpu b32 $r14 0x0001
-	bra ne #main_not_ctx_chan
-		mov b32 $r2 $r15
-		call #ctx_chan
-		bra #main_done
-
-	// request to store current channel context?
-	main_not_ctx_chan:
-	cmpu b32 $r14 0x0002
-	bra ne #main_not_ctx_save
-		trace_set(T_SAVE)
-		bclr $flags $p1
-		bclr $flags $p2
-		call #ctx_xfer
-		trace_clr(T_SAVE)
-		bra #main_done
-
-	main_not_ctx_save:
-		shl b32 $r15 $r14 16
-		or $r15 E_BAD_COMMAND
-		call #error
-		bra #main
-
-	main_done:
-	mov $r1 0x820
-	shl b32 $r1 6
-	clear b32 $r2
-	bset $r2 31
-	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-
-	// incoming fifo command?
-	iord $r10 I[$r0 + 0x200]	// INTR
-	and $r11 $r10 0x00000004
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r11 0x1900
-		mov $r13 #cmd_queue
-		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
-		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
-		call #queue_put
-		add b32 $r11 0x400
-		mov $r14 1
-		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
-
-	// context switch request?
-	ih_no_fifo:
-	and $r11 $r10 0x00000100
-	bra e #ih_no_ctxsw
-		// enqueue a context switch for later processing
-		mov $r13 #cmd_queue
-		mov $r14 0x4001
-		call #queue_put
-
-	// anything we didn't handle, bring it to the host's attention
-	ih_no_ctxsw:
-	mov $r11 0x104
-	not b32 $r11
-	and $r11 $r10 $r11
-	bra e #ih_no_other
-		mov $r10 0xc1c
-		shl b32 $r10 6
-		iowr I[$r10] $r11	// INTR_UP_SET
-
-	// ack, and wake up main()
-	ih_no_other:
-	iowr I[$r0 + 0x100] $r10	// INTR_ACK
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
-ctx_4160s:
-	mov $r14 0x4160
-	sethi $r14 0x400000
-	mov $r15 1
-	call #nv_wr32
-	ctx_4160s_wait:
-		call #nv_rd32
-		xbit $r15 $r15 4
-		bra e #ctx_4160s_wait
-	ret
-
-// Without clearing again at end of xfer, some things cause PGRAPH
-// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
-// still function with it set however...
-ctx_4160c:
-	mov $r14 0x4160
-	sethi $r14 0x400000
-	clear b32 $r15
-	call #nv_wr32
-	ret
-
-// Again, not real sure
-//
-// In: $r15 value to set 0x404170 to
-//
-ctx_4170s:
-	mov $r14 0x4170
-	sethi $r14 0x400000
-	or $r15 0x10
-	call #nv_wr32
-	ret
-
-// Waits for a ctx_4170s() call to complete
-//
-ctx_4170w:
-	mov $r14 0x4170
-	sethi $r14 0x400000
-	call #nv_rd32
-	and $r15 0x10
-	bra ne #ctx_4170w
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 0x614
-	shl b32 $r14 6
-	mov $r15 0x270
-	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	mov $r15 0x770
-	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
-	ret
-
-// Not a clue what this is for, except that unless the value is 0x10, the
-// strand context is saved (and presumably restored) incorrectly..
-//
-// In: $r15 value to set to (0x00/0x10 are used)
-//
-ctx_86c:
-	mov $r14 0x86c
-	shl b32 $r14 6
-	iowr I[$r14] $r15	// HUB(0x86c) = val
-	mov $r14 -0x75ec
-	sethi $r14 0x400000
-	call #nv_wr32		// ROP(0xa14) = val
-	mov $r14 -0x5794
-	sethi $r14 0x410000
-	call #nv_wr32		// GPC(0x86c) = val
-	ret
-
-// ctx_load - load's a channel's ctxctl data, and selects its vm
-//
-// In: $r2 channel address
-//
-ctx_load:
-	trace_set(T_CHAN)
-
-	// switch to channel, somewhat magic in parts..
-	mov $r10 12		// DONE_UNK12
-	call #wait_donez
-	mov $r1 0xa24
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r0	// 0x409a24
-	mov $r3 0xb00
-	shl b32 $r3 6
-	iowr I[$r3 + 0x100] $r2	// CHAN_NEXT
-	mov $r1 0xa0c
-	shl b32 $r1 6
-	mov $r4 7
-	iowr I[$r1 + 0x000] $r2 // MEM_CHAN
-	iowr I[$r1 + 0x100] $r4	// MEM_CMD
-	ctx_chan_wait_0:
-		iord $r4 I[$r1 + 0x100]
-		and $r4 0x1f
-		bra ne #ctx_chan_wait_0
-	iowr I[$r3 + 0x000] $r2	// CHAN_CUR
-
-	// load channel header, fetch PGRAPH context pointer
-	mov $xtargets $r0
-	bclr $r2 31
-	shl b32 $r2 4
-	add b32 $r2 2
-
-	trace_set(T_LCHAN)
-	mov $r1 0xa04
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r2		// MEM_BASE
-	mov $r1 0xa20
-	shl b32 $r1 6
-	mov $r2 0x0002
-	sethi $r2 0x80000000
-	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vram
-	mov $r1 0x10			// chan + 0x0210
-	mov $r2 #xfer_data
-	sethi $r2 0x00020000		// 16 bytes
-	xdld $r1 $r2
-	xdwait
-	trace_clr(T_LCHAN)
-
-	// update current context
-	ld b32 $r1 D[$r0 + #xfer_data + 4]
-	shl b32 $r1 24
-	ld b32 $r2 D[$r0 + #xfer_data + 0]
-	shr b32 $r2 8
-	or $r1 $r2
-	st b32 D[$r0 + #ctx_current] $r1
-
-	// set transfer base to start of context, and fetch context header
-	trace_set(T_LCTXH)
-	mov $r2 0xa04
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r1		// MEM_BASE
-	mov $r2 1
-	mov $r1 0xa20
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vm
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdld $r0 $r1
-	xdwait
-	trace_clr(T_LCTXH)
-
-	trace_clr(T_CHAN)
-	ret
-
-// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
-//            the active channel for ctxctl, but not actually transfer
-//            any context data.  intended for use only during initial
-//            context construction.
-//
-// In: $r2 channel address
-//
-ctx_chan:
-	call #ctx_4160s
-	call #ctx_load
-	mov $r10 12			// DONE_UNK12
-	call #wait_donez
-	mov $r1 0xa10
-	shl b32 $r1 6
-	mov $r2 5
-	iowr I[$r1 + 0x000] $r2		// MEM_CMD = 5 (???)
-	ctx_chan_wait:
-		iord $r2 I[$r1 + 0x000]
-		or $r2 $r2
-		bra ne #ctx_chan_wait
-	call #ctx_4160c
-	ret
-
-// Execute per-context state overrides list
-//
-// Only executed on the first load of a channel.  Might want to look into
-// removing this and having the host directly modify the channel's context
-// to change this state...  The nouveau DRM already builds this list as
-// it's definitely needed for NVIDIA's, so we may as well use it for now
-//
-// Input: $r1 mmio list length
-//
-ctx_mmio_exec:
-	// set transfer base to be the mmio list
-	ld b32 $r3 D[$r0 + #chan_mmio_address]
-	mov $r2 0xa04
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r3		// MEM_BASE
-
-	clear b32 $r3
-	ctx_mmio_loop:
-		// fetch next 256 bytes of mmio list if necessary
-		and $r4 $r3 0xff
-		bra ne #ctx_mmio_pull
-			mov $r5 #xfer_data
-			sethi $r5 0x00060000	// 256 bytes
-			xdld $r3 $r5
-			xdwait
-
-		// execute a single list entry
-		ctx_mmio_pull:
-		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
-		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
-		call #nv_wr32
-
-		// next!
-		add b32 $r3 8
-		sub b32 $r1 1
-		bra ne #ctx_mmio_loop
-
-	// set transfer base back to the current context
-	ctx_mmio_done:
-	ld b32 $r3 D[$r0 + #ctx_current]
-	iowr I[$r2 + 0x000] $r3		// MEM_BASE
-
-	// disable the mmio list now, we don't need/want to execute it again
-	st b32 D[$r0 + #chan_mmio_count] $r0
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdst $r0 $r1
-	xdwait
-	ret
-
-// Transfer HUB context data between GPU and storage area
-//
-// In: $r2 channel address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// according to mwk, some kind of wait for idle
-	mov $r15 0xc00
-	shl b32 $r15 6
-	mov $r14 4
-	iowr I[$r15 + 0x200] $r14
-	ctx_xfer_idle:
-		iord $r14 I[$r15 + 0x000]
-		and $r14 0x2000
-		bra ne #ctx_xfer_idle
-
-	bra not $p1 #ctx_xfer_pre
-	bra $p2 #ctx_xfer_pre_load
-	ctx_xfer_pre:
-		mov $r15 0x10
-		call #ctx_86c
-		call #ctx_4160s
-		bra not $p1 #ctx_xfer_exec
-
-	ctx_xfer_pre_load:
-		mov $r15 2
-		call #ctx_4170s
-		call #ctx_4170w
-		call #ctx_redswitch
-		clear b32 $r15
-		call #ctx_4170s
-		call #ctx_load
-
-	// fetch context pointer, and initiate xfer on all GPCs
-	ctx_xfer_exec:
-	ld b32 $r1 D[$r0 + #ctx_current]
-	mov $r2 0x414
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r0	// BAR_STATUS = reset
-	mov $r14 -0x5b00
-	sethi $r14 0x410000
-	mov b32 $r15 $r1
-	call #nv_wr32		// GPC_BCAST_WRCMD_DATA = ctx pointer
-	add b32 $r14 4
-	xbit $r15 $flags $p1
-	xbit $r2 $flags $p2
-	shl b32 $r2 1
-	or $r15 $r2
-	call #nv_wr32		// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
-
-	// strands
-	mov $r1 0x4afc
-	sethi $r1 0x20000
-	mov $r2 0xc
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
-	call #strand_wait
-	mov $r2 0x47fc
-	sethi $r2 0x20000
-	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
-	xbit $r2 $flags $p1
-	add b32 $r2 3
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 6		// first, last
-	mov $r11 0		// base = 0
-	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
-	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
-	mov $r14 0		// not multi
-	call #mmctx_xfer
-
-	// wait for GPCs to all complete
-	mov $r10 8		// DONE_BAR
-	call #wait_doneo
-
-	// wait for strand xfer to complete
-	call #strand_wait
-
-	// post-op
-	bra $p1 #ctx_xfer_post
-		mov $r10 12		// DONE_UNK12
-		call #wait_donez
-		mov $r1 0xa10
-		shl b32 $r1 6
-		mov $r2 5
-		iowr I[$r1] $r2		// MEM_CMD
-		ctx_xfer_post_save_wait:
-			iord $r2 I[$r1]
-			or $r2 $r2
-			bra ne #ctx_xfer_post_save_wait
-
-	bra $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r15 2
-		call #ctx_4170s
-		clear b32 $r15
-		call #ctx_86c
-		call #strand_post
-		call #ctx_4170w
-		clear b32 $r15
-		call #ctx_4170s
-
-		bra not $p1 #ctx_xfer_no_post_mmio
-		ld b32 $r1 D[$r0 + #chan_mmio_count]
-		or $r1 $r1
-		bra e #ctx_xfer_no_post_mmio
-			call #ctx_mmio_exec
-
-		ctx_xfer_no_post_mmio:
-		call #ctx_4160c
-
-	ctx_xfer_done:
-	ret
-
+#include "com.fuc"
+#include "hub.fuc"
 .align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
index bb03d2a..b59f694 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
@@ -1,9 +1,13 @@
 uint32_t nvc0_grhub_data[] = {
-/* 0x0000: gpc_count */
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
 	0x00000000,
-/* 0x0004: rop_count */
+/* 0x000c: rop_count */
 	0x00000000,
-/* 0x0008: cmd_queue */
+/* 0x0010: cmd_queue */
 	0x00000000,
 	0x00000000,
 	0x00000000,
@@ -22,203 +26,194 @@
 	0x00000000,
 	0x00000000,
 	0x00000000,
-/* 0x0050: hub_mmio_list_head */
-	0x00000000,
-/* 0x0054: hub_mmio_list_tail */
-	0x00000000,
 /* 0x0058: ctx_current */
 	0x00000000,
-/* 0x005c: chipsets */
-	0x000000c0,
-	0x013c00a0,
-	0x000000c1,
-	0x014000a0,
-	0x000000c3,
-	0x013c00a0,
-	0x000000c4,
-	0x013c00a0,
-	0x000000c8,
-	0x013c00a0,
-	0x000000ce,
-	0x013c00a0,
-	0x000000cf,
-	0x013c00a0,
-	0x000000d9,
-	0x01dc0140,
 	0x00000000,
-/* 0x00a0: nvc0_hub_mmio_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
 	0x0417e91c,
-	0x04400204,
-	0x28404004,
-	0x00404044,
-	0x34404094,
-	0x184040d0,
-	0x004040f8,
-	0x08404130,
-	0x08404150,
-	0x04404164,
-	0x08404174,
-	0x1c404200,
-	0x34404404,
-	0x0c404460,
-	0x00404480,
-	0x00404498,
-	0x0c404604,
-	0x7c404618,
-	0x50404698,
-	0x044046f0,
-	0x54404700,
-	0x00405800,
-	0x08405830,
-	0x00405854,
-	0x0c405870,
-	0x04405a00,
-	0x00405a18,
-	0x00406020,
-	0x0c406028,
-	0x044064a8,
-	0x044064b4,
-	0x00407804,
-	0x1440780c,
-	0x004078bc,
-	0x18408000,
-	0x00408064,
-	0x08408800,
-	0x0c408900,
-	0x00408980,
-/* 0x013c: nvc0_hub_mmio_tail */
-	0x044064c0,
-/* 0x0140: nvc1_hub_mmio_tail */
-/* 0x0140: nvd9_hub_mmio_head */
-	0x0417e91c,
-	0x04400204,
-	0x24404004,
-	0x00404044,
-	0x34404094,
-	0x184040d0,
-	0x004040f8,
-	0x08404130,
-	0x08404150,
-	0x04404164,
-	0x04404178,
-	0x1c404200,
-	0x34404404,
-	0x0c404460,
-	0x00404480,
-	0x00404498,
-	0x0c404604,
-	0x7c404618,
-	0x50404698,
-	0x044046f0,
-	0x54404700,
-	0x00405800,
-	0x08405830,
-	0x00405854,
-	0x0c405870,
-	0x04405a00,
-	0x00405a18,
-	0x00406020,
-	0x0c406028,
-	0x044064a8,
-	0x104064b4,
-	0x00407804,
-	0x1440780c,
-	0x004078bc,
-	0x18408000,
-	0x00408064,
-	0x08408800,
-	0x0c408900,
-	0x00408980,
-/* 0x01dc: nvd9_hub_mmio_tail */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0200: chan_data */
-/* 0x0200: chan_mmio_count */
-	0x00000000,
-/* 0x0204: chan_mmio_address */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0300: xfer_data */
-	0x00000000,
 };
 
 uint32_t nvc0_grhub_code[] = {
-	0x03090ef5,
+	0x031b0ef5,
 /* 0x0004: queue_put */
 	0x9800d898,
 	0x86f001d9,
 	0x0489b808,
 	0xf00c1bf4,
 	0x21f502f7,
-	0x00f802ec,
+	0x00f802fe,
 /* 0x001c: queue_put_next */
 	0xb60798c4,
 	0x8dbb0384,
@@ -250,7 +245,7 @@
 	0xc800bccf,
 	0x1bf41fcc,
 	0x06a7f0fa,
-	0x010321f5,
+	0x010921f5,
 	0xf840bfcf,
 /* 0x008d: nv_wr32 */
 	0x28b7f100,
@@ -272,63 +267,66 @@
 	0x0684b604,
 	0xf80080d0,
 /* 0x00c9: wait_donez */
-	0x3c87f100,
-	0x0684b608,
-	0x99f094bd,
-	0x0089d000,
-	0x081887f1,
-	0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
-	0x87f1008a,
-	0x84b60400,
-	0x0088cf06,
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x07f104bd,
+	0x03f00600,
+	0x000ad002,
+/* 0x00e6: wait_donez_ne */
+	0x87f104bd,
+	0x83f00000,
+	0x0088cf01,
 	0xf4888aff,
-	0x87f1f31b,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00099,
-/* 0x0103: wait_doneo */
-	0xf100f800,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00099f0,
-	0x87f10089,
+	0x94bdf31b,
+	0xf10099f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0109: wait_doneo */
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x87f104bd,
 	0x84b60818,
 	0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x0124: wait_doneo_e */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
 	0xf30bf488,
-	0x085c87f1,
-	0xbd0684b6,
-	0x0099f094,
-	0xf80089d0,
-/* 0x013d: mmctx_size */
-/* 0x013f: nv_mmctx_size_loop */
-	0x9894bd00,
-	0x85b600e8,
-	0x0180b61a,
-	0xbb0284b6,
-	0xe0b60098,
-	0x04efb804,
-	0xb9eb1bf4,
-	0x00f8029f,
-/* 0x015c: mmctx_xfer */
-	0x083c87f1,
-	0xbd0684b6,
-	0x0199f094,
-	0xf10089d0,
+	0x99f094bd,
+	0x0007f100,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x0147: mmctx_size */
+	0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+	0x00e89894,
+	0xb61a85b6,
+	0x84b60180,
+	0x0098bb02,
+	0xb804e0b6,
+	0x1bf404ef,
+	0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+	0x94bd00f8,
+	0xf10199f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
 	0xb6071087,
 	0x94bd0684,
 	0xf405bbfd,
 	0x8bd0090b,
 	0x0099f000,
-/* 0x0180: mmctx_base_disabled */
+/* 0x018c: mmctx_base_disabled */
 	0xf405eefd,
 	0x8ed00c0b,
 	0xc08fd080,
-/* 0x018f: mmctx_multi_disabled */
+/* 0x019b: mmctx_multi_disabled */
 	0xb70199f0,
 	0xc8010080,
 	0xb4b600ab,
@@ -336,8 +334,8 @@
 	0xb601aec8,
 	0xbefd11e4,
 	0x008bd005,
-/* 0x01a8: mmctx_exec_loop */
-/* 0x01a8: mmctx_wait_free */
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
 	0xf0008ecf,
 	0x0bf41fe4,
 	0x00ce98fa,
@@ -346,76 +344,77 @@
 	0x04cdb804,
 	0xc8e81bf4,
 	0x1bf402ab,
-/* 0x01c9: mmctx_fini_wait */
+/* 0x01d5: mmctx_fini_wait */
 	0x008bcf18,
 	0xb01fb4f0,
 	0x1bf410b4,
 	0x02a7f0f7,
 	0xf4c921f4,
-/* 0x01de: mmctx_stop */
+/* 0x01ea: mmctx_stop */
 	0xabc81b0e,
 	0x10b4b600,
 	0xf00cb9f0,
 	0x8bd012b9,
-/* 0x01ed: mmctx_stop_wait */
+/* 0x01f9: mmctx_stop_wait */
 	0x008bcf00,
 	0xf412bbc8,
-/* 0x01f6: mmctx_done */
-	0x87f1fa1b,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00199,
-/* 0x0207: strand_wait */
-	0xf900f800,
-	0x02a7f0a0,
-	0xfcc921f4,
-/* 0x0213: strand_pre */
-	0xf100f8a0,
-	0xf04afc87,
-	0x97f00283,
-	0x0089d00c,
-	0x020721f5,
-/* 0x0226: strand_post */
-	0x87f100f8,
-	0x83f04afc,
-	0x0d97f002,
-	0xf50089d0,
-	0xf8020721,
-/* 0x0239: strand_set */
-	0xfca7f100,
-	0x02a3f04f,
-	0x0500aba2,
-	0xd00fc7f0,
-	0xc7f000ac,
-	0x00bcd00b,
-	0x020721f5,
-	0xf000aed0,
-	0xbcd00ac7,
-	0x0721f500,
-/* 0x0263: strand_ctx_init */
-	0xf100f802,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00399f0,
+/* 0x0202: mmctx_done */
+	0x94bdfa1b,
+	0xf10199f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0215: strand_wait */
+	0xf0a0f900,
+	0x21f402a7,
+	0xf8a0fcc9,
+/* 0x0221: strand_pre */
+	0xfc87f100,
+	0x0283f04a,
+	0xd00c97f0,
 	0x21f50089,
-	0xe7f00213,
-	0x3921f503,
+	0x00f80215,
+/* 0x0234: strand_post */
+	0x4afc87f1,
+	0xf00283f0,
+	0x89d00d97,
+	0x1521f500,
+/* 0x0247: strand_set */
+	0xf100f802,
+	0xf04ffca7,
+	0xaba202a3,
+	0xc7f00500,
+	0x00acd00f,
+	0xd00bc7f0,
+	0x21f500bc,
+	0xaed00215,
+	0x0ac7f000,
+	0xf500bcd0,
+	0xf8021521,
+/* 0x0271: strand_ctx_init */
+	0xf094bd00,
+	0x07f10399,
+	0x03f00f00,
+	0x0009d002,
+	0x21f504bd,
+	0xe7f00221,
+	0x4721f503,
 	0xfca7f102,
 	0x02a3f046,
 	0x0400aba0,
 	0xf040a0d0,
 	0xbcd001c7,
-	0x0721f500,
+	0x1521f500,
 	0x010c9202,
 	0xf000acd0,
 	0xbcd002c7,
-	0x0721f500,
-	0x2621f502,
+	0x1521f500,
+	0x3421f502,
 	0x8087f102,
 	0x0684b608,
 	0xb70089cf,
 	0x95220080,
-/* 0x02ba: ctx_init_strand_loop */
+/* 0x02ca: ctx_init_strand_loop */
 	0x8ed008fe,
 	0x408ed000,
 	0xb6808acf,
@@ -424,73 +423,61 @@
 	0xb60480b6,
 	0x1bf40192,
 	0x08e4b6e8,
-	0xf1f2efbc,
-	0xb6085c87,
-	0x94bd0684,
-	0xd00399f0,
-	0x00f80089,
-/* 0x02ec: error */
-	0xe7f1e0f9,
-	0xe4b60814,
-	0x00efd006,
-	0x0c1ce7f1,
-	0xf006e4b6,
-	0xefd001f7,
-	0xf8e0fc00,
-/* 0x0309: init */
-	0xfe04bd00,
-	0x07fe0004,
-	0x0017f100,
-	0x0227f012,
-	0xf10012d0,
-	0xfe05b917,
-	0x17f10010,
-	0x10d00400,
-	0x0437f1c0,
-	0x0634b604,
-	0x200327f1,
-	0xf10032d0,
-	0xd0200427,
-	0x27f10132,
-	0x32d0200b,
-	0x0c27f102,
-	0x0732d020,
-	0x0c2427f1,
-	0xb90624b6,
-	0x23d00003,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x02fe: error */
+	0x07f100f8,
+	0x03f00500,
+	0x000fd002,
+	0xf7f004bd,
+	0x0007f101,
+	0x0303f007,
+	0xbd000fd0,
+/* 0x031b: init */
+	0xbd00f804,
+	0x0004fe04,
+	0xf10007fe,
+	0xf0120017,
+	0x12d00227,
+	0xb117f100,
+	0x0010fe05,
+	0x040017f1,
+	0xf1c010d0,
+	0xb6040437,
+	0x27f10634,
+	0x32d02003,
 	0x0427f100,
-	0x0023f087,
-	0xb70012d0,
-	0xf0010012,
-	0x12d00427,
-	0x1031f400,
-	0x9604e7f1,
-	0xf440e3f0,
-	0xf1c76821,
-	0x01018090,
-	0x801ff4f0,
-	0x17f0000f,
-	0x041fbb01,
-	0xf10112b6,
-	0xb6040c27,
-	0x21d00624,
-	0x4021d000,
-	0x080027f1,
-	0xcf0624b6,
-	0xf7f00022,
-/* 0x03a9: init_find_chipset */
-	0x08f0b654,
-	0xb800f398,
-	0x0bf40432,
-	0x0034b00b,
-	0xf8f11bf4,
-/* 0x03bd: init_context */
-	0x0017f100,
-	0x02fe5801,
-	0xf003ff58,
-	0x0e8000e3,
-	0x150f8014,
-	0x013d21f5,
+	0x0132d020,
+	0x200b27f1,
+	0xf10232d0,
+	0xd0200c27,
+	0x27f10732,
+	0x24b60c24,
+	0x0003b906,
+	0xf10023d0,
+	0xf0870427,
+	0x12d00023,
+	0x0012b700,
+	0x0427f001,
+	0xf40012d0,
+	0xe7f11031,
+	0xe3f09604,
+	0x6821f440,
+	0x8090f1c7,
+	0xf4f00301,
+	0x020f801f,
+	0xbb0117f0,
+	0x12b6041f,
+	0x0c27f101,
+	0x0624b604,
+	0xd00021d0,
+	0x17f14021,
+	0x0e980100,
+	0x010f9800,
+	0x014721f5,
 	0x070037f1,
 	0x950634b6,
 	0x34d00814,
@@ -501,208 +488,213 @@
 	0x0815b600,
 	0xb60110b6,
 	0x1fb90814,
-	0x6321f502,
+	0x7121f502,
 	0x001fbb02,
-	0xf1000398,
+	0xf1020398,
 	0xf0200047,
-/* 0x040e: init_gpc */
+/* 0x03f6: init_gpc */
 	0x4ea05043,
 	0x1fb90804,
 	0x8d21f402,
-	0x08004ea0,
-	0xf4022fb9,
+	0x010c4ea0,
+	0x21f4f4bd,
+	0x044ea08d,
+	0x8d21f401,
+	0x01004ea0,
+	0xf402f7f0,
 	0x4ea08d21,
-	0xf4bd010c,
-	0xa08d21f4,
-	0xf401044e,
-	0x4ea08d21,
-	0xf7f00100,
-	0x8d21f402,
-	0x08004ea0,
-/* 0x0440: init_gpc_wait */
-	0xc86821f4,
-	0x0bf41fff,
-	0x044ea0fa,
-	0x6821f408,
-	0xb7001fbb,
-	0xb6800040,
-	0x1bf40132,
-	0x0027f1b4,
-	0x0624b608,
-	0xb74021d0,
-	0xbd080020,
+/* 0x041e: init_gpc_wait */
+	0x21f40800,
+	0x1fffc868,
+	0xa0fa0bf4,
+	0xf408044e,
+	0x1fbb6821,
+	0x0040b700,
+	0x0132b680,
+	0xf1be1bf4,
+	0xf0010007,
+	0x01d00203,
+	0xbd04bd00,
 	0x1f19f014,
-/* 0x0473: main */
-	0xf40021d0,
-	0x28f40031,
-	0x08d7f000,
-	0xf43921f4,
-	0xe4b1f401,
-	0x1bf54001,
-	0x87f100d1,
-	0x84b6083c,
-	0xf094bd06,
-	0x89d00499,
-	0x0017f100,
-	0x0614b60b,
-	0xcf4012cf,
-	0x13c80011,
-	0x7e0bf41f,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0001,
+/* 0x0458: main */
+	0xf40031f4,
+	0xd7f00028,
+	0x3921f410,
+	0xb1f401f4,
+	0xf54001e4,
+	0xbd00de1b,
+	0x0499f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x0b0017f1,
+	0xcf0614b6,
+	0x11cf4012,
+	0x1f13c800,
+	0x00870bf5,
 	0xf41f23c8,
-	0x20f95a0b,
-	0xf10212b9,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00799f0,
-	0x32f40089,
-	0x0231f401,
-	0x082921f5,
-	0x085c87f1,
-	0xbd0684b6,
+	0x20f9620b,
+	0xbd0212b9,
 	0x0799f094,
-	0xfc0089d0,
-	0x3c87f120,
-	0x0684b608,
-	0x99f094bd,
-	0x0089d006,
-	0xf50131f4,
-	0xf1082921,
-	0xb6085c87,
-	0x94bd0684,
-	0xd00699f0,
-	0x0ef40089,
-/* 0x0509: chsw_prev_no_next */
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xf40132f4,
+	0x21f50231,
+	0x94bd082f,
+	0xf10799f0,
+	0xf0170007,
+	0x09d00203,
+	0xfc04bd00,
+	0xf094bd20,
+	0x07f10699,
+	0x03f00f00,
+	0x0009d002,
+	0x31f404bd,
+	0x2f21f501,
+	0xf094bd08,
+	0x07f10699,
+	0x03f01700,
+	0x0009d002,
+	0x0ef404bd,
+/* 0x04f9: chsw_prev_no_next */
 	0xb920f931,
 	0x32f40212,
 	0x0232f401,
-	0x082921f5,
+	0x082f21f5,
 	0x17f120fc,
 	0x14b60b00,
 	0x0012d006,
-/* 0x0527: chsw_no_prev */
+/* 0x0517: chsw_no_prev */
 	0xc8130ef4,
 	0x0bf41f23,
 	0x0131f40d,
 	0xf50232f4,
-/* 0x0537: chsw_done */
-	0xf1082921,
+/* 0x0527: chsw_done */
+	0xf1082f21,
 	0xb60b0c17,
 	0x27f00614,
 	0x0012d001,
-	0x085c87f1,
-	0xbd0684b6,
-	0x0499f094,
-	0xf50089d0,
-/* 0x0557: main_not_ctx_switch */
-	0xb0ff200e,
-	0x1bf401e4,
-	0x02f2b90d,
-	0x07b521f5,
-/* 0x0567: main_not_ctx_chan */
-	0xb0420ef4,
-	0x1bf402e4,
-	0x3c87f12e,
-	0x0684b608,
 	0x99f094bd,
-	0x0089d007,
+	0x0007f104,
+	0x0203f017,
+	0xbd0009d0,
+	0x130ef504,
+/* 0x0549: main_not_ctx_switch */
+	0x01e4b0ff,
+	0xb90d1bf4,
+	0x21f502f2,
+	0x0ef407bb,
+/* 0x0559: main_not_ctx_chan */
+	0x02e4b046,
+	0xbd321bf4,
+	0x0799f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
 	0xf40132f4,
 	0x21f50232,
-	0x87f10829,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00799,
-	0x110ef400,
-/* 0x0598: main_not_ctx_save */
-	0xf010ef94,
-	0x21f501f5,
-	0x0ef502ec,
-/* 0x05a6: main_done */
-	0x17f1fed1,
-	0x14b60820,
-	0xf024bd06,
-	0x12d01f29,
-	0xbe0ef500,
-/* 0x05b9: ih */
+	0x94bd082f,
+	0xf10799f0,
+	0xf0170007,
+	0x09d00203,
+	0xf404bd00,
+/* 0x058e: main_not_ctx_save */
+	0xef94110e,
+	0x01f5f010,
+	0x02fe21f5,
+	0xfec00ef5,
+/* 0x059c: main_done */
+	0x29f024bd,
+	0x0007f11f,
+	0x0203f008,
+	0xbd0002d0,
+	0xab0ef504,
+/* 0x05b1: ih */
 	0xfe80f9fe,
 	0x80f90188,
 	0xa0f990f9,
 	0xd0f9b0f9,
 	0xf0f9e0f9,
-	0xc4800acf,
-	0x0bf404ab,
-	0x00b7f11d,
-	0x08d7f019,
-	0xcf40becf,
-	0x21f400bf,
-	0x00b0b704,
-	0x01e7f004,
-/* 0x05ef: ih_no_fifo */
-	0xe400bed0,
-	0xf40100ab,
-	0xd7f00d0b,
-	0x01e7f108,
-	0x0421f440,
-/* 0x0600: ih_no_ctxsw */
-	0x0104b7f1,
-	0xabffb0bd,
-	0x0d0bf4b4,
-	0x0c1ca7f1,
-	0xd006a4b6,
-/* 0x0616: ih_no_other */
-	0x0ad000ab,
-	0xfcf0fc40,
-	0xfcd0fce0,
-	0xfca0fcb0,
-	0xfe80fc90,
-	0x80fc0088,
-	0xf80032f4,
-/* 0x0631: ctx_4160s */
-	0x60e7f101,
+	0x0acf04bd,
+	0x04abc480,
+	0xf11d0bf4,
+	0xf01900b7,
+	0xbecf10d7,
+	0x00bfcf40,
+	0xb70421f4,
+	0xf00400b0,
+	0xbed001e7,
+/* 0x05e9: ih_no_fifo */
+	0x00abe400,
+	0x0d0bf401,
+	0xf110d7f0,
+	0xf44001e7,
+/* 0x05fa: ih_no_ctxsw */
+	0xb7f10421,
+	0xb0bd0104,
+	0xf4b4abff,
+	0xa7f10d0b,
+	0xa4b60c1c,
+	0x00abd006,
+/* 0x0610: ih_no_other */
+	0xfc400ad0,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x062b: ctx_4160s */
+	0xf101f800,
+	0xf04160e7,
+	0xf7f040e3,
+	0x8d21f401,
+/* 0x0638: ctx_4160s_wait */
+	0xc86821f4,
+	0x0bf404ff,
+/* 0x0643: ctx_4160c */
+	0xf100f8fa,
+	0xf04160e7,
+	0xf4bd40e3,
+	0xf88d21f4,
+/* 0x0651: ctx_4170s */
+	0x70e7f100,
 	0x40e3f041,
-	0xf401f7f0,
-/* 0x063e: ctx_4160s_wait */
-	0x21f48d21,
-	0x04ffc868,
-	0xf8fa0bf4,
-/* 0x0649: ctx_4160c */
-	0x60e7f100,
-	0x40e3f041,
-	0x21f4f4bd,
-/* 0x0657: ctx_4170s */
-	0xf100f88d,
-	0xf04170e7,
-	0xf5f040e3,
-	0x8d21f410,
-/* 0x0666: ctx_4170w */
-	0xe7f100f8,
-	0xe3f04170,
-	0x6821f440,
-	0xf410f4f0,
-	0x00f8f31b,
-/* 0x0678: ctx_redswitch */
-	0x0614e7f1,
-	0xf106e4b6,
-	0xd00270f7,
-	0xf7f000ef,
-/* 0x0689: ctx_redswitch_delay */
-	0x01f2b608,
-	0xf1fd1bf4,
-	0xd00770f7,
-	0x00f800ef,
-/* 0x0698: ctx_86c */
-	0x086ce7f1,
-	0xd006e4b6,
-	0xe7f100ef,
-	0xe3f08a14,
-	0x8d21f440,
-	0xa86ce7f1,
-	0xf441e3f0,
+	0xf410f5f0,
 	0x00f88d21,
-/* 0x06b8: ctx_load */
-	0x083c87f1,
-	0xbd0684b6,
-	0x0599f094,
-	0xf00089d0,
+/* 0x0660: ctx_4170w */
+	0x4170e7f1,
+	0xf440e3f0,
+	0xf4f06821,
+	0xf31bf410,
+/* 0x0672: ctx_redswitch */
+	0xe7f100f8,
+	0xe4b60614,
+	0x70f7f106,
+	0x00efd002,
+/* 0x0683: ctx_redswitch_delay */
+	0xb608f7f0,
+	0x1bf401f2,
+	0x70f7f1fd,
+	0x00efd007,
+/* 0x0692: ctx_86c */
+	0xe7f100f8,
+	0xe4b6086c,
+	0x00efd006,
+	0x8a14e7f1,
+	0xf440e3f0,
+	0xe7f18d21,
+	0xe3f0a86c,
+	0x8d21f441,
+/* 0x06b2: ctx_load */
+	0x94bd00f8,
+	0xf10599f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf004bd00,
 	0x21f40ca7,
 	0x2417f1c9,
 	0x0614b60a,
@@ -713,168 +705,169 @@
 	0x0614b60a,
 	0xd00747f0,
 	0x14d00012,
-/* 0x06f1: ctx_chan_wait_0 */
+/* 0x06ed: ctx_chan_wait_0 */
 	0x4014cf40,
 	0xf41f44f0,
 	0x32d0fa1b,
 	0x000bfe00,
 	0xb61f2af0,
 	0x20b60424,
-	0x3c87f102,
-	0x0684b608,
+	0xf094bd02,
+	0x07f10899,
+	0x03f00f00,
+	0x0009d002,
+	0x17f104bd,
+	0x14b60a04,
+	0x0012d006,
+	0x0a2017f1,
+	0xf00614b6,
+	0x23f10227,
+	0x12d08000,
+	0x1017f000,
+	0x020027f1,
+	0xfa0223f0,
+	0x03f80512,
 	0x99f094bd,
-	0x0089d008,
-	0x0a0417f1,
-	0xd00614b6,
-	0x17f10012,
-	0x14b60a20,
-	0x0227f006,
-	0x800023f1,
-	0xf00012d0,
-	0x27f11017,
-	0x23f00300,
-	0x0512fa02,
-	0x87f103f8,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00899,
-	0xc1019800,
+	0x0007f108,
+	0x0203f017,
+	0xbd0009d0,
+	0x81019804,
 	0x981814b6,
-	0x25b6c002,
+	0x25b68002,
 	0x0512fd08,
-	0xf1160180,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00999f0,
-	0x27f10089,
-	0x24b60a04,
-	0x0021d006,
-	0xf10127f0,
-	0xb60a2017,
-	0x12d00614,
-	0x0017f100,
-	0x0613f002,
-	0xf80501fa,
-	0x5c87f103,
-	0x0684b608,
-	0x99f094bd,
-	0x0089d009,
-	0x085c87f1,
-	0xbd0684b6,
-	0x0599f094,
-	0xf80089d0,
-/* 0x07b5: ctx_chan */
-	0x3121f500,
-	0xb821f506,
-	0x0ca7f006,
-	0xf1c921f4,
-	0xb60a1017,
-	0x27f00614,
-	0x0012d005,
-/* 0x07d0: ctx_chan_wait */
-	0xfd0012cf,
-	0x1bf40522,
-	0x4921f5fa,
-/* 0x07df: ctx_mmio_exec */
-	0x9800f806,
-	0x27f18103,
-	0x24b60a04,
-	0x0023d006,
-/* 0x07ee: ctx_mmio_loop */
-	0x34c434bd,
-	0x0f1bf4ff,
-	0x030057f1,
-	0xfa0653f0,
-	0x03f80535,
-/* 0x0800: ctx_mmio_pull */
-	0x98c04e98,
-	0x21f4c14f,
-	0x0830b68d,
-	0xf40112b6,
-/* 0x0812: ctx_mmio_done */
-	0x0398df1b,
-	0x0023d016,
-	0xf1800080,
-	0xf0020017,
-	0x01fa0613,
-	0xf803f806,
-/* 0x0829: ctx_xfer */
-	0x00f7f100,
-	0x06f4b60c,
-	0xd004e7f0,
-/* 0x0836: ctx_xfer_idle */
-	0xfecf80fe,
-	0x00e4f100,
-	0xf91bf420,
-	0xf40611f4,
-/* 0x0846: ctx_xfer_pre */
-	0xf7f01102,
-	0x9821f510,
-	0x3121f506,
-	0x1c11f406,
-/* 0x0854: ctx_xfer_pre_load */
-	0xf502f7f0,
-	0xf5065721,
-	0xf5066621,
-	0xbd067821,
-	0x5721f5f4,
-	0xb821f506,
-/* 0x086d: ctx_xfer_exec */
-	0x16019806,
-	0x041427f1,
+	0xbd160180,
+	0x0999f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x0a0427f1,
 	0xd00624b6,
-	0xe7f10020,
-	0xe3f0a500,
-	0x021fb941,
+	0x27f00021,
+	0x2017f101,
+	0x0614b60a,
+	0xf10012d0,
+	0xf0010017,
+	0x01fa0613,
+	0xbd03f805,
+	0x0999f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x99f094bd,
+	0x0007f105,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x07bb: ctx_chan */
+	0xf500f804,
+	0xf5062b21,
+	0xf006b221,
+	0x21f40ca7,
+	0x1017f1c9,
+	0x0614b60a,
+	0xd00527f0,
+/* 0x07d6: ctx_chan_wait */
+	0x12cf0012,
+	0x0522fd00,
+	0xf5fa1bf4,
+	0xf8064321,
+/* 0x07e5: ctx_mmio_exec */
+	0x41039800,
+	0x0a0427f1,
+	0xd00624b6,
+	0x34bd0023,
+/* 0x07f4: ctx_mmio_loop */
+	0xf4ff34c4,
+	0x57f10f1b,
+	0x53f00200,
+	0x0535fa06,
+/* 0x0806: ctx_mmio_pull */
+	0x4e9803f8,
+	0x814f9880,
 	0xb68d21f4,
-	0xfcf004e0,
-	0x022cf001,
-	0xfd0124b6,
-	0x21f405f2,
-	0xfc17f18d,
-	0x0213f04a,
-	0xd00c27f0,
-	0x21f50012,
-	0x27f10207,
-	0x23f047fc,
-	0x0020d002,
-	0xb6012cf0,
-	0x12d00320,
-	0x01acf000,
-	0xf006a5f0,
-	0x0c9800b7,
-	0x150d9814,
-	0xf500e7f0,
-	0xf0015c21,
-	0x21f508a7,
-	0x21f50103,
-	0x01f40207,
-	0x0ca7f022,
-	0xf1c921f4,
-	0xb60a1017,
-	0x27f00614,
-	0x0012d005,
-/* 0x08f4: ctx_xfer_post_save_wait */
-	0xfd0012cf,
-	0x1bf40522,
-	0x3202f4fa,
-/* 0x0900: ctx_xfer_post */
-	0xf502f7f0,
-	0xbd065721,
-	0x9821f5f4,
-	0x2621f506,
-	0x6621f502,
+	0x12b60830,
+	0xdf1bf401,
+/* 0x0818: ctx_mmio_done */
+	0xd0160398,
+	0x00800023,
+	0x0017f140,
+	0x0613f001,
+	0xf80601fa,
+/* 0x082f: ctx_xfer */
+	0xf100f803,
+	0xb60c00f7,
+	0xe7f006f4,
+	0x80fed004,
+/* 0x083c: ctx_xfer_idle */
+	0xf100fecf,
+	0xf42000e4,
+	0x11f4f91b,
+	0x1102f406,
+/* 0x084c: ctx_xfer_pre */
+	0xf510f7f0,
+	0xf5069221,
+	0xf4062b21,
+/* 0x085a: ctx_xfer_pre_load */
+	0xf7f01c11,
+	0x5121f502,
+	0x6021f506,
+	0x7221f506,
 	0xf5f4bd06,
-	0xf4065721,
-	0x01981011,
-	0x0511fd80,
-	0xf5070bf4,
-/* 0x092b: ctx_xfer_no_post_mmio */
-	0xf507df21,
-/* 0x092f: ctx_xfer_done */
-	0xf8064921,
-	0x00000000,
-	0x00000000,
+	0xf5065121,
+/* 0x0873: ctx_xfer_exec */
+	0x9806b221,
+	0x27f11601,
+	0x24b60414,
+	0x0020d006,
+	0xa500e7f1,
+	0xb941e3f0,
+	0x21f4021f,
+	0x04e0b68d,
+	0xf001fcf0,
+	0x24b6022c,
+	0x05f2fd01,
+	0xf18d21f4,
+	0xf04afc17,
+	0x27f00213,
+	0x0012d00c,
+	0x021521f5,
+	0x47fc27f1,
+	0xd00223f0,
+	0x2cf00020,
+	0x0320b601,
+	0xf00012d0,
+	0xa5f001ac,
+	0x00b7f006,
+	0x98000c98,
+	0xe7f0010d,
+	0x6621f500,
+	0x08a7f001,
+	0x010921f5,
+	0x021521f5,
+	0xf02201f4,
+	0x21f40ca7,
+	0x1017f1c9,
+	0x0614b60a,
+	0xd00527f0,
+/* 0x08fa: ctx_xfer_post_save_wait */
+	0x12cf0012,
+	0x0522fd00,
+	0xf4fa1bf4,
+/* 0x0906: ctx_xfer_post */
+	0xf7f03202,
+	0x5121f502,
+	0xf5f4bd06,
+	0xf5069221,
+	0xf5023421,
+	0xbd066021,
+	0x5121f5f4,
+	0x1011f406,
+	0xfd400198,
+	0x0bf40511,
+	0xe521f507,
+/* 0x0931: ctx_xfer_no_post_mmio */
+	0x4321f507,
+/* 0x0935: ctx_xfer_done */
+	0x0000f806,
 	0x00000000,
 	0x00000000,
 	0x00000000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc
new file mode 100644
index 0000000..afbe03a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GF117
+#include "macros.fuc"
+
+.section #nvd7_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #nvd7_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
new file mode 100644
index 0000000..a1b9f76
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
@@ -0,0 +1,921 @@
+uint32_t nvd7_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
+	0x00000000,
+/* 0x000c: rop_count */
+	0x00000000,
+/* 0x0010: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: ctx_current */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
+	0x0417e91c,
+};
+
+uint32_t nvd7_grhub_code[] = {
+	0x031b0ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f802fe,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0x0728b7f1,
+	0xb906b4b6,
+	0xc9f002ec,
+	0x00bcd01f,
+/* 0x0078: nv_rd32_wait */
+	0xc800bccf,
+	0x1bf41fcc,
+	0x06a7f0fa,
+	0x010921f5,
+	0xf840bfcf,
+/* 0x008d: nv_wr32 */
+	0x28b7f100,
+	0x06b4b607,
+	0xb980bfd0,
+	0xc9f002ec,
+	0x1ec9f01f,
+/* 0x00a3: nv_wr32_wait */
+	0xcf00bcd0,
+	0xccc800bc,
+	0xfa1bf41f,
+/* 0x00ae: watchdog_reset */
+	0x87f100f8,
+	0x84b60430,
+	0x1ff9f006,
+	0xf8008fd0,
+/* 0x00bd: watchdog_clear */
+	0x3087f100,
+	0x0684b604,
+	0xf80080d0,
+/* 0x00c9: wait_donez */
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x07f104bd,
+	0x03f00600,
+	0x000ad002,
+/* 0x00e6: wait_donez_ne */
+	0x87f104bd,
+	0x83f00000,
+	0x0088cf01,
+	0xf4888aff,
+	0x94bdf31b,
+	0xf10099f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0109: wait_doneo */
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x87f104bd,
+	0x84b60818,
+	0x008ad006,
+/* 0x0124: wait_doneo_e */
+	0x040087f1,
+	0xcf0684b6,
+	0x8aff0088,
+	0xf30bf488,
+	0x99f094bd,
+	0x0007f100,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x0147: mmctx_size */
+	0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+	0x00e89894,
+	0xb61a85b6,
+	0x84b60180,
+	0x0098bb02,
+	0xb804e0b6,
+	0x1bf404ef,
+	0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+	0x94bd00f8,
+	0xf10199f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
+	0xb6071087,
+	0x94bd0684,
+	0xf405bbfd,
+	0x8bd0090b,
+	0x0099f000,
+/* 0x018c: mmctx_base_disabled */
+	0xf405eefd,
+	0x8ed00c0b,
+	0xc08fd080,
+/* 0x019b: mmctx_multi_disabled */
+	0xb70199f0,
+	0xc8010080,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xb601aec8,
+	0xbefd11e4,
+	0x008bd005,
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
+	0xf0008ecf,
+	0x0bf41fe4,
+	0x00ce98fa,
+	0xd005e9fd,
+	0xc0b6c08e,
+	0x04cdb804,
+	0xc8e81bf4,
+	0x1bf402ab,
+/* 0x01d5: mmctx_fini_wait */
+	0x008bcf18,
+	0xb01fb4f0,
+	0x1bf410b4,
+	0x02a7f0f7,
+	0xf4c921f4,
+/* 0x01ea: mmctx_stop */
+	0xabc81b0e,
+	0x10b4b600,
+	0xf00cb9f0,
+	0x8bd012b9,
+/* 0x01f9: mmctx_stop_wait */
+	0x008bcf00,
+	0xf412bbc8,
+/* 0x0202: mmctx_done */
+	0x94bdfa1b,
+	0xf10199f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0215: strand_wait */
+	0xf0a0f900,
+	0x21f402a7,
+	0xf8a0fcc9,
+/* 0x0221: strand_pre */
+	0xfc87f100,
+	0x0283f04a,
+	0xd00c97f0,
+	0x21f50089,
+	0x00f80215,
+/* 0x0234: strand_post */
+	0x4afc87f1,
+	0xf00283f0,
+	0x89d00d97,
+	0x1521f500,
+/* 0x0247: strand_set */
+	0xf100f802,
+	0xf04ffca7,
+	0xaba202a3,
+	0xc7f00500,
+	0x00acd00f,
+	0xd00bc7f0,
+	0x21f500bc,
+	0xaed00215,
+	0x0ac7f000,
+	0xf500bcd0,
+	0xf8021521,
+/* 0x0271: strand_ctx_init */
+	0xf094bd00,
+	0x07f10399,
+	0x03f00f00,
+	0x0009d002,
+	0x21f504bd,
+	0xe7f00221,
+	0x4721f503,
+	0xfca7f102,
+	0x02a3f046,
+	0x0400aba0,
+	0xf040a0d0,
+	0xbcd001c7,
+	0x1521f500,
+	0x010c9202,
+	0xf000acd0,
+	0xbcd002c7,
+	0x1521f500,
+	0x3421f502,
+	0x8087f102,
+	0x0684b608,
+	0xb70089cf,
+	0x95220080,
+/* 0x02ca: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x02fe: error */
+	0x07f100f8,
+	0x03f00500,
+	0x000fd002,
+	0xf7f004bd,
+	0x0007f101,
+	0x0303f007,
+	0xbd000fd0,
+/* 0x031b: init */
+	0xbd00f804,
+	0x0004fe04,
+	0xf10007fe,
+	0xf0120017,
+	0x12d00227,
+	0xb117f100,
+	0x0010fe05,
+	0x040017f1,
+	0xf1c010d0,
+	0xb6040437,
+	0x27f10634,
+	0x32d02003,
+	0x0427f100,
+	0x0132d020,
+	0x200b27f1,
+	0xf10232d0,
+	0xd0200c27,
+	0x27f10732,
+	0x24b60c24,
+	0x0003b906,
+	0xf10023d0,
+	0xf0870427,
+	0x12d00023,
+	0x0012b700,
+	0x0427f001,
+	0xf40012d0,
+	0xe7f11031,
+	0xe3f09604,
+	0x6821f440,
+	0x8090f1c7,
+	0xf4f00301,
+	0x020f801f,
+	0xbb0117f0,
+	0x12b6041f,
+	0x0c27f101,
+	0x0624b604,
+	0xd00021d0,
+	0x17f14021,
+	0x0e980100,
+	0x010f9800,
+	0x014721f5,
+	0x070037f1,
+	0x950634b6,
+	0x34d00814,
+	0x4034d000,
+	0x130030b7,
+	0xb6001fbb,
+	0x3fd002f5,
+	0x0815b600,
+	0xb60110b6,
+	0x1fb90814,
+	0x7121f502,
+	0x001fbb02,
+	0xf1020398,
+	0xf0200047,
+/* 0x03f6: init_gpc */
+	0x4ea05043,
+	0x1fb90804,
+	0x8d21f402,
+	0x010c4ea0,
+	0x21f4f4bd,
+	0x044ea08d,
+	0x8d21f401,
+	0x01004ea0,
+	0xf402f7f0,
+	0x4ea08d21,
+/* 0x041e: init_gpc_wait */
+	0x21f40800,
+	0x1fffc868,
+	0xa0fa0bf4,
+	0xf408044e,
+	0x1fbb6821,
+	0x0040b700,
+	0x0132b680,
+	0xf1be1bf4,
+	0xf0010007,
+	0x01d00203,
+	0xbd04bd00,
+	0x1f19f014,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0001,
+/* 0x0458: main */
+	0xf40031f4,
+	0xd7f00028,
+	0x3921f410,
+	0xb1f401f4,
+	0xf54001e4,
+	0xbd00de1b,
+	0x0499f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x0b0017f1,
+	0xcf0614b6,
+	0x11cf4012,
+	0x1f13c800,
+	0x00870bf5,
+	0xf41f23c8,
+	0x20f9620b,
+	0xbd0212b9,
+	0x0799f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xf40132f4,
+	0x21f50231,
+	0x94bd082f,
+	0xf10799f0,
+	0xf0170007,
+	0x09d00203,
+	0xfc04bd00,
+	0xf094bd20,
+	0x07f10699,
+	0x03f00f00,
+	0x0009d002,
+	0x31f404bd,
+	0x2f21f501,
+	0xf094bd08,
+	0x07f10699,
+	0x03f01700,
+	0x0009d002,
+	0x0ef404bd,
+/* 0x04f9: chsw_prev_no_next */
+	0xb920f931,
+	0x32f40212,
+	0x0232f401,
+	0x082f21f5,
+	0x17f120fc,
+	0x14b60b00,
+	0x0012d006,
+/* 0x0517: chsw_no_prev */
+	0xc8130ef4,
+	0x0bf41f23,
+	0x0131f40d,
+	0xf50232f4,
+/* 0x0527: chsw_done */
+	0xf1082f21,
+	0xb60b0c17,
+	0x27f00614,
+	0x0012d001,
+	0x99f094bd,
+	0x0007f104,
+	0x0203f017,
+	0xbd0009d0,
+	0x130ef504,
+/* 0x0549: main_not_ctx_switch */
+	0x01e4b0ff,
+	0xb90d1bf4,
+	0x21f502f2,
+	0x0ef407bb,
+/* 0x0559: main_not_ctx_chan */
+	0x02e4b046,
+	0xbd321bf4,
+	0x0799f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xf40132f4,
+	0x21f50232,
+	0x94bd082f,
+	0xf10799f0,
+	0xf0170007,
+	0x09d00203,
+	0xf404bd00,
+/* 0x058e: main_not_ctx_save */
+	0xef94110e,
+	0x01f5f010,
+	0x02fe21f5,
+	0xfec00ef5,
+/* 0x059c: main_done */
+	0x29f024bd,
+	0x0007f11f,
+	0x0203f008,
+	0xbd0002d0,
+	0xab0ef504,
+/* 0x05b1: ih */
+	0xfe80f9fe,
+	0x80f90188,
+	0xa0f990f9,
+	0xd0f9b0f9,
+	0xf0f9e0f9,
+	0x0acf04bd,
+	0x04abc480,
+	0xf11d0bf4,
+	0xf01900b7,
+	0xbecf10d7,
+	0x00bfcf40,
+	0xb70421f4,
+	0xf00400b0,
+	0xbed001e7,
+/* 0x05e9: ih_no_fifo */
+	0x00abe400,
+	0x0d0bf401,
+	0xf110d7f0,
+	0xf44001e7,
+/* 0x05fa: ih_no_ctxsw */
+	0xb7f10421,
+	0xb0bd0104,
+	0xf4b4abff,
+	0xa7f10d0b,
+	0xa4b60c1c,
+	0x00abd006,
+/* 0x0610: ih_no_other */
+	0xfc400ad0,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x062b: ctx_4160s */
+	0xf101f800,
+	0xf04160e7,
+	0xf7f040e3,
+	0x8d21f401,
+/* 0x0638: ctx_4160s_wait */
+	0xc86821f4,
+	0x0bf404ff,
+/* 0x0643: ctx_4160c */
+	0xf100f8fa,
+	0xf04160e7,
+	0xf4bd40e3,
+	0xf88d21f4,
+/* 0x0651: ctx_4170s */
+	0x70e7f100,
+	0x40e3f041,
+	0xf410f5f0,
+	0x00f88d21,
+/* 0x0660: ctx_4170w */
+	0x4170e7f1,
+	0xf440e3f0,
+	0xf4f06821,
+	0xf31bf410,
+/* 0x0672: ctx_redswitch */
+	0xe7f100f8,
+	0xe4b60614,
+	0x70f7f106,
+	0x00efd002,
+/* 0x0683: ctx_redswitch_delay */
+	0xb608f7f0,
+	0x1bf401f2,
+	0x70f7f1fd,
+	0x00efd007,
+/* 0x0692: ctx_86c */
+	0xe7f100f8,
+	0xe4b6086c,
+	0x00efd006,
+	0x8a14e7f1,
+	0xf440e3f0,
+	0xe7f18d21,
+	0xe3f0a86c,
+	0x8d21f441,
+/* 0x06b2: ctx_load */
+	0x94bd00f8,
+	0xf10599f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf004bd00,
+	0x21f40ca7,
+	0x2417f1c9,
+	0x0614b60a,
+	0xf10010d0,
+	0xb60b0037,
+	0x32d00634,
+	0x0c17f140,
+	0x0614b60a,
+	0xd00747f0,
+	0x14d00012,
+/* 0x06ed: ctx_chan_wait_0 */
+	0x4014cf40,
+	0xf41f44f0,
+	0x32d0fa1b,
+	0x000bfe00,
+	0xb61f2af0,
+	0x20b60424,
+	0xf094bd02,
+	0x07f10899,
+	0x03f00f00,
+	0x0009d002,
+	0x17f104bd,
+	0x14b60a04,
+	0x0012d006,
+	0x0a2017f1,
+	0xf00614b6,
+	0x23f10227,
+	0x12d08000,
+	0x1017f000,
+	0x020027f1,
+	0xfa0223f0,
+	0x03f80512,
+	0x99f094bd,
+	0x0007f108,
+	0x0203f017,
+	0xbd0009d0,
+	0x81019804,
+	0x981814b6,
+	0x25b68002,
+	0x0512fd08,
+	0xbd160180,
+	0x0999f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x0a0427f1,
+	0xd00624b6,
+	0x27f00021,
+	0x2017f101,
+	0x0614b60a,
+	0xf10012d0,
+	0xf0010017,
+	0x01fa0613,
+	0xbd03f805,
+	0x0999f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x99f094bd,
+	0x0007f105,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x07bb: ctx_chan */
+	0xf500f804,
+	0xf5062b21,
+	0xf006b221,
+	0x21f40ca7,
+	0x1017f1c9,
+	0x0614b60a,
+	0xd00527f0,
+/* 0x07d6: ctx_chan_wait */
+	0x12cf0012,
+	0x0522fd00,
+	0xf5fa1bf4,
+	0xf8064321,
+/* 0x07e5: ctx_mmio_exec */
+	0x41039800,
+	0x0a0427f1,
+	0xd00624b6,
+	0x34bd0023,
+/* 0x07f4: ctx_mmio_loop */
+	0xf4ff34c4,
+	0x57f10f1b,
+	0x53f00200,
+	0x0535fa06,
+/* 0x0806: ctx_mmio_pull */
+	0x4e9803f8,
+	0x814f9880,
+	0xb68d21f4,
+	0x12b60830,
+	0xdf1bf401,
+/* 0x0818: ctx_mmio_done */
+	0xd0160398,
+	0x00800023,
+	0x0017f140,
+	0x0613f001,
+	0xf80601fa,
+/* 0x082f: ctx_xfer */
+	0xf100f803,
+	0xb60c00f7,
+	0xe7f006f4,
+	0x80fed004,
+/* 0x083c: ctx_xfer_idle */
+	0xf100fecf,
+	0xf42000e4,
+	0x11f4f91b,
+	0x1102f406,
+/* 0x084c: ctx_xfer_pre */
+	0xf510f7f0,
+	0xf5069221,
+	0xf4062b21,
+/* 0x085a: ctx_xfer_pre_load */
+	0xf7f01c11,
+	0x5121f502,
+	0x6021f506,
+	0x7221f506,
+	0xf5f4bd06,
+	0xf5065121,
+/* 0x0873: ctx_xfer_exec */
+	0x9806b221,
+	0x27f11601,
+	0x24b60414,
+	0x0020d006,
+	0xa500e7f1,
+	0xb941e3f0,
+	0x21f4021f,
+	0x04e0b68d,
+	0xf001fcf0,
+	0x24b6022c,
+	0x05f2fd01,
+	0xf18d21f4,
+	0xf04afc17,
+	0x27f00213,
+	0x0012d00c,
+	0x021521f5,
+	0x47fc27f1,
+	0xd00223f0,
+	0x2cf00020,
+	0x0320b601,
+	0xf00012d0,
+	0xa5f001ac,
+	0x00b7f006,
+	0x98000c98,
+	0xe7f0010d,
+	0x6621f500,
+	0x08a7f001,
+	0x010921f5,
+	0x021521f5,
+	0xf02201f4,
+	0x21f40ca7,
+	0x1017f1c9,
+	0x0614b60a,
+	0xd00527f0,
+/* 0x08fa: ctx_xfer_post_save_wait */
+	0x12cf0012,
+	0x0522fd00,
+	0xf4fa1bf4,
+/* 0x0906: ctx_xfer_post */
+	0xf7f03202,
+	0x5121f502,
+	0xf5f4bd06,
+	0xf5069221,
+	0xf5023421,
+	0xbd066021,
+	0x5121f5f4,
+	0x1011f406,
+	0xfd400198,
+	0x0bf40511,
+	0xe521f507,
+/* 0x0931: ctx_xfer_no_post_mmio */
+	0x4321f507,
+/* 0x0935: ctx_xfer_done */
+	0x0000f806,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
index 7fe9d7c..d4840f1 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nve0 PGRAPH/HUB
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -20,774 +19,22 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-/* To build:
- *    m4 nve0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grhub.fuc.h
- */
+#define CHIPSET GK100
+#include "macros.fuc"
 
 .section #nve0_grhub_data
-include(`nve0.fuc')
-gpc_count:		.b32 0
-rop_count:		.b32 0
-cmd_queue:		queue_init
-hub_mmio_list_head:	.b32 0
-hub_mmio_list_tail:	.b32 0
-
-ctx_current:		.b32 0
-
-chipsets:
-.b8  0xe4 0 0 0
-.b16 #nve4_hub_mmio_head
-.b16 #nve4_hub_mmio_tail
-.b8  0xe7 0 0 0
-.b16 #nve4_hub_mmio_head
-.b16 #nve4_hub_mmio_tail
-.b8  0xe6 0 0 0
-.b16 #nve4_hub_mmio_head
-.b16 #nve4_hub_mmio_tail
-.b8  0 0 0 0
-
-nve4_hub_mmio_head:
-mmctx_data(0x17e91c, 2)
-mmctx_data(0x400204, 2)
-mmctx_data(0x404010, 7)
-mmctx_data(0x4040a8, 9)
-mmctx_data(0x4040d0, 7)
-mmctx_data(0x4040f8, 1)
-mmctx_data(0x404130, 3)
-mmctx_data(0x404150, 3)
-mmctx_data(0x404164, 1)
-mmctx_data(0x4041a0, 4)
-mmctx_data(0x404200, 4)
-mmctx_data(0x404404, 14)
-mmctx_data(0x404460, 4)
-mmctx_data(0x404480, 1)
-mmctx_data(0x404498, 1)
-mmctx_data(0x404604, 4)
-mmctx_data(0x404618, 4)
-mmctx_data(0x40462c, 2)
-mmctx_data(0x404640, 1)
-mmctx_data(0x404654, 1)
-mmctx_data(0x404660, 1)
-mmctx_data(0x404678, 19)
-mmctx_data(0x4046c8, 3)
-mmctx_data(0x404700, 3)
-mmctx_data(0x404718, 10)
-mmctx_data(0x404744, 2)
-mmctx_data(0x404754, 1)
-mmctx_data(0x405800, 1)
-mmctx_data(0x405830, 3)
-mmctx_data(0x405854, 1)
-mmctx_data(0x405870, 4)
-mmctx_data(0x405a00, 2)
-mmctx_data(0x405a18, 1)
-mmctx_data(0x405b00, 1)
-mmctx_data(0x405b10, 1)
-mmctx_data(0x406020, 1)
-mmctx_data(0x406028, 4)
-mmctx_data(0x4064a8, 2)
-mmctx_data(0x4064b4, 2)
-mmctx_data(0x4064c0, 12)
-mmctx_data(0x4064fc, 1)
-mmctx_data(0x407040, 1)
-mmctx_data(0x407804, 1)
-mmctx_data(0x40780c, 6)
-mmctx_data(0x4078bc, 1)
-mmctx_data(0x408000, 7)
-mmctx_data(0x408064, 1)
-mmctx_data(0x408800, 3)
-mmctx_data(0x408840, 1)
-mmctx_data(0x408900, 3)
-mmctx_data(0x408980, 1)
-nve4_hub_mmio_tail:
-
-.align 256
-chan_data:
-chan_mmio_count:	.b32 0
-chan_mmio_address:	.b32 0
-
-.align 256
-xfer_data: 		.b32 0
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
 
 .section #nve0_grhub_code
+#define INCLUDE_CODE
 bra #init
-define(`include_code')
-include(`nve0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nve0.fuc)
-//
-error:
-	push $r14
-	mov $r14 0x814
-	shl b32 $r14 6
-	iowr I[$r14 + 0x000] $r15	// CC_SCRATCH[5] = error code
-	mov $r14 0xc1c
-	shl b32 $r14 6
-	mov $r15 1
-	iowr I[$r14 + 0x000] $r15	// INTR_UP_SET
-	pop $r14
-	ret
-
-// HUB fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//
-// Output:
-//   CC_SCRATCH[0]:
-//	     31:31: set to signal completion
-//   CC_SCRATCH[1]:
-//	      31:0: total PGRAPH context size
-//
-init:
-	clear b32 $r0
-	mov $sp $r0
-	mov $xdbase $r0
-
-	// enable fifo access
-	mov $r1 0x1200
-	mov $r2 2
-	iowr I[$r1 + 0x000] $r2	// FIFO_ENABLE
-
-	// setup i0 handler, and route all interrupts to it
-	mov $r1 #ih
-	mov $iv0 $r1
-	mov $r1 0x400
-	iowr I[$r1 + 0x300] $r0	// INTR_DISPATCH
-
-	// route HUB_CHANNEL_SWITCH to fuc interrupt 8
-	mov $r3 0x404
-	shl b32 $r3 6
-	mov $r2 0x2003		// { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
-	iowr I[$r3 + 0x000] $r2
-
-	// not sure what these are, route them because NVIDIA does, and
-	// the IRQ handler will signal the host if we ever get one.. we
-	// may find out if/why we need to handle these if so..
-	//
-	mov $r2 0x2004
-	iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
-	mov $r2 0x200b
-	iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
-	mov $r2 0x200c
-	iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
-
-	// enable all INTR_UP interrupts
-	mov $r2 0xc24
-	shl b32 $r2 6
-	not b32 $r3 $r0
-	iowr I[$r2] $r3
-
-	// enable fifo, ctxsw, 9, 10, 15 interrupts
-	mov $r2 -0x78fc		// 0x8704
-	sethi $r2 0
-	iowr I[$r1 + 0x000] $r2	// INTR_EN_SET
-
-	// fifo level triggered, rest edge
-	sub b32 $r1 0x100
-	mov $r2 4
-	iowr I[$r1] $r2
-
-	// enable interrupts
-	bset $flags ie0
-
-	// fetch enabled GPC/ROP counts
-	mov $r14 -0x69fc	// 0x409604
-	sethi $r14 0x400000
-	call #nv_rd32
-	extr $r1 $r15 16:20
-	st b32 D[$r0 + #rop_count] $r1
-	and $r15 0x1f
-	st b32 D[$r0 + #gpc_count] $r15
-
-	// set BAR_REQMASK to GPC mask
-	mov $r1 1
-	shl b32 $r1 $r15
-	sub b32 $r1 1
-	mov $r2 0x40c
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r1
-	iowr I[$r2 + 0x100] $r1
-
-	// find context data for this chipset
-	mov $r2 0x800
-	shl b32 $r2 6
-	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
-	mov $r15 #chipsets - 8
-	init_find_chipset:
-		add b32 $r15 8
-		ld b32 $r3 D[$r15 + 0x00]
-		cmpu b32 $r3 $r2
-		bra e #init_context
-		cmpu b32 $r3 0
-		bra ne #init_find_chipset
-		// unknown chipset
-		ret
-
-	// context size calculation, reserve first 256 bytes for use by fuc
-	init_context:
-	mov $r1 256
-
-	// calculate size of mmio context data
-	ld b16 $r14 D[$r15 + 4]
-	ld b16 $r15 D[$r15 + 6]
-	sethi $r14 0
-	st b32 D[$r0 + #hub_mmio_list_head] $r14
-	st b32 D[$r0 + #hub_mmio_list_tail] $r15
-	call #mmctx_size
-
-	// set mmctx base addresses now so we don't have to do it later,
-	// they don't (currently) ever change
-	mov $r3 0x700
-	shl b32 $r3 6
-	shr b32 $r4 $r1 8
-	iowr I[$r3 + 0x000] $r4		// MMCTX_SAVE_SWBASE
-	iowr I[$r3 + 0x100] $r4		// MMCTX_LOAD_SWBASE
-	add b32 $r3 0x1300
-	add b32 $r1 $r15
-	shr b32 $r15 2
-	iowr I[$r3 + 0x000] $r15	// MMCTX_LOAD_COUNT, wtf for?!?
-
-	// strands, base offset needs to be aligned to 256 bytes
-	shr b32 $r1 8
-	add b32 $r1 1
-	shl b32 $r1 8
-	mov b32 $r15 $r1
-	call #strand_ctx_init
-	add b32 $r1 $r15
-
-	// initialise each GPC in sequence by passing in the offset of its
-	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
-	// has previously been uploaded by the host) running.
-	//
-	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
-	// when it has completed, and return the size of its context data
-	// in GPCn_CC_SCRATCH[1]
-	//
-	ld b32 $r3 D[$r0 + #gpc_count]
-	mov $r4 0x2000
-	sethi $r4 0x500000
-	init_gpc:
-		// setup, and start GPC ucode running
-		add b32 $r14 $r4 0x804
-		mov b32 $r15 $r1
-		call #nv_wr32			// CC_SCRATCH[1] = ctx offset
-		add b32 $r14 $r4 0x800
-		mov b32 $r15 $r2
-		call #nv_wr32			// CC_SCRATCH[0] = chipset
-		add b32 $r14 $r4 0x10c
-		clear b32 $r15
-		call #nv_wr32
-		add b32 $r14 $r4 0x104
-		call #nv_wr32			// ENTRY
-		add b32 $r14 $r4 0x100
-		mov $r15 2			// CTRL_START_TRIGGER
-		call #nv_wr32			// CTRL
-
-		// wait for it to complete, and adjust context size
-		add b32 $r14 $r4 0x800
-		init_gpc_wait:
-			call #nv_rd32
-			xbit $r15 $r15 31
-			bra e #init_gpc_wait
-		add b32 $r14 $r4 0x804
-		call #nv_rd32
-		add b32 $r1 $r15
-
-		// next!
-		add b32 $r4 0x8000
-		sub b32 $r3 1
-		bra ne #init_gpc
-
-	// save context size, and tell host we're ready
-	mov $r2 0x800
-	shl b32 $r2 6
-	iowr I[$r2 + 0x100] $r1		// CC_SCRATCH[1]  = context size
-	add b32 $r2 0x800
-	clear b32 $r1
-	bset $r1 31
-	iowr I[$r2 + 0x000] $r1		// CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
-	// sleep until we have something to do
-	bset $flags $p0
-	sleep $p0
-	mov $r13 #cmd_queue
-	call #queue_get
-	bra $p1 #main
-
-	// context switch, requested by GPU?
-	cmpu b32 $r14 0x4001
-	bra ne #main_not_ctx_switch
-		trace_set(T_AUTO)
-		mov $r1 0xb00
-		shl b32 $r1 6
-		iord $r2 I[$r1 + 0x100]		// CHAN_NEXT
-		iord $r1 I[$r1 + 0x000]		// CHAN_CUR
-
-		xbit $r3 $r1 31
-		bra e #chsw_no_prev
-			xbit $r3 $r2 31
-			bra e #chsw_prev_no_next
-				push $r2
-				mov b32 $r2 $r1
-				trace_set(T_SAVE)
-				bclr $flags $p1
-				bset $flags $p2
-				call #ctx_xfer
-				trace_clr(T_SAVE);
-				pop $r2
-				trace_set(T_LOAD);
-				bset $flags $p1
-				call #ctx_xfer
-				trace_clr(T_LOAD);
-				bra #chsw_done
-			chsw_prev_no_next:
-				push $r2
-				mov b32 $r2 $r1
-				bclr $flags $p1
-				bclr $flags $p2
-				call #ctx_xfer
-				pop $r2
-				mov $r1 0xb00
-				shl b32 $r1 6
-				iowr I[$r1] $r2
-				bra #chsw_done
-		chsw_no_prev:
-			xbit $r3 $r2 31
-			bra e #chsw_done
-				bset $flags $p1
-				bclr $flags $p2
-				call #ctx_xfer
-
-		// ack the context switch request
-		chsw_done:
-		mov $r1 0xb0c
-		shl b32 $r1 6
-		mov $r2 1
-		iowr I[$r1 + 0x000] $r2		// 0x409b0c
-		trace_clr(T_AUTO)
-		bra #main
-
-	// request to set current channel? (*not* a context switch)
-	main_not_ctx_switch:
-	cmpu b32 $r14 0x0001
-	bra ne #main_not_ctx_chan
-		mov b32 $r2 $r15
-		call #ctx_chan
-		bra #main_done
-
-	// request to store current channel context?
-	main_not_ctx_chan:
-	cmpu b32 $r14 0x0002
-	bra ne #main_not_ctx_save
-		trace_set(T_SAVE)
-		bclr $flags $p1
-		bclr $flags $p2
-		call #ctx_xfer
-		trace_clr(T_SAVE)
-		bra #main_done
-
-	main_not_ctx_save:
-		shl b32 $r15 $r14 16
-		or $r15 E_BAD_COMMAND
-		call #error
-		bra #main
-
-	main_done:
-	mov $r1 0x820
-	shl b32 $r1 6
-	clear b32 $r2
-	bset $r2 31
-	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
-	bra #main
-
-// interrupt handler
-ih:
-	push $r8
-	mov $r8 $flags
-	push $r8
-	push $r9
-	push $r10
-	push $r11
-	push $r13
-	push $r14
-	push $r15
-
-	// incoming fifo command?
-	iord $r10 I[$r0 + 0x200]	// INTR
-	and $r11 $r10 0x00000004
-	bra e #ih_no_fifo
-		// queue incoming fifo command for later processing
-		mov $r11 0x1900
-		mov $r13 #cmd_queue
-		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
-		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
-		call #queue_put
-		add b32 $r11 0x400
-		mov $r14 1
-		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
-
-	// context switch request?
-	ih_no_fifo:
-	and $r11 $r10 0x00000100
-	bra e #ih_no_ctxsw
-		// enqueue a context switch for later processing
-		mov $r13 #cmd_queue
-		mov $r14 0x4001
-		call #queue_put
-
-	// anything we didn't handle, bring it to the host's attention
-	ih_no_ctxsw:
-	mov $r11 0x104
-	not b32 $r11
-	and $r11 $r10 $r11
-	bra e #ih_no_other
-		mov $r10 0xc1c
-		shl b32 $r10 6
-		iowr I[$r10] $r11	// INTR_UP_SET
-
-	// ack, and wake up main()
-	ih_no_other:
-	iowr I[$r0 + 0x100] $r10	// INTR_ACK
-
-	pop $r15
-	pop $r14
-	pop $r13
-	pop $r11
-	pop $r10
-	pop $r9
-	pop $r8
-	mov $flags $r8
-	pop $r8
-	bclr $flags $p0
-	iret
-
-// Again, not real sure
-//
-// In: $r15 value to set 0x404170 to
-//
-ctx_4170s:
-	mov $r14 0x4170
-	sethi $r14 0x400000
-	or $r15 0x10
-	call #nv_wr32
-	ret
-
-// Waits for a ctx_4170s() call to complete
-//
-ctx_4170w:
-	mov $r14 0x4170
-	sethi $r14 0x400000
-	call #nv_rd32
-	and $r15 0x10
-	bra ne #ctx_4170w
-	ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off?  Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
-	mov $r14 0x614
-	shl b32 $r14 6
-	mov $r15 0x270
-	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
-	mov $r15 8
-	ctx_redswitch_delay:
-		sub b32 $r15 1
-		bra ne #ctx_redswitch_delay
-	mov $r15 0x770
-	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
-	ret
-
-// Not a clue what this is for, except that unless the value is 0x10, the
-// strand context is saved (and presumably restored) incorrectly..
-//
-// In: $r15 value to set to (0x00/0x10 are used)
-//
-ctx_86c:
-	mov $r14 0x86c
-	shl b32 $r14 6
-	iowr I[$r14] $r15	// HUB(0x86c) = val
-	mov $r14 -0x75ec
-	sethi $r14 0x400000
-	call #nv_wr32		// ROP(0xa14) = val
-	mov $r14 -0x5794
-	sethi $r14 0x410000
-	call #nv_wr32		// GPC(0x86c) = val
-	ret
-
-// ctx_load - load's a channel's ctxctl data, and selects its vm
-//
-// In: $r2 channel address
-//
-ctx_load:
-	trace_set(T_CHAN)
-
-	// switch to channel, somewhat magic in parts..
-	mov $r10 12		// DONE_UNK12
-	call #wait_donez
-	mov $r1 0xa24
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r0	// 0x409a24
-	mov $r3 0xb00
-	shl b32 $r3 6
-	iowr I[$r3 + 0x100] $r2	// CHAN_NEXT
-	mov $r1 0xa0c
-	shl b32 $r1 6
-	mov $r4 7
-	iowr I[$r1 + 0x000] $r2 // MEM_CHAN
-	iowr I[$r1 + 0x100] $r4	// MEM_CMD
-	ctx_chan_wait_0:
-		iord $r4 I[$r1 + 0x100]
-		and $r4 0x1f
-		bra ne #ctx_chan_wait_0
-	iowr I[$r3 + 0x000] $r2	// CHAN_CUR
-
-	// load channel header, fetch PGRAPH context pointer
-	mov $xtargets $r0
-	bclr $r2 31
-	shl b32 $r2 4
-	add b32 $r2 2
-
-	trace_set(T_LCHAN)
-	mov $r1 0xa04
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r2		// MEM_BASE
-	mov $r1 0xa20
-	shl b32 $r1 6
-	mov $r2 0x0002
-	sethi $r2 0x80000000
-	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vram
-	mov $r1 0x10			// chan + 0x0210
-	mov $r2 #xfer_data
-	sethi $r2 0x00020000		// 16 bytes
-	xdld $r1 $r2
-	xdwait
-	trace_clr(T_LCHAN)
-
-	// update current context
-	ld b32 $r1 D[$r0 + #xfer_data + 4]
-	shl b32 $r1 24
-	ld b32 $r2 D[$r0 + #xfer_data + 0]
-	shr b32 $r2 8
-	or $r1 $r2
-	st b32 D[$r0 + #ctx_current] $r1
-
-	// set transfer base to start of context, and fetch context header
-	trace_set(T_LCTXH)
-	mov $r2 0xa04
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r1		// MEM_BASE
-	mov $r2 1
-	mov $r1 0xa20
-	shl b32 $r1 6
-	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vm
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdld $r0 $r1
-	xdwait
-	trace_clr(T_LCTXH)
-
-	trace_clr(T_CHAN)
-	ret
-
-// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
-//            the active channel for ctxctl, but not actually transfer
-//            any context data.  intended for use only during initial
-//            context construction.
-//
-// In: $r2 channel address
-//
-ctx_chan:
-	call #ctx_load
-	mov $r10 12			// DONE_UNK12
-	call #wait_donez
-	mov $r1 0xa10
-	shl b32 $r1 6
-	mov $r2 5
-	iowr I[$r1 + 0x000] $r2		// MEM_CMD = 5 (???)
-	ctx_chan_wait:
-		iord $r2 I[$r1 + 0x000]
-		or $r2 $r2
-		bra ne #ctx_chan_wait
-	ret
-
-// Execute per-context state overrides list
-//
-// Only executed on the first load of a channel.  Might want to look into
-// removing this and having the host directly modify the channel's context
-// to change this state...  The nouveau DRM already builds this list as
-// it's definitely needed for NVIDIA's, so we may as well use it for now
-//
-// Input: $r1 mmio list length
-//
-ctx_mmio_exec:
-	// set transfer base to be the mmio list
-	ld b32 $r3 D[$r0 + #chan_mmio_address]
-	mov $r2 0xa04
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r3		// MEM_BASE
-
-	clear b32 $r3
-	ctx_mmio_loop:
-		// fetch next 256 bytes of mmio list if necessary
-		and $r4 $r3 0xff
-		bra ne #ctx_mmio_pull
-			mov $r5 #xfer_data
-			sethi $r5 0x00060000	// 256 bytes
-			xdld $r3 $r5
-			xdwait
-
-		// execute a single list entry
-		ctx_mmio_pull:
-		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
-		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
-		call #nv_wr32
-
-		// next!
-		add b32 $r3 8
-		sub b32 $r1 1
-		bra ne #ctx_mmio_loop
-
-	// set transfer base back to the current context
-	ctx_mmio_done:
-	ld b32 $r3 D[$r0 + #ctx_current]
-	iowr I[$r2 + 0x000] $r3		// MEM_BASE
-
-	// disable the mmio list now, we don't need/want to execute it again
-	st b32 D[$r0 + #chan_mmio_count] $r0
-	mov $r1 #chan_data
-	sethi $r1 0x00060000		// 256 bytes
-	xdst $r0 $r1
-	xdwait
-	ret
-
-// Transfer HUB context data between GPU and storage area
-//
-// In: $r2 channel address
-//     $p1 clear on save, set on load
-//     $p2 set if opposite direction done/will be done, so:
-//		on save it means: "a load will follow this save"
-//		on load it means: "a save preceeded this load"
-//
-ctx_xfer:
-	// according to mwk, some kind of wait for idle
-	mov $r15 0xc00
-	shl b32 $r15 6
-	mov $r14 4
-	iowr I[$r15 + 0x200] $r14
-	ctx_xfer_idle:
-		iord $r14 I[$r15 + 0x000]
-		and $r14 0x2000
-		bra ne #ctx_xfer_idle
-
-	bra not $p1 #ctx_xfer_pre
-	bra $p2 #ctx_xfer_pre_load
-	ctx_xfer_pre:
-		mov $r15 0x10
-		call #ctx_86c
-		bra not $p1 #ctx_xfer_exec
-
-	ctx_xfer_pre_load:
-		mov $r15 2
-		call #ctx_4170s
-		call #ctx_4170w
-		call #ctx_redswitch
-		clear b32 $r15
-		call #ctx_4170s
-		call #ctx_load
-
-	// fetch context pointer, and initiate xfer on all GPCs
-	ctx_xfer_exec:
-	ld b32 $r1 D[$r0 + #ctx_current]
-	mov $r2 0x414
-	shl b32 $r2 6
-	iowr I[$r2 + 0x000] $r0	// BAR_STATUS = reset
-	mov $r14 -0x5b00
-	sethi $r14 0x410000
-	mov b32 $r15 $r1
-	call #nv_wr32		// GPC_BCAST_WRCMD_DATA = ctx pointer
-	add b32 $r14 4
-	xbit $r15 $flags $p1
-	xbit $r2 $flags $p2
-	shl b32 $r2 1
-	or $r15 $r2
-	call #nv_wr32		// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
-
-	// strands
-	mov $r1 0x4afc
-	sethi $r1 0x20000
-	mov $r2 0xc
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
-	call #strand_wait
-	mov $r2 0x47fc
-	sethi $r2 0x20000
-	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
-	xbit $r2 $flags $p1
-	add b32 $r2 3
-	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
-	// mmio context
-	xbit $r10 $flags $p1	// direction
-	or $r10 6		// first, last
-	mov $r11 0		// base = 0
-	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
-	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
-	mov $r14 0		// not multi
-	call #mmctx_xfer
-
-	// wait for GPCs to all complete
-	mov $r10 8		// DONE_BAR
-	call #wait_doneo
-
-	// wait for strand xfer to complete
-	call #strand_wait
-
-	// post-op
-	bra $p1 #ctx_xfer_post
-		mov $r10 12		// DONE_UNK12
-		call #wait_donez
-		mov $r1 0xa10
-		shl b32 $r1 6
-		mov $r2 5
-		iowr I[$r1] $r2		// MEM_CMD
-		ctx_xfer_post_save_wait:
-			iord $r2 I[$r1]
-			or $r2 $r2
-			bra ne #ctx_xfer_post_save_wait
-
-	bra $p2 #ctx_xfer_done
-	ctx_xfer_post:
-		mov $r15 2
-		call #ctx_4170s
-		clear b32 $r15
-		call #ctx_86c
-		call #strand_post
-		call #ctx_4170w
-		clear b32 $r15
-		call #ctx_4170s
-
-		bra not $p1 #ctx_xfer_no_post_mmio
-		ld b32 $r1 D[$r0 + #chan_mmio_count]
-		or $r1 $r1
-		bra e #ctx_xfer_no_post_mmio
-			call #ctx_mmio_exec
-
-		ctx_xfer_no_post_mmio:
-
-	ctx_xfer_done:
-	ret
-
+#include "com.fuc"
+#include "hub.fuc"
 .align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
index e3421af..eb7bc0e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
@@ -1,9 +1,13 @@
 uint32_t nve0_grhub_data[] = {
-/* 0x0000: gpc_count */
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
 	0x00000000,
-/* 0x0004: rop_count */
+/* 0x000c: rop_count */
 	0x00000000,
-/* 0x0008: cmd_queue */
+/* 0x0010: cmd_queue */
 	0x00000000,
 	0x00000000,
 	0x00000000,
@@ -22,200 +26,194 @@
 	0x00000000,
 	0x00000000,
 	0x00000000,
-/* 0x0050: hub_mmio_list_head */
-	0x00000000,
-/* 0x0054: hub_mmio_list_tail */
-	0x00000000,
 /* 0x0058: ctx_current */
 	0x00000000,
-/* 0x005c: chipsets */
-	0x000000e4,
-	0x01440078,
-	0x000000e7,
-	0x01440078,
-	0x000000e6,
-	0x01440078,
 	0x00000000,
-/* 0x0078: nve4_hub_mmio_head */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
 	0x0417e91c,
-	0x04400204,
-	0x18404010,
-	0x204040a8,
-	0x184040d0,
-	0x004040f8,
-	0x08404130,
-	0x08404150,
-	0x00404164,
-	0x0c4041a0,
-	0x0c404200,
-	0x34404404,
-	0x0c404460,
-	0x00404480,
-	0x00404498,
-	0x0c404604,
-	0x0c404618,
-	0x0440462c,
-	0x00404640,
-	0x00404654,
-	0x00404660,
-	0x48404678,
-	0x084046c8,
-	0x08404700,
-	0x24404718,
-	0x04404744,
-	0x00404754,
-	0x00405800,
-	0x08405830,
-	0x00405854,
-	0x0c405870,
-	0x04405a00,
-	0x00405a18,
-	0x00405b00,
-	0x00405b10,
-	0x00406020,
-	0x0c406028,
-	0x044064a8,
-	0x044064b4,
-	0x2c4064c0,
-	0x004064fc,
-	0x00407040,
-	0x00407804,
-	0x1440780c,
-	0x004078bc,
-	0x18408000,
-	0x00408064,
-	0x08408800,
-	0x00408840,
-	0x08408900,
-	0x00408980,
-/* 0x0144: nve4_hub_mmio_tail */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0200: chan_data */
-/* 0x0200: chan_mmio_count */
-	0x00000000,
-/* 0x0204: chan_mmio_address */
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-	0x00000000,
-/* 0x0300: xfer_data */
-	0x00000000,
 };
 
 uint32_t nve0_grhub_code[] = {
-	0x03090ef5,
+	0x031b0ef5,
 /* 0x0004: queue_put */
 	0x9800d898,
 	0x86f001d9,
 	0x0489b808,
 	0xf00c1bf4,
 	0x21f502f7,
-	0x00f802ec,
+	0x00f802fe,
 /* 0x001c: queue_put_next */
 	0xb60798c4,
 	0x8dbb0384,
@@ -247,7 +245,7 @@
 	0xc800bccf,
 	0x1bf41fcc,
 	0x06a7f0fa,
-	0x010321f5,
+	0x010921f5,
 	0xf840bfcf,
 /* 0x008d: nv_wr32 */
 	0x28b7f100,
@@ -269,63 +267,66 @@
 	0x0684b604,
 	0xf80080d0,
 /* 0x00c9: wait_donez */
-	0x3c87f100,
-	0x0684b608,
-	0x99f094bd,
-	0x0089d000,
-	0x081887f1,
-	0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
-	0x87f1008a,
-	0x84b60400,
-	0x0088cf06,
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x07f104bd,
+	0x03f00600,
+	0x000ad002,
+/* 0x00e6: wait_donez_ne */
+	0x87f104bd,
+	0x83f00000,
+	0x0088cf01,
 	0xf4888aff,
-	0x87f1f31b,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00099,
-/* 0x0103: wait_doneo */
-	0xf100f800,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00099f0,
-	0x87f10089,
+	0x94bdf31b,
+	0xf10099f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0109: wait_doneo */
+	0xf094bd00,
+	0x07f10099,
+	0x03f00f00,
+	0x0009d002,
+	0x87f104bd,
 	0x84b60818,
 	0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x0124: wait_doneo_e */
 	0x040087f1,
 	0xcf0684b6,
 	0x8aff0088,
 	0xf30bf488,
-	0x085c87f1,
-	0xbd0684b6,
-	0x0099f094,
-	0xf80089d0,
-/* 0x013d: mmctx_size */
-/* 0x013f: nv_mmctx_size_loop */
-	0x9894bd00,
-	0x85b600e8,
-	0x0180b61a,
-	0xbb0284b6,
-	0xe0b60098,
-	0x04efb804,
-	0xb9eb1bf4,
-	0x00f8029f,
-/* 0x015c: mmctx_xfer */
-	0x083c87f1,
-	0xbd0684b6,
-	0x0199f094,
-	0xf10089d0,
+	0x99f094bd,
+	0x0007f100,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x0147: mmctx_size */
+	0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+	0x00e89894,
+	0xb61a85b6,
+	0x84b60180,
+	0x0098bb02,
+	0xb804e0b6,
+	0x1bf404ef,
+	0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+	0x94bd00f8,
+	0xf10199f0,
+	0xf00f0007,
+	0x09d00203,
+	0xf104bd00,
 	0xb6071087,
 	0x94bd0684,
 	0xf405bbfd,
 	0x8bd0090b,
 	0x0099f000,
-/* 0x0180: mmctx_base_disabled */
+/* 0x018c: mmctx_base_disabled */
 	0xf405eefd,
 	0x8ed00c0b,
 	0xc08fd080,
-/* 0x018f: mmctx_multi_disabled */
+/* 0x019b: mmctx_multi_disabled */
 	0xb70199f0,
 	0xc8010080,
 	0xb4b600ab,
@@ -333,8 +334,8 @@
 	0xb601aec8,
 	0xbefd11e4,
 	0x008bd005,
-/* 0x01a8: mmctx_exec_loop */
-/* 0x01a8: mmctx_wait_free */
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
 	0xf0008ecf,
 	0x0bf41fe4,
 	0x00ce98fa,
@@ -343,76 +344,77 @@
 	0x04cdb804,
 	0xc8e81bf4,
 	0x1bf402ab,
-/* 0x01c9: mmctx_fini_wait */
+/* 0x01d5: mmctx_fini_wait */
 	0x008bcf18,
 	0xb01fb4f0,
 	0x1bf410b4,
 	0x02a7f0f7,
 	0xf4c921f4,
-/* 0x01de: mmctx_stop */
+/* 0x01ea: mmctx_stop */
 	0xabc81b0e,
 	0x10b4b600,
 	0xf00cb9f0,
 	0x8bd012b9,
-/* 0x01ed: mmctx_stop_wait */
+/* 0x01f9: mmctx_stop_wait */
 	0x008bcf00,
 	0xf412bbc8,
-/* 0x01f6: mmctx_done */
-	0x87f1fa1b,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00199,
-/* 0x0207: strand_wait */
-	0xf900f800,
-	0x02a7f0a0,
-	0xfcc921f4,
-/* 0x0213: strand_pre */
-	0xf100f8a0,
-	0xf04afc87,
-	0x97f00283,
-	0x0089d00c,
-	0x020721f5,
-/* 0x0226: strand_post */
-	0x87f100f8,
-	0x83f04afc,
-	0x0d97f002,
-	0xf50089d0,
-	0xf8020721,
-/* 0x0239: strand_set */
-	0xfca7f100,
-	0x02a3f04f,
-	0x0500aba2,
-	0xd00fc7f0,
-	0xc7f000ac,
-	0x00bcd00b,
-	0x020721f5,
-	0xf000aed0,
-	0xbcd00ac7,
-	0x0721f500,
-/* 0x0263: strand_ctx_init */
-	0xf100f802,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00399f0,
+/* 0x0202: mmctx_done */
+	0x94bdfa1b,
+	0xf10199f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0215: strand_wait */
+	0xf0a0f900,
+	0x21f402a7,
+	0xf8a0fcc9,
+/* 0x0221: strand_pre */
+	0xfc87f100,
+	0x0283f04a,
+	0xd00c97f0,
 	0x21f50089,
-	0xe7f00213,
-	0x3921f503,
+	0x00f80215,
+/* 0x0234: strand_post */
+	0x4afc87f1,
+	0xf00283f0,
+	0x89d00d97,
+	0x1521f500,
+/* 0x0247: strand_set */
+	0xf100f802,
+	0xf04ffca7,
+	0xaba202a3,
+	0xc7f00500,
+	0x00acd00f,
+	0xd00bc7f0,
+	0x21f500bc,
+	0xaed00215,
+	0x0ac7f000,
+	0xf500bcd0,
+	0xf8021521,
+/* 0x0271: strand_ctx_init */
+	0xf094bd00,
+	0x07f10399,
+	0x03f00f00,
+	0x0009d002,
+	0x21f504bd,
+	0xe7f00221,
+	0x4721f503,
 	0xfca7f102,
 	0x02a3f046,
 	0x0400aba0,
 	0xf040a0d0,
 	0xbcd001c7,
-	0x0721f500,
+	0x1521f500,
 	0x010c9202,
 	0xf000acd0,
 	0xbcd002c7,
-	0x0721f500,
-	0x2621f502,
+	0x1521f500,
+	0x3421f502,
 	0x8087f102,
 	0x0684b608,
 	0xb70089cf,
 	0x95220080,
-/* 0x02ba: ctx_init_strand_loop */
+/* 0x02ca: ctx_init_strand_loop */
 	0x8ed008fe,
 	0x408ed000,
 	0xb6808acf,
@@ -421,73 +423,61 @@
 	0xb60480b6,
 	0x1bf40192,
 	0x08e4b6e8,
-	0xf1f2efbc,
-	0xb6085c87,
-	0x94bd0684,
-	0xd00399f0,
-	0x00f80089,
-/* 0x02ec: error */
-	0xe7f1e0f9,
-	0xe4b60814,
-	0x00efd006,
-	0x0c1ce7f1,
-	0xf006e4b6,
-	0xefd001f7,
-	0xf8e0fc00,
-/* 0x0309: init */
-	0xfe04bd00,
-	0x07fe0004,
-	0x0017f100,
-	0x0227f012,
-	0xf10012d0,
-	0xfe05b917,
-	0x17f10010,
-	0x10d00400,
-	0x0437f1c0,
-	0x0634b604,
-	0x200327f1,
-	0xf10032d0,
-	0xd0200427,
-	0x27f10132,
-	0x32d0200b,
-	0x0c27f102,
-	0x0732d020,
-	0x0c2427f1,
-	0xb90624b6,
-	0x23d00003,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x02fe: error */
+	0x07f100f8,
+	0x03f00500,
+	0x000fd002,
+	0xf7f004bd,
+	0x0007f101,
+	0x0303f007,
+	0xbd000fd0,
+/* 0x031b: init */
+	0xbd00f804,
+	0x0004fe04,
+	0xf10007fe,
+	0xf0120017,
+	0x12d00227,
+	0xb117f100,
+	0x0010fe05,
+	0x040017f1,
+	0xf1c010d0,
+	0xb6040437,
+	0x27f10634,
+	0x32d02003,
 	0x0427f100,
-	0x0023f087,
-	0xb70012d0,
-	0xf0010012,
-	0x12d00427,
-	0x1031f400,
-	0x9604e7f1,
-	0xf440e3f0,
-	0xf1c76821,
-	0x01018090,
-	0x801ff4f0,
-	0x17f0000f,
-	0x041fbb01,
-	0xf10112b6,
-	0xb6040c27,
-	0x21d00624,
-	0x4021d000,
-	0x080027f1,
-	0xcf0624b6,
-	0xf7f00022,
-/* 0x03a9: init_find_chipset */
-	0x08f0b654,
-	0xb800f398,
-	0x0bf40432,
-	0x0034b00b,
-	0xf8f11bf4,
-/* 0x03bd: init_context */
-	0x0017f100,
-	0x02fe5801,
-	0xf003ff58,
-	0x0e8000e3,
-	0x150f8014,
-	0x013d21f5,
+	0x0132d020,
+	0x200b27f1,
+	0xf10232d0,
+	0xd0200c27,
+	0x27f10732,
+	0x24b60c24,
+	0x0003b906,
+	0xf10023d0,
+	0xf0870427,
+	0x12d00023,
+	0x0012b700,
+	0x0427f001,
+	0xf40012d0,
+	0xe7f11031,
+	0xe3f09604,
+	0x6821f440,
+	0x8090f1c7,
+	0xf4f00301,
+	0x020f801f,
+	0xbb0117f0,
+	0x12b6041f,
+	0x0c27f101,
+	0x0624b604,
+	0xd00021d0,
+	0x17f14021,
+	0x0e980100,
+	0x010f9800,
+	0x014721f5,
 	0x070037f1,
 	0x950634b6,
 	0x34d00814,
@@ -498,196 +488,201 @@
 	0x0815b600,
 	0xb60110b6,
 	0x1fb90814,
-	0x6321f502,
+	0x7121f502,
 	0x001fbb02,
-	0xf1000398,
+	0xf1020398,
 	0xf0200047,
-/* 0x040e: init_gpc */
+/* 0x03f6: init_gpc */
 	0x4ea05043,
 	0x1fb90804,
 	0x8d21f402,
-	0x08004ea0,
-	0xf4022fb9,
+	0x010c4ea0,
+	0x21f4f4bd,
+	0x044ea08d,
+	0x8d21f401,
+	0x01004ea0,
+	0xf402f7f0,
 	0x4ea08d21,
-	0xf4bd010c,
-	0xa08d21f4,
-	0xf401044e,
-	0x4ea08d21,
-	0xf7f00100,
-	0x8d21f402,
-	0x08004ea0,
-/* 0x0440: init_gpc_wait */
-	0xc86821f4,
-	0x0bf41fff,
-	0x044ea0fa,
-	0x6821f408,
-	0xb7001fbb,
-	0xb6800040,
-	0x1bf40132,
-	0x0027f1b4,
-	0x0624b608,
-	0xb74021d0,
-	0xbd080020,
+/* 0x041e: init_gpc_wait */
+	0x21f40800,
+	0x1fffc868,
+	0xa0fa0bf4,
+	0xf408044e,
+	0x1fbb6821,
+	0x0040b700,
+	0x0132b680,
+	0xf1be1bf4,
+	0xf0010007,
+	0x01d00203,
+	0xbd04bd00,
 	0x1f19f014,
-/* 0x0473: main */
-	0xf40021d0,
-	0x28f40031,
-	0x08d7f000,
-	0xf43921f4,
-	0xe4b1f401,
-	0x1bf54001,
-	0x87f100d1,
-	0x84b6083c,
-	0xf094bd06,
-	0x89d00499,
-	0x0017f100,
-	0x0614b60b,
-	0xcf4012cf,
-	0x13c80011,
-	0x7e0bf41f,
+	0x080007f1,
+	0xd00203f0,
+	0x04bd0001,
+/* 0x0458: main */
+	0xf40031f4,
+	0xd7f00028,
+	0x3921f410,
+	0xb1f401f4,
+	0xf54001e4,
+	0xbd00de1b,
+	0x0499f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x0b0017f1,
+	0xcf0614b6,
+	0x11cf4012,
+	0x1f13c800,
+	0x00870bf5,
 	0xf41f23c8,
-	0x20f95a0b,
-	0xf10212b9,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00799f0,
-	0x32f40089,
-	0x0231f401,
-	0x07fb21f5,
-	0x085c87f1,
-	0xbd0684b6,
+	0x20f9620b,
+	0xbd0212b9,
 	0x0799f094,
-	0xfc0089d0,
-	0x3c87f120,
-	0x0684b608,
-	0x99f094bd,
-	0x0089d006,
-	0xf50131f4,
-	0xf107fb21,
-	0xb6085c87,
-	0x94bd0684,
-	0xd00699f0,
-	0x0ef40089,
-/* 0x0509: chsw_prev_no_next */
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xf40132f4,
+	0x21f50231,
+	0x94bd0801,
+	0xf10799f0,
+	0xf0170007,
+	0x09d00203,
+	0xfc04bd00,
+	0xf094bd20,
+	0x07f10699,
+	0x03f00f00,
+	0x0009d002,
+	0x31f404bd,
+	0x0121f501,
+	0xf094bd08,
+	0x07f10699,
+	0x03f01700,
+	0x0009d002,
+	0x0ef404bd,
+/* 0x04f9: chsw_prev_no_next */
 	0xb920f931,
 	0x32f40212,
 	0x0232f401,
-	0x07fb21f5,
+	0x080121f5,
 	0x17f120fc,
 	0x14b60b00,
 	0x0012d006,
-/* 0x0527: chsw_no_prev */
+/* 0x0517: chsw_no_prev */
 	0xc8130ef4,
 	0x0bf41f23,
 	0x0131f40d,
 	0xf50232f4,
-/* 0x0537: chsw_done */
-	0xf107fb21,
+/* 0x0527: chsw_done */
+	0xf1080121,
 	0xb60b0c17,
 	0x27f00614,
 	0x0012d001,
-	0x085c87f1,
-	0xbd0684b6,
-	0x0499f094,
-	0xf50089d0,
-/* 0x0557: main_not_ctx_switch */
-	0xb0ff200e,
-	0x1bf401e4,
-	0x02f2b90d,
-	0x078f21f5,
-/* 0x0567: main_not_ctx_chan */
-	0xb0420ef4,
-	0x1bf402e4,
-	0x3c87f12e,
-	0x0684b608,
 	0x99f094bd,
-	0x0089d007,
+	0x0007f104,
+	0x0203f017,
+	0xbd0009d0,
+	0x130ef504,
+/* 0x0549: main_not_ctx_switch */
+	0x01e4b0ff,
+	0xb90d1bf4,
+	0x21f502f2,
+	0x0ef40795,
+/* 0x0559: main_not_ctx_chan */
+	0x02e4b046,
+	0xbd321bf4,
+	0x0799f094,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
 	0xf40132f4,
 	0x21f50232,
-	0x87f107fb,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00799,
-	0x110ef400,
-/* 0x0598: main_not_ctx_save */
-	0xf010ef94,
-	0x21f501f5,
-	0x0ef502ec,
-/* 0x05a6: main_done */
-	0x17f1fed1,
-	0x14b60820,
-	0xf024bd06,
-	0x12d01f29,
-	0xbe0ef500,
-/* 0x05b9: ih */
+	0x94bd0801,
+	0xf10799f0,
+	0xf0170007,
+	0x09d00203,
+	0xf404bd00,
+/* 0x058e: main_not_ctx_save */
+	0xef94110e,
+	0x01f5f010,
+	0x02fe21f5,
+	0xfec00ef5,
+/* 0x059c: main_done */
+	0x29f024bd,
+	0x0007f11f,
+	0x0203f008,
+	0xbd0002d0,
+	0xab0ef504,
+/* 0x05b1: ih */
 	0xfe80f9fe,
 	0x80f90188,
 	0xa0f990f9,
 	0xd0f9b0f9,
 	0xf0f9e0f9,
-	0xc4800acf,
-	0x0bf404ab,
-	0x00b7f11d,
-	0x08d7f019,
-	0xcf40becf,
-	0x21f400bf,
-	0x00b0b704,
-	0x01e7f004,
-/* 0x05ef: ih_no_fifo */
-	0xe400bed0,
-	0xf40100ab,
-	0xd7f00d0b,
-	0x01e7f108,
-	0x0421f440,
-/* 0x0600: ih_no_ctxsw */
-	0x0104b7f1,
-	0xabffb0bd,
-	0x0d0bf4b4,
-	0x0c1ca7f1,
-	0xd006a4b6,
-/* 0x0616: ih_no_other */
-	0x0ad000ab,
-	0xfcf0fc40,
-	0xfcd0fce0,
-	0xfca0fcb0,
-	0xfe80fc90,
-	0x80fc0088,
-	0xf80032f4,
-/* 0x0631: ctx_4170s */
-	0x70e7f101,
-	0x40e3f041,
-	0xf410f5f0,
+	0x0acf04bd,
+	0x04abc480,
+	0xf11d0bf4,
+	0xf01900b7,
+	0xbecf10d7,
+	0x00bfcf40,
+	0xb70421f4,
+	0xf00400b0,
+	0xbed001e7,
+/* 0x05e9: ih_no_fifo */
+	0x00abe400,
+	0x0d0bf401,
+	0xf110d7f0,
+	0xf44001e7,
+/* 0x05fa: ih_no_ctxsw */
+	0xb7f10421,
+	0xb0bd0104,
+	0xf4b4abff,
+	0xa7f10d0b,
+	0xa4b60c1c,
+	0x00abd006,
+/* 0x0610: ih_no_other */
+	0xfc400ad0,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x062b: ctx_4170s */
+	0xf101f800,
+	0xf04170e7,
+	0xf5f040e3,
+	0x8d21f410,
+/* 0x063a: ctx_4170w */
+	0xe7f100f8,
+	0xe3f04170,
+	0x6821f440,
+	0xf410f4f0,
+	0x00f8f31b,
+/* 0x064c: ctx_redswitch */
+	0x0614e7f1,
+	0xf106e4b6,
+	0xd00270f7,
+	0xf7f000ef,
+/* 0x065d: ctx_redswitch_delay */
+	0x01f2b608,
+	0xf1fd1bf4,
+	0xd00770f7,
+	0x00f800ef,
+/* 0x066c: ctx_86c */
+	0x086ce7f1,
+	0xd006e4b6,
+	0xe7f100ef,
+	0xe3f08a14,
+	0x8d21f440,
+	0xa86ce7f1,
+	0xf441e3f0,
 	0x00f88d21,
-/* 0x0640: ctx_4170w */
-	0x4170e7f1,
-	0xf440e3f0,
-	0xf4f06821,
-	0xf31bf410,
-/* 0x0652: ctx_redswitch */
-	0xe7f100f8,
-	0xe4b60614,
-	0x70f7f106,
-	0x00efd002,
-/* 0x0663: ctx_redswitch_delay */
-	0xb608f7f0,
-	0x1bf401f2,
-	0x70f7f1fd,
-	0x00efd007,
-/* 0x0672: ctx_86c */
-	0xe7f100f8,
-	0xe4b6086c,
-	0x00efd006,
-	0x8a14e7f1,
-	0xf440e3f0,
-	0xe7f18d21,
-	0xe3f0a86c,
-	0x8d21f441,
-/* 0x0692: ctx_load */
-	0x87f100f8,
-	0x84b6083c,
-	0xf094bd06,
-	0x89d00599,
-	0x0ca7f000,
+/* 0x068c: ctx_load */
+	0x99f094bd,
+	0x0007f105,
+	0x0203f00f,
+	0xbd0009d0,
+	0x0ca7f004,
 	0xf1c921f4,
 	0xb60a2417,
 	0x10d00614,
@@ -697,162 +692,227 @@
 	0xb60a0c17,
 	0x47f00614,
 	0x0012d007,
-/* 0x06cb: ctx_chan_wait_0 */
+/* 0x06c7: ctx_chan_wait_0 */
 	0xcf4014d0,
 	0x44f04014,
 	0xfa1bf41f,
 	0xfe0032d0,
 	0x2af0000b,
 	0x0424b61f,
-	0xf10220b6,
-	0xb6083c87,
-	0x94bd0684,
-	0xd00899f0,
-	0x17f10089,
-	0x14b60a04,
-	0x0012d006,
-	0x0a2017f1,
-	0xf00614b6,
-	0x23f10227,
-	0x12d08000,
-	0x1017f000,
-	0x030027f1,
-	0xfa0223f0,
-	0x03f80512,
-	0x085c87f1,
-	0xbd0684b6,
+	0xbd0220b6,
 	0x0899f094,
-	0x980089d0,
-	0x14b6c101,
-	0xc0029818,
+	0x0f0007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x0a0417f1,
+	0xd00614b6,
+	0x17f10012,
+	0x14b60a20,
+	0x0227f006,
+	0x800023f1,
+	0xf00012d0,
+	0x27f11017,
+	0x23f00200,
+	0x0512fa02,
+	0x94bd03f8,
+	0xf10899f0,
+	0xf0170007,
+	0x09d00203,
+	0x9804bd00,
+	0x14b68101,
+	0x80029818,
 	0xfd0825b6,
 	0x01800512,
-	0x3c87f116,
-	0x0684b608,
-	0x99f094bd,
-	0x0089d009,
-	0x0a0427f1,
-	0xd00624b6,
-	0x27f00021,
-	0x2017f101,
-	0x0614b60a,
-	0xf10012d0,
-	0xf0020017,
+	0xf094bd16,
+	0x07f10999,
+	0x03f00f00,
+	0x0009d002,
+	0x27f104bd,
+	0x24b60a04,
+	0x0021d006,
+	0xf10127f0,
+	0xb60a2017,
+	0x12d00614,
+	0x0017f100,
+	0x0613f001,
+	0xf80501fa,
+	0xf094bd03,
+	0x07f10999,
+	0x03f01700,
+	0x0009d002,
+	0x94bd04bd,
+	0xf10599f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0795: ctx_chan */
+	0x8c21f500,
+	0x0ca7f006,
+	0xf1c921f4,
+	0xb60a1017,
+	0x27f00614,
+	0x0012d005,
+/* 0x07ac: ctx_chan_wait */
+	0xfd0012cf,
+	0x1bf40522,
+/* 0x07b7: ctx_mmio_exec */
+	0x9800f8fa,
+	0x27f14103,
+	0x24b60a04,
+	0x0023d006,
+/* 0x07c6: ctx_mmio_loop */
+	0x34c434bd,
+	0x0f1bf4ff,
+	0x020057f1,
+	0xfa0653f0,
+	0x03f80535,
+/* 0x07d8: ctx_mmio_pull */
+	0x98804e98,
+	0x21f4814f,
+	0x0830b68d,
+	0xf40112b6,
+/* 0x07ea: ctx_mmio_done */
+	0x0398df1b,
+	0x0023d016,
+	0xf1400080,
+	0xf0010017,
 	0x01fa0613,
-	0xf103f805,
-	0xb6085c87,
-	0x94bd0684,
-	0xd00999f0,
-	0x87f10089,
-	0x84b6085c,
-	0xf094bd06,
-	0x89d00599,
-/* 0x078f: ctx_chan */
-	0xf500f800,
-	0xf0069221,
-	0x21f40ca7,
-	0x1017f1c9,
-	0x0614b60a,
-	0xd00527f0,
-/* 0x07a6: ctx_chan_wait */
-	0x12cf0012,
-	0x0522fd00,
-	0xf8fa1bf4,
-/* 0x07b1: ctx_mmio_exec */
-	0x81039800,
-	0x0a0427f1,
+	0xf803f806,
+/* 0x0801: ctx_xfer */
+	0x00f7f100,
+	0x06f4b60c,
+	0xd004e7f0,
+/* 0x080e: ctx_xfer_idle */
+	0xfecf80fe,
+	0x00e4f100,
+	0xf91bf420,
+	0xf40611f4,
+/* 0x081e: ctx_xfer_pre */
+	0xf7f00d02,
+	0x6c21f510,
+	0x1c11f406,
+/* 0x0828: ctx_xfer_pre_load */
+	0xf502f7f0,
+	0xf5062b21,
+	0xf5063a21,
+	0xbd064c21,
+	0x2b21f5f4,
+	0x8c21f506,
+/* 0x0841: ctx_xfer_exec */
+	0x16019806,
+	0x041427f1,
 	0xd00624b6,
-	0x34bd0023,
-/* 0x07c0: ctx_mmio_loop */
-	0xf4ff34c4,
-	0x57f10f1b,
-	0x53f00300,
-	0x0535fa06,
-/* 0x07d2: ctx_mmio_pull */
-	0x4e9803f8,
-	0xc14f98c0,
+	0xe7f10020,
+	0xe3f0a500,
+	0x021fb941,
 	0xb68d21f4,
-	0x12b60830,
-	0xdf1bf401,
-/* 0x07e4: ctx_mmio_done */
-	0xd0160398,
-	0x00800023,
-	0x0017f180,
-	0x0613f002,
-	0xf80601fa,
-/* 0x07fb: ctx_xfer */
-	0xf100f803,
-	0xb60c00f7,
-	0xe7f006f4,
-	0x80fed004,
-/* 0x0808: ctx_xfer_idle */
-	0xf100fecf,
-	0xf42000e4,
-	0x11f4f91b,
-	0x0d02f406,
-/* 0x0818: ctx_xfer_pre */
-	0xf510f7f0,
-	0xf4067221,
-/* 0x0822: ctx_xfer_pre_load */
-	0xf7f01c11,
-	0x3121f502,
-	0x4021f506,
-	0x5221f506,
+	0xfcf004e0,
+	0x022cf001,
+	0xfd0124b6,
+	0x21f405f2,
+	0xfc17f18d,
+	0x0213f04a,
+	0xd00c27f0,
+	0x21f50012,
+	0x27f10215,
+	0x23f047fc,
+	0x0020d002,
+	0xb6012cf0,
+	0x12d00320,
+	0x01acf000,
+	0xf006a5f0,
+	0x0c9800b7,
+	0x010d9800,
+	0xf500e7f0,
+	0xf0016621,
+	0x21f508a7,
+	0x21f50109,
+	0x01f40215,
+	0x0ca7f022,
+	0xf1c921f4,
+	0xb60a1017,
+	0x27f00614,
+	0x0012d005,
+/* 0x08c8: ctx_xfer_post_save_wait */
+	0xfd0012cf,
+	0x1bf40522,
+	0x2e02f4fa,
+/* 0x08d4: ctx_xfer_post */
+	0xf502f7f0,
+	0xbd062b21,
+	0x6c21f5f4,
+	0x3421f506,
+	0x3a21f502,
 	0xf5f4bd06,
-	0xf5063121,
-/* 0x083b: ctx_xfer_exec */
-	0x98069221,
-	0x27f11601,
-	0x24b60414,
-	0x0020d006,
-	0xa500e7f1,
-	0xb941e3f0,
-	0x21f4021f,
-	0x04e0b68d,
-	0xf001fcf0,
-	0x24b6022c,
-	0x05f2fd01,
-	0xf18d21f4,
-	0xf04afc17,
-	0x27f00213,
-	0x0012d00c,
-	0x020721f5,
-	0x47fc27f1,
-	0xd00223f0,
-	0x2cf00020,
-	0x0320b601,
-	0xf00012d0,
-	0xa5f001ac,
-	0x00b7f006,
-	0x98140c98,
-	0xe7f0150d,
-	0x5c21f500,
-	0x08a7f001,
-	0x010321f5,
-	0x020721f5,
-	0xf02201f4,
-	0x21f40ca7,
-	0x1017f1c9,
-	0x0614b60a,
-	0xd00527f0,
-/* 0x08c2: ctx_xfer_post_save_wait */
-	0x12cf0012,
-	0x0522fd00,
-	0xf4fa1bf4,
-/* 0x08ce: ctx_xfer_post */
-	0xf7f02e02,
-	0x3121f502,
-	0xf5f4bd06,
-	0xf5067221,
-	0xf5022621,
-	0xbd064021,
-	0x3121f5f4,
-	0x1011f406,
-	0xfd800198,
-	0x0bf40511,
-	0xb121f507,
-/* 0x08f9: ctx_xfer_no_post_mmio */
-/* 0x08f9: ctx_xfer_done */
-	0x0000f807,
+	0xf4062b21,
+	0x01981011,
+	0x0511fd40,
+	0xf5070bf4,
+/* 0x08ff: ctx_xfer_no_post_mmio */
+/* 0x08ff: ctx_xfer_done */
+	0xf807b721,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
 	0x00000000,
 };
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc
new file mode 100644
index 0000000..ec42ed2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK110
+#include "macros.fuc"
+
+.section #nvf0_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #nvf0_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
new file mode 100644
index 0000000..438506d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
@@ -0,0 +1,918 @@
+uint32_t nvf0_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+	0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+	0x00000304,
+/* 0x0008: gpc_count */
+	0x00000000,
+/* 0x000c: rop_count */
+	0x00000000,
+/* 0x0010: cmd_queue */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0058: ctx_current */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+	0x00000000,
+/* 0x0104: chan_mmio_address */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0200: xfer_data */
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+/* 0x0300: hub_mmio_list_base */
+	0x0417e91c,
+};
+
+uint32_t nvf0_grhub_code[] = {
+	0x031b0ef5,
+/* 0x0004: queue_put */
+	0x9800d898,
+	0x86f001d9,
+	0x0489b808,
+	0xf00c1bf4,
+	0x21f502f7,
+	0x00f802fe,
+/* 0x001c: queue_put_next */
+	0xb60798c4,
+	0x8dbb0384,
+	0x0880b600,
+	0x80008e80,
+	0x90b6018f,
+	0x0f94f001,
+	0xf801d980,
+/* 0x0039: queue_get */
+	0x0131f400,
+	0x9800d898,
+	0x89b801d9,
+	0x210bf404,
+	0xb60789c4,
+	0x9dbb0394,
+	0x0890b600,
+	0x98009e98,
+	0x80b6019f,
+	0x0f84f001,
+	0xf400d880,
+/* 0x0066: queue_get_done */
+	0x00f80132,
+/* 0x0068: nv_rd32 */
+	0x0728b7f1,
+	0xb906b4b6,
+	0xc9f002ec,
+	0x00bcd01f,
+/* 0x0078: nv_rd32_wait */
+	0xc800bccf,
+	0x1bf41fcc,
+	0x06a7f0fa,
+	0x010921f5,
+	0xf840bfcf,
+/* 0x008d: nv_wr32 */
+	0x28b7f100,
+	0x06b4b607,
+	0xb980bfd0,
+	0xc9f002ec,
+	0x1ec9f01f,
+/* 0x00a3: nv_wr32_wait */
+	0xcf00bcd0,
+	0xccc800bc,
+	0xfa1bf41f,
+/* 0x00ae: watchdog_reset */
+	0x87f100f8,
+	0x84b60430,
+	0x1ff9f006,
+	0xf8008fd0,
+/* 0x00bd: watchdog_clear */
+	0x3087f100,
+	0x0684b604,
+	0xf80080d0,
+/* 0x00c9: wait_donez */
+	0xf094bd00,
+	0x07f10099,
+	0x03f03700,
+	0x0009d002,
+	0x07f104bd,
+	0x03f00600,
+	0x000ad002,
+/* 0x00e6: wait_donez_ne */
+	0x87f104bd,
+	0x83f00000,
+	0x0088cf01,
+	0xf4888aff,
+	0x94bdf31b,
+	0xf10099f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0109: wait_doneo */
+	0xf094bd00,
+	0x07f10099,
+	0x03f03700,
+	0x0009d002,
+	0x87f104bd,
+	0x84b60818,
+	0x008ad006,
+/* 0x0124: wait_doneo_e */
+	0x040087f1,
+	0xcf0684b6,
+	0x8aff0088,
+	0xf30bf488,
+	0x99f094bd,
+	0x0007f100,
+	0x0203f017,
+	0xbd0009d0,
+/* 0x0147: mmctx_size */
+	0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+	0x00e89894,
+	0xb61a85b6,
+	0x84b60180,
+	0x0098bb02,
+	0xb804e0b6,
+	0x1bf404ef,
+	0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+	0x94bd00f8,
+	0xf10199f0,
+	0xf0370007,
+	0x09d00203,
+	0xf104bd00,
+	0xb6071087,
+	0x94bd0684,
+	0xf405bbfd,
+	0x8bd0090b,
+	0x0099f000,
+/* 0x018c: mmctx_base_disabled */
+	0xf405eefd,
+	0x8ed00c0b,
+	0xc08fd080,
+/* 0x019b: mmctx_multi_disabled */
+	0xb70199f0,
+	0xc8010080,
+	0xb4b600ab,
+	0x0cb9f010,
+	0xb601aec8,
+	0xbefd11e4,
+	0x008bd005,
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
+	0xf0008ecf,
+	0x0bf41fe4,
+	0x00ce98fa,
+	0xd005e9fd,
+	0xc0b6c08e,
+	0x04cdb804,
+	0xc8e81bf4,
+	0x1bf402ab,
+/* 0x01d5: mmctx_fini_wait */
+	0x008bcf18,
+	0xb01fb4f0,
+	0x1bf410b4,
+	0x02a7f0f7,
+	0xf4c921f4,
+/* 0x01ea: mmctx_stop */
+	0xabc81b0e,
+	0x10b4b600,
+	0xf00cb9f0,
+	0x8bd012b9,
+/* 0x01f9: mmctx_stop_wait */
+	0x008bcf00,
+	0xf412bbc8,
+/* 0x0202: mmctx_done */
+	0x94bdfa1b,
+	0xf10199f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0215: strand_wait */
+	0xf0a0f900,
+	0x21f402a7,
+	0xf8a0fcc9,
+/* 0x0221: strand_pre */
+	0xfc87f100,
+	0x0283f04a,
+	0xd00c97f0,
+	0x21f50089,
+	0x00f80215,
+/* 0x0234: strand_post */
+	0x4afc87f1,
+	0xf00283f0,
+	0x89d00d97,
+	0x1521f500,
+/* 0x0247: strand_set */
+	0xf100f802,
+	0xf04ffca7,
+	0xaba202a3,
+	0xc7f00500,
+	0x00acd00f,
+	0xd00bc7f0,
+	0x21f500bc,
+	0xaed00215,
+	0x0ac7f000,
+	0xf500bcd0,
+	0xf8021521,
+/* 0x0271: strand_ctx_init */
+	0xf094bd00,
+	0x07f10399,
+	0x03f03700,
+	0x0009d002,
+	0x21f504bd,
+	0xe7f00221,
+	0x4721f503,
+	0xfca7f102,
+	0x02a3f046,
+	0x0400aba0,
+	0xf040a0d0,
+	0xbcd001c7,
+	0x1521f500,
+	0x010c9202,
+	0xf000acd0,
+	0xbcd002c7,
+	0x1521f500,
+	0x3421f502,
+	0x8087f102,
+	0x0684b608,
+	0xb70089cf,
+	0x95220080,
+/* 0x02ca: ctx_init_strand_loop */
+	0x8ed008fe,
+	0x408ed000,
+	0xb6808acf,
+	0xa0b606a5,
+	0x00eabb01,
+	0xb60480b6,
+	0x1bf40192,
+	0x08e4b6e8,
+	0xbdf2efbc,
+	0x0399f094,
+	0x170007f1,
+	0xd00203f0,
+	0x04bd0009,
+/* 0x02fe: error */
+	0x07f100f8,
+	0x03f00500,
+	0x000fd002,
+	0xf7f004bd,
+	0x0007f101,
+	0x0303f007,
+	0xbd000fd0,
+/* 0x031b: init */
+	0xbd00f804,
+	0x0004fe04,
+	0xf10007fe,
+	0xf0120017,
+	0x12d00227,
+	0xb117f100,
+	0x0010fe05,
+	0x040017f1,
+	0xf1c010d0,
+	0xb6040437,
+	0x27f10634,
+	0x32d02003,
+	0x0427f100,
+	0x0132d020,
+	0x200b27f1,
+	0xf10232d0,
+	0xd0200c27,
+	0x27f10732,
+	0x24b60c24,
+	0x0003b906,
+	0xf10023d0,
+	0xf0870427,
+	0x12d00023,
+	0x0012b700,
+	0x0427f001,
+	0xf40012d0,
+	0xe7f11031,
+	0xe3f09604,
+	0x6821f440,
+	0x8090f1c7,
+	0xf4f00301,
+	0x020f801f,
+	0xbb0117f0,
+	0x12b6041f,
+	0x0c27f101,
+	0x0624b604,
+	0xd00021d0,
+	0x17f14021,
+	0x0e980100,
+	0x010f9800,
+	0x014721f5,
+	0x070037f1,
+	0x950634b6,
+	0x34d00814,
+	0x4034d000,
+	0x130030b7,
+	0xb6001fbb,
+	0x3fd002f5,
+	0x0815b600,
+	0xb60110b6,
+	0x1fb90814,
+	0x7121f502,
+	0x001fbb02,
+	0xf1020398,
+	0xf0200047,
+/* 0x03f6: init_gpc */
+	0x4ea05043,
+	0x1fb90804,
+	0x8d21f402,
+	0x010c4ea0,
+	0x21f4f4bd,
+	0x044ea08d,
+	0x8d21f401,
+	0x01004ea0,
+	0xf402f7f0,
+	0x4ea08d21,
+/* 0x041e: init_gpc_wait */
+	0x21f40800,
+	0x1fffc868,
+	0xa0fa0bf4,
+	0xf408044e,
+	0x1fbb6821,
+	0x0040b700,
+	0x0132b680,
+	0xf1be1bf4,
+	0xf0010007,
+	0x01d00203,
+	0xbd04bd00,
+	0x1f19f014,
+	0x300007f1,
+	0xd00203f0,
+	0x04bd0001,
+/* 0x0458: main */
+	0xf40031f4,
+	0xd7f00028,
+	0x3921f410,
+	0xb1f401f4,
+	0xf54001e4,
+	0xbd00de1b,
+	0x0499f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x0b0017f1,
+	0xcf0614b6,
+	0x11cf4012,
+	0x1f13c800,
+	0x00870bf5,
+	0xf41f23c8,
+	0x20f9620b,
+	0xbd0212b9,
+	0x0799f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xf40132f4,
+	0x21f50231,
+	0x94bd0801,
+	0xf10799f0,
+	0xf0170007,
+	0x09d00203,
+	0xfc04bd00,
+	0xf094bd20,
+	0x07f10699,
+	0x03f03700,
+	0x0009d002,
+	0x31f404bd,
+	0x0121f501,
+	0xf094bd08,
+	0x07f10699,
+	0x03f01700,
+	0x0009d002,
+	0x0ef404bd,
+/* 0x04f9: chsw_prev_no_next */
+	0xb920f931,
+	0x32f40212,
+	0x0232f401,
+	0x080121f5,
+	0x17f120fc,
+	0x14b60b00,
+	0x0012d006,
+/* 0x0517: chsw_no_prev */
+	0xc8130ef4,
+	0x0bf41f23,
+	0x0131f40d,
+	0xf50232f4,
+/* 0x0527: chsw_done */
+	0xf1080121,
+	0xb60b0c17,
+	0x27f00614,
+	0x0012d001,
+	0x99f094bd,
+	0x0007f104,
+	0x0203f017,
+	0xbd0009d0,
+	0x130ef504,
+/* 0x0549: main_not_ctx_switch */
+	0x01e4b0ff,
+	0xb90d1bf4,
+	0x21f502f2,
+	0x0ef40795,
+/* 0x0559: main_not_ctx_chan */
+	0x02e4b046,
+	0xbd321bf4,
+	0x0799f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0xf40132f4,
+	0x21f50232,
+	0x94bd0801,
+	0xf10799f0,
+	0xf0170007,
+	0x09d00203,
+	0xf404bd00,
+/* 0x058e: main_not_ctx_save */
+	0xef94110e,
+	0x01f5f010,
+	0x02fe21f5,
+	0xfec00ef5,
+/* 0x059c: main_done */
+	0x29f024bd,
+	0x0007f11f,
+	0x0203f030,
+	0xbd0002d0,
+	0xab0ef504,
+/* 0x05b1: ih */
+	0xfe80f9fe,
+	0x80f90188,
+	0xa0f990f9,
+	0xd0f9b0f9,
+	0xf0f9e0f9,
+	0x0acf04bd,
+	0x04abc480,
+	0xf11d0bf4,
+	0xf01900b7,
+	0xbecf10d7,
+	0x00bfcf40,
+	0xb70421f4,
+	0xf00400b0,
+	0xbed001e7,
+/* 0x05e9: ih_no_fifo */
+	0x00abe400,
+	0x0d0bf401,
+	0xf110d7f0,
+	0xf44001e7,
+/* 0x05fa: ih_no_ctxsw */
+	0xb7f10421,
+	0xb0bd0104,
+	0xf4b4abff,
+	0xa7f10d0b,
+	0xa4b60c1c,
+	0x00abd006,
+/* 0x0610: ih_no_other */
+	0xfc400ad0,
+	0xfce0fcf0,
+	0xfcb0fcd0,
+	0xfc90fca0,
+	0x0088fe80,
+	0x32f480fc,
+/* 0x062b: ctx_4170s */
+	0xf101f800,
+	0xf04170e7,
+	0xf5f040e3,
+	0x8d21f410,
+/* 0x063a: ctx_4170w */
+	0xe7f100f8,
+	0xe3f04170,
+	0x6821f440,
+	0xf410f4f0,
+	0x00f8f31b,
+/* 0x064c: ctx_redswitch */
+	0x0614e7f1,
+	0xf106e4b6,
+	0xd00270f7,
+	0xf7f000ef,
+/* 0x065d: ctx_redswitch_delay */
+	0x01f2b608,
+	0xf1fd1bf4,
+	0xd00770f7,
+	0x00f800ef,
+/* 0x066c: ctx_86c */
+	0x086ce7f1,
+	0xd006e4b6,
+	0xe7f100ef,
+	0xe3f08a14,
+	0x8d21f440,
+	0xa86ce7f1,
+	0xf441e3f0,
+	0x00f88d21,
+/* 0x068c: ctx_load */
+	0x99f094bd,
+	0x0007f105,
+	0x0203f037,
+	0xbd0009d0,
+	0x0ca7f004,
+	0xf1c921f4,
+	0xb60a2417,
+	0x10d00614,
+	0x0037f100,
+	0x0634b60b,
+	0xf14032d0,
+	0xb60a0c17,
+	0x47f00614,
+	0x0012d007,
+/* 0x06c7: ctx_chan_wait_0 */
+	0xcf4014d0,
+	0x44f04014,
+	0xfa1bf41f,
+	0xfe0032d0,
+	0x2af0000b,
+	0x0424b61f,
+	0xbd0220b6,
+	0x0899f094,
+	0x370007f1,
+	0xd00203f0,
+	0x04bd0009,
+	0x0a0417f1,
+	0xd00614b6,
+	0x17f10012,
+	0x14b60a20,
+	0x0227f006,
+	0x800023f1,
+	0xf00012d0,
+	0x27f11017,
+	0x23f00200,
+	0x0512fa02,
+	0x94bd03f8,
+	0xf10899f0,
+	0xf0170007,
+	0x09d00203,
+	0x9804bd00,
+	0x14b68101,
+	0x80029818,
+	0xfd0825b6,
+	0x01800512,
+	0xf094bd16,
+	0x07f10999,
+	0x03f03700,
+	0x0009d002,
+	0x27f104bd,
+	0x24b60a04,
+	0x0021d006,
+	0xf10127f0,
+	0xb60a2017,
+	0x12d00614,
+	0x0017f100,
+	0x0613f001,
+	0xf80501fa,
+	0xf094bd03,
+	0x07f10999,
+	0x03f01700,
+	0x0009d002,
+	0x94bd04bd,
+	0xf10599f0,
+	0xf0170007,
+	0x09d00203,
+	0xf804bd00,
+/* 0x0795: ctx_chan */
+	0x8c21f500,
+	0x0ca7f006,
+	0xf1c921f4,
+	0xb60a1017,
+	0x27f00614,
+	0x0012d005,
+/* 0x07ac: ctx_chan_wait */
+	0xfd0012cf,
+	0x1bf40522,
+/* 0x07b7: ctx_mmio_exec */
+	0x9800f8fa,
+	0x27f14103,
+	0x24b60a04,
+	0x0023d006,
+/* 0x07c6: ctx_mmio_loop */
+	0x34c434bd,
+	0x0f1bf4ff,
+	0x020057f1,
+	0xfa0653f0,
+	0x03f80535,
+/* 0x07d8: ctx_mmio_pull */
+	0x98804e98,
+	0x21f4814f,
+	0x0830b68d,
+	0xf40112b6,
+/* 0x07ea: ctx_mmio_done */
+	0x0398df1b,
+	0x0023d016,
+	0xf1400080,
+	0xf0010017,
+	0x01fa0613,
+	0xf803f806,
+/* 0x0801: ctx_xfer */
+	0x00f7f100,
+	0x06f4b60c,
+	0xd004e7f0,
+/* 0x080e: ctx_xfer_idle */
+	0xfecf80fe,
+	0x00e4f100,
+	0xf91bf420,
+	0xf40611f4,
+/* 0x081e: ctx_xfer_pre */
+	0xf7f00d02,
+	0x6c21f510,
+	0x1c11f406,
+/* 0x0828: ctx_xfer_pre_load */
+	0xf502f7f0,
+	0xf5062b21,
+	0xf5063a21,
+	0xbd064c21,
+	0x2b21f5f4,
+	0x8c21f506,
+/* 0x0841: ctx_xfer_exec */
+	0x16019806,
+	0x041427f1,
+	0xd00624b6,
+	0xe7f10020,
+	0xe3f0a500,
+	0x021fb941,
+	0xb68d21f4,
+	0xfcf004e0,
+	0x022cf001,
+	0xfd0124b6,
+	0x21f405f2,
+	0xfc17f18d,
+	0x0213f04a,
+	0xd00c27f0,
+	0x21f50012,
+	0x27f10215,
+	0x23f047fc,
+	0x0020d002,
+	0xb6012cf0,
+	0x12d00320,
+	0x01acf000,
+	0xf006a5f0,
+	0x0c9800b7,
+	0x010d9800,
+	0xf500e7f0,
+	0xf0016621,
+	0x21f508a7,
+	0x21f50109,
+	0x01f40215,
+	0x0ca7f022,
+	0xf1c921f4,
+	0xb60a1017,
+	0x27f00614,
+	0x0012d005,
+/* 0x08c8: ctx_xfer_post_save_wait */
+	0xfd0012cf,
+	0x1bf40522,
+	0x2e02f4fa,
+/* 0x08d4: ctx_xfer_post */
+	0xf502f7f0,
+	0xbd062b21,
+	0x6c21f5f4,
+	0x3421f506,
+	0x3a21f502,
+	0xf5f4bd06,
+	0xf4062b21,
+	0x01981011,
+	0x0511fd40,
+	0xf5070bf4,
+/* 0x08ff: ctx_xfer_no_post_mmio */
+/* 0x08ff: ctx_xfer_done */
+	0xf807b721,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
new file mode 100644
index 0000000..33a5a82
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "os.h"
+
+#define GF100 0xc0
+#define GF117 0xd7
+#define GK100 0xe0
+#define GK110 0xf0
+
+#define NV_PGRAPH_FECS_SIGNAL                                          0x409400
+#if CHIPSET < GK110
+#define NV_PGRAPH_FECS_CC_SCRATCH_VAL(n)                    ((n) * 4 + 0x409800)
+#define NV_PGRAPH_FECS_CC_SCRATCH_SET(n)                    ((n) * 4 + 0x409820)
+#define NV_PGRAPH_FECS_CC_SCRATCH_CLR(n)                    ((n) * 4 + 0x409840)
+#else
+#define NV_PGRAPH_FECS_CC_SCRATCH_VAL(n)                    ((n) * 4 + 0x409800)
+#define NV_PGRAPH_FECS_CC_SCRATCH_CLR(n)                    ((n) * 4 + 0x409840)
+#define NV_PGRAPH_FECS_CC_SCRATCH_SET(n)                    ((n) * 4 + 0x4098c0)
+#endif
+#define NV_PGRAPH_FECS_INTR_UP_SET                                     0x409c1c
+
+#if CHIPSET < GK110
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n)              ((n) * 4 + 0x41a800)
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(n)              ((n) * 4 + 0x41a820)
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_CLR(n)              ((n) * 4 + 0x41a840)
+#else
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n)              ((n) * 4 + 0x41a800)
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_CLR(n)              ((n) * 4 + 0x41a840)
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(n)              ((n) * 4 + 0x41a8c0)
+#endif
+
+#define mmctx_data(r,c) .b32 (((c - 1) << 26) | r)
+#define queue_init      .skip 72 // (2 * 4) + ((8 * 4) * 2)
+
+#define T_WAIT    0
+#define T_MMCTX   1
+#define T_STRWAIT 2
+#define T_STRINIT 3
+#define T_AUTO    4
+#define T_CHAN    5
+#define T_LOAD    6
+#define T_SAVE    7
+#define T_LCHAN   8
+#define T_LCTXH   9
+
+#define nv_mkmm(rv,r) /*
+*/	movw rv  ((r) & 0x0000fffc) /*
+*/	sethi rv ((r) & 0x00ff0000)
+#define nv_mkio(rv,r,i) /*
+*/	nv_mkmm(rv, (((r) & 0xffc) << 6) | ((i) << 2))
+
+#define nv_iord(rv,r,i) /*
+*/	nv_mkio(rv,r,i) /*
+*/	iord rv I[rv]
+#define nv_iowr(r,i,rv) /*
+*/	nv_mkio($r0,r,i) /*
+*/	iowr I[$r0] rv /*
+*/	clear b32 $r0
+
+#define trace_set(bit) /*
+*/	clear b32 $r9 /*
+*/	bset $r9 bit /*
+*/	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(7), 0, $r9)
+#define trace_clr(bit) /*
+*/	clear b32 $r9 /*
+*/	bset $r9 bit /*
+*/	nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_CLR(7), 0, $r9)
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc
deleted file mode 100644
index f16a5d5..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc
+++ /dev/null
@@ -1,400 +0,0 @@
-/* fuc microcode util functions for nve0 PGRAPH
- *
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)')
-define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))')
-
-ifdef(`include_code', `
-// Error codes
-define(`E_BAD_COMMAND', 0x01)
-define(`E_CMD_OVERFLOW', 0x02)
-
-// Util macros to help with debugging ucode hangs etc
-define(`T_WAIT', 0)
-define(`T_MMCTX', 1)
-define(`T_STRWAIT', 2)
-define(`T_STRINIT', 3)
-define(`T_AUTO', 4)
-define(`T_CHAN', 5)
-define(`T_LOAD', 6)
-define(`T_SAVE', 7)
-define(`T_LCHAN', 8)
-define(`T_LCTXH', 9)
-
-define(`trace_set', `
-	mov $r8 0x83c
-	shl b32 $r8 6
-	clear b32 $r9
-	bset $r9 $1
-	iowr I[$r8 + 0x000] $r9		// CC_SCRATCH[7]
-')
-
-define(`trace_clr', `
-	mov $r8 0x85c
-	shl b32 $r8 6
-	clear b32 $r9
-	bset $r9 $1
-	iowr I[$r8 + 0x000] $r9		// CC_SCRATCH[7]
-')
-
-// queue_put - add request to queue
-//
-// In : $r13 queue pointer
-//	$r14 command
-//	$r15 data
-//
-queue_put:
-	// make sure we have space..
-	ld b32 $r8 D[$r13 + 0x0]	// GET
-	ld b32 $r9 D[$r13 + 0x4]	// PUT
-	xor $r8 8
-	cmpu b32 $r8 $r9
-	bra ne #queue_put_next
-		mov $r15 E_CMD_OVERFLOW
-		call #error
-		ret
-
-	// store cmd/data on queue
-	queue_put_next:
-	and $r8 $r9 7
-	shl b32 $r8 3
-	add b32 $r8 $r13
-	add b32 $r8 8
-	st b32 D[$r8 + 0x0] $r14
-	st b32 D[$r8 + 0x4] $r15
-
-	// update PUT
-	add b32 $r9 1
-	and $r9 0xf
-	st b32 D[$r13 + 0x4] $r9
-	ret
-
-// queue_get - fetch request from queue
-//
-// In : $r13 queue pointer
-//
-// Out:	$p1  clear on success (data available)
-//	$r14 command
-// 	$r15 data
-//
-queue_get:
-	bset $flags $p1
-	ld b32 $r8 D[$r13 + 0x0]	// GET
-	ld b32 $r9 D[$r13 + 0x4]	// PUT
-	cmpu b32 $r8 $r9
-	bra e #queue_get_done
-		// fetch first cmd/data pair
-		and $r9 $r8 7
-		shl b32 $r9 3
-		add b32 $r9 $r13
-		add b32 $r9 8
-		ld b32 $r14 D[$r9 + 0x0]
-		ld b32 $r15 D[$r9 + 0x4]
-
-		// update GET
-		add b32 $r8 1
-		and $r8 0xf
-		st b32 D[$r13 + 0x0] $r8
-		bclr $flags $p1
-queue_get_done:
-	ret
-
-// nv_rd32 - read 32-bit value from nv register
-//
-// In : $r14 register
-// Out: $r15 value
-//
-nv_rd32:
-	mov $r11 0x728
-	shl b32 $r11 6
-	mov b32 $r12 $r14
-	bset $r12 31			// MMIO_CTRL_PENDING
-	iowr I[$r11 + 0x000] $r12	// MMIO_CTRL
-	nv_rd32_wait:
-		iord $r12 I[$r11 + 0x000]
-		xbit $r12 $r12 31
-		bra ne #nv_rd32_wait
-	mov $r10 6			// DONE_MMIO_RD
-	call #wait_doneo
-	iord $r15 I[$r11 + 0x100]	// MMIO_RDVAL
-	ret
-
-// nv_wr32 - write 32-bit value to nv register
-//
-// In : $r14 register
-//      $r15 value
-//
-nv_wr32:
-	mov $r11 0x728
-	shl b32 $r11 6
-	iowr I[$r11 + 0x200] $r15	// MMIO_WRVAL
-	mov b32 $r12 $r14
-	bset $r12 31			// MMIO_CTRL_PENDING
-	bset $r12 30			// MMIO_CTRL_WRITE
-	iowr I[$r11 + 0x000] $r12	// MMIO_CTRL
-	nv_wr32_wait:
-		iord $r12 I[$r11 + 0x000]
-		xbit $r12 $r12 31
-		bra ne #nv_wr32_wait
-	ret
-
-// (re)set watchdog timer
-//
-// In : $r15 timeout
-//
-watchdog_reset:
-	mov $r8 0x430
-	shl b32 $r8 6
-	bset $r15 31
-	iowr I[$r8 + 0x000] $r15
-	ret
-
-// clear watchdog timer
-watchdog_clear:
-	mov $r8 0x430
-	shl b32 $r8 6
-	iowr I[$r8 + 0x000] $r0
-	ret
-
-// wait_done{z,o} - wait on FUC_DONE bit to become clear/set
-//
-// In : $r10 bit to wait on
-//
-define(`wait_done', `
-$1:
-	trace_set(T_WAIT);
-	mov $r8 0x818
-	shl b32 $r8 6
-	iowr I[$r8 + 0x000] $r10	// CC_SCRATCH[6] = wait bit
-	wait_done_$1:
-		mov $r8 0x400
-		shl b32 $r8 6
-		iord $r8 I[$r8 + 0x000]	// DONE
-		xbit $r8 $r8 $r10
-		bra $2 #wait_done_$1
-	trace_clr(T_WAIT)
-	ret
-')
-wait_done(wait_donez, ne)
-wait_done(wait_doneo, e)
-
-// mmctx_size - determine size of a mmio list transfer
-//
-// In : $r14 mmio list head
-//      $r15 mmio list tail
-// Out: $r15 transfer size (in bytes)
-//
-mmctx_size:
-	clear b32 $r9
-	nv_mmctx_size_loop:
-		ld b32 $r8 D[$r14]
-		shr b32 $r8 26
-		add b32 $r8 1
-		shl b32 $r8 2
-		add b32 $r9 $r8
-		add b32 $r14 4
-		cmpu b32 $r14 $r15
-		bra ne #nv_mmctx_size_loop
-	mov b32 $r15 $r9
-	ret
-
-// mmctx_xfer - execute a list of mmio transfers
-//
-// In : $r10 flags
-//		bit 0: direction (0 = save, 1 = load)
-//		bit 1: set if first transfer
-//		bit 2: set if last transfer
-//	$r11 base
-//	$r12 mmio list head
-//	$r13 mmio list tail
-//	$r14 multi_stride
-//	$r15 multi_mask
-//
-mmctx_xfer:
-	trace_set(T_MMCTX)
-	mov $r8 0x710
-	shl b32 $r8 6
-	clear b32 $r9
-	or $r11 $r11
-	bra e #mmctx_base_disabled
-		iowr I[$r8 + 0x000] $r11	// MMCTX_BASE
-		bset $r9 0			// BASE_EN
-	mmctx_base_disabled:
-	or $r14 $r14
-	bra e #mmctx_multi_disabled
-		iowr I[$r8 + 0x200] $r14 	// MMCTX_MULTI_STRIDE
-		iowr I[$r8 + 0x300] $r15 	// MMCTX_MULTI_MASK
-		bset $r9 1			// MULTI_EN
-	mmctx_multi_disabled:
-	add b32 $r8 0x100
-
-	xbit $r11 $r10 0
-	shl b32 $r11 16			// DIR
-	bset $r11 12			// QLIMIT = 0x10
-	xbit $r14 $r10 1
-	shl b32 $r14 17
-	or $r11 $r14			// START_TRIGGER
-	iowr I[$r8 + 0x000] $r11	// MMCTX_CTRL
-
-	// loop over the mmio list, and send requests to the hw
-	mmctx_exec_loop:
-		// wait for space in mmctx queue
-		mmctx_wait_free:
-			iord $r14 I[$r8 + 0x000] // MMCTX_CTRL
-			and $r14 0x1f
-			bra e #mmctx_wait_free
-
-		// queue up an entry
-		ld b32 $r14 D[$r12]
-		or $r14 $r9
-		iowr I[$r8 + 0x300] $r14
-		add b32 $r12 4
-		cmpu b32 $r12 $r13
-		bra ne #mmctx_exec_loop
-
-	xbit $r11 $r10 2
-	bra ne #mmctx_stop
-		// wait for queue to empty
-		mmctx_fini_wait:
-			iord $r11 I[$r8 + 0x000]	// MMCTX_CTRL
-			and $r11 0x1f
-			cmpu b32 $r11 0x10
-			bra ne #mmctx_fini_wait
-		mov $r10 2				// DONE_MMCTX
-		call #wait_donez
-		bra #mmctx_done
-	mmctx_stop:
-		xbit $r11 $r10 0
-		shl b32 $r11 16			// DIR
-		bset $r11 12			// QLIMIT = 0x10
-		bset $r11 18			// STOP_TRIGGER
-		iowr I[$r8 + 0x000] $r11	// MMCTX_CTRL
-		mmctx_stop_wait:
-			// wait for STOP_TRIGGER to clear
-			iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
-			xbit $r11 $r11 18
-			bra ne #mmctx_stop_wait
-	mmctx_done:
-	trace_clr(T_MMCTX)
-	ret
-
-// Wait for DONE_STRAND
-//
-strand_wait:
-	push $r10
-	mov $r10 2
-	call #wait_donez
-	pop $r10
-	ret
-
-// unknown - call before issuing strand commands
-//
-strand_pre:
-	mov $r8 0x4afc
-	sethi $r8 0x20000
-	mov $r9 0xc
-	iowr I[$r8] $r9
-	call #strand_wait
-	ret
-
-// unknown - call after issuing strand commands
-//
-strand_post:
-	mov $r8 0x4afc
-	sethi $r8 0x20000
-	mov $r9 0xd
-	iowr I[$r8] $r9
-	call #strand_wait
-	ret
-
-// Selects strand set?!
-//
-// In: $r14 id
-//
-strand_set:
-	mov $r10 0x4ffc
-	sethi $r10 0x20000
-	sub b32 $r11 $r10 0x500
-	mov $r12 0xf
-	iowr I[$r10 + 0x000] $r12		// 0x93c = 0xf
-	mov $r12 0xb
-	iowr I[$r11 + 0x000] $r12		// 0x928 = 0xb
-	call #strand_wait
-	iowr I[$r10 + 0x000] $r14		// 0x93c = <id>
-	mov $r12 0xa
-	iowr I[$r11 + 0x000] $r12		// 0x928 = 0xa
-	call #strand_wait
-	ret
-
-// Initialise strand context data
-//
-// In : $r15 context base
-// Out: $r15 context size (in bytes)
-//
-// Strandset(?) 3 hardcoded currently
-//
-strand_ctx_init:
-	trace_set(T_STRINIT)
-	call #strand_pre
-	mov $r14 3
-	call #strand_set
-	mov $r10 0x46fc
-	sethi $r10 0x20000
-	add b32 $r11 $r10 0x400
-	iowr I[$r10 + 0x100] $r0	// STRAND_FIRST_GENE = 0
-	mov $r12 1
-	iowr I[$r11 + 0x000] $r12	// STRAND_CMD = LATCH_FIRST_GENE
-	call #strand_wait
-	sub b32 $r12 $r0 1
-	iowr I[$r10 + 0x000] $r12	// STRAND_GENE_CNT = 0xffffffff
-	mov $r12 2
-	iowr I[$r11 + 0x000] $r12	// STRAND_CMD = LATCH_GENE_CNT
-	call #strand_wait
-	call #strand_post
-
-	// read the size of each strand, poke the context offset of
-	// each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
-	// about it later then.
-	mov $r8 0x880
-	shl b32 $r8 6
-	iord $r9 I[$r8 + 0x000]		// STRANDS
-	add b32 $r8 0x2200
-	shr b32 $r14 $r15 8
-	ctx_init_strand_loop:
-		iowr I[$r8 + 0x000] $r14	// STRAND_SAVE_SWBASE
-		iowr I[$r8 + 0x100] $r14	// STRAND_LOAD_SWBASE
-		iord $r10 I[$r8 + 0x200]	// STRAND_SIZE
-		shr b32 $r10 6
-		add b32 $r10 1
-		add b32 $r14 $r10
-		add b32 $r8 4
-		sub b32 $r9 1
-		bra ne #ctx_init_strand_loop
-
-	shl b32 $r14 8
-	sub b32 $r15 $r14 $r15
-	trace_clr(T_STRINIT)
-	ret
-')
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h
new file mode 100644
index 0000000..fd1d380
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_GRAPH_OS_H__
+#define __NVKM_GRAPH_OS_H__
+
+#define E_BAD_COMMAND  0x00000001
+#define E_CMD_OVERFLOW 0x00000002
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
index 1ac3611..03de517 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
@@ -186,13 +186,6 @@
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static int
-nv50_graph_tlb_flush(struct nouveau_engine *engine)
-{
-	nv50_vm_flush_engine(&engine->base, 0x00);
-	return 0;
-}
-
 static const struct nouveau_bitfield nv50_pgraph_status[] = {
 	{ 0x00000001, "BUSY" }, /* set when any bit is set */
 	{ 0x00000002, "DISPATCH" },
@@ -302,8 +295,10 @@
 				nv_rd32(priv, 0x400388));
 	}
 
-	nv50_vm_flush_engine(&engine->base, 0x00);
 
+	nv_wr32(priv, 0x100c80, 0x00000001);
+	if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
+		nv_error(priv, "vm flush timeout\n");
 	nv_mask(priv, 0x400500, 0x00000001, 0x00000001);
 	spin_unlock_irqrestore(&priv->lock, flags);
 	return timeout ? -EBUSY : 0;
@@ -857,10 +852,9 @@
 
 	};
 
-	if (nv_device(priv)->chipset == 0x50 ||
-	    nv_device(priv)->chipset == 0xac)
-		nv_engine(priv)->tlb_flush = nv50_graph_tlb_flush;
-	else
+	/* unfortunate hw bug workaround... */
+	if (nv_device(priv)->chipset != 0x50 &&
+	    nv_device(priv)->chipset != 0xac)
 		nv_engine(priv)->tlb_flush = nv84_graph_tlb_flush;
 
 	spin_lock_init(&priv->lock);
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
index f9b9d82..3f4f35c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
@@ -23,14 +23,12 @@
  */
 
 #include "nvc0.h"
-#include "fuc/hubnvc0.fuc.h"
-#include "fuc/gpcnvc0.fuc.h"
 
 /*******************************************************************************
  * Graphics object classes
  ******************************************************************************/
 
-static struct nouveau_oclass
+struct nouveau_oclass
 nvc0_graph_sclass[] = {
 	{ 0x902d, &nouveau_object_ofuncs },
 	{ 0x9039, &nouveau_object_ofuncs },
@@ -39,40 +37,6 @@
 	{}
 };
 
-static struct nouveau_oclass
-nvc1_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0x9039, &nouveau_object_ofuncs },
-	{ 0x9097, &nouveau_object_ofuncs },
-	{ 0x90c0, &nouveau_object_ofuncs },
-	{ 0x9197, &nouveau_object_ofuncs },
-	{}
-};
-
-static struct nouveau_oclass
-nvc8_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0x9039, &nouveau_object_ofuncs },
-	{ 0x9097, &nouveau_object_ofuncs },
-	{ 0x90c0, &nouveau_object_ofuncs },
-	{ 0x9197, &nouveau_object_ofuncs },
-	{ 0x9297, &nouveau_object_ofuncs },
-	{}
-};
-
-u64
-nvc0_graph_units(struct nouveau_graph *graph)
-{
-	struct nvc0_graph_priv *priv = (void *)graph;
-	u64 cfg;
-
-	cfg  = (u32)priv->gpc_nr;
-	cfg |= (u32)priv->tpc_total << 8;
-	cfg |= (u64)priv->rop_nr << 32;
-
-	return cfg;
-}
-
 /*******************************************************************************
  * PGRAPH context
  ******************************************************************************/
@@ -181,60 +145,308 @@
 	nouveau_graph_context_destroy(&chan->base);
 }
 
-static struct nouveau_oclass
-nvc0_graph_cclass = {
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
 /*******************************************************************************
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static void
-nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base)
+struct nvc0_graph_init
+nvc0_graph_init_regs[] = {
+	{ 0x400080,   1, 0x04, 0x003083c2 },
+	{ 0x400088,   1, 0x04, 0x00006fe7 },
+	{ 0x40008c,   1, 0x04, 0x00000000 },
+	{ 0x400090,   1, 0x04, 0x00000030 },
+	{ 0x40013c,   1, 0x04, 0x013901f7 },
+	{ 0x400140,   1, 0x04, 0x00000100 },
+	{ 0x400144,   1, 0x04, 0x00000000 },
+	{ 0x400148,   1, 0x04, 0x00000110 },
+	{ 0x400138,   1, 0x04, 0x00000000 },
+	{ 0x400130,   2, 0x04, 0x00000000 },
+	{ 0x400124,   1, 0x04, 0x00000002 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk40xx[] = {
+	{ 0x40415c,   1, 0x04, 0x00000000 },
+	{ 0x404170,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk44xx[] = {
+	{ 0x404488,   2, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk78xx[] = {
+	{ 0x407808,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk60xx[] = {
+	{ 0x406024,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk58xx[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk80xx[] = {
+	{ 0x40803c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_gpc[] = {
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x80000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{ 0x418814,   3, 0x04, 0x00000000 },
+	{ 0x418b04,   1, 0x04, 0x00000000 },
+	{ 0x4188c8,   1, 0x04, 0x80000000 },
+	{ 0x4188cc,   1, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000050 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x41900c,   1, 0x04, 0x00000000 },
+	{ 0x419018,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvc0_graph_init_tpc[] = {
+	{ 0x419d08,   2, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x41980c,   3, 0x04, 0x00000000 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc5 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x80000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00008bf4 },
+	{ 0x419cbc,   1, 0x04, 0x28137606 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419bd4,   1, 0x04, 0x00800000 },
+	{ 0x419bdc,   1, 0x04, 0x00000000 },
+	{ 0x419d2c,   1, 0x04, 0x00000000 },
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00001100 },
+	{ 0x419eac,   1, 0x04, 0x11100702 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x06060618 },
+	{ 0x419ed0,   1, 0x04, 0x0eff0e38 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk88xx[] = {
+	{ 0x40880c,   1, 0x04, 0x00000000 },
+	{ 0x408910,   9, 0x04, 0x00000000 },
+	{ 0x408950,   1, 0x04, 0x00000000 },
+	{ 0x408954,   1, 0x04, 0x0000ffff },
+	{ 0x408984,   1, 0x04, 0x00000000 },
+	{ 0x408988,   1, 0x04, 0x08040201 },
+	{ 0x40898c,   1, 0x04, 0x80402010 },
+	{}
+};
+
+struct nvc0_graph_init
+nvc0_graph_tpc_0[] = {
+	{ 0x50405c,   1, 0x04, 0x00000001 },
+	{}
+};
+
+void
+nvc0_graph_mmio(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init)
 {
-	nv_error(priv, "%06x - done 0x%08x\n", base,
-		 nv_rd32(priv, base + 0x400));
-	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		 nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
-		 nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
-	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		 nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
-		 nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
+	for (; init && init->count; init++) {
+		u32 addr = init->addr, i;
+		for (i = 0; i < init->count; i++) {
+			nv_wr32(priv, addr, init->data);
+			addr += init->pitch;
+		}
+	}
 }
 
 void
-nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv)
+nvc0_graph_icmd(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init)
 {
-	u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
-	u32 gpc;
+	u32 addr, data;
+	int i, j;
 
-	nvc0_graph_ctxctl_debug_unit(priv, 0x409000);
-	for (gpc = 0; gpc < gpcnr; gpc++)
-		nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
+	nv_wr32(priv, 0x400208, 0x80000000);
+	for (i = 0; init->count; init++, i++) {
+		if (!i || data != init->data) {
+			nv_wr32(priv, 0x400204, init->data);
+			data = init->data;
+		}
+
+		addr = init->addr;
+		for (j = 0; j < init->count; j++) {
+			nv_wr32(priv, 0x400200, addr);
+			addr += init->pitch;
+			while (nv_rd32(priv, 0x400700) & 0x00000002) {}
+		}
+	}
+	nv_wr32(priv, 0x400208, 0x00000000);
 }
 
-static void
-nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
+void
+nvc0_graph_mthd(struct nvc0_graph_priv *priv, struct nvc0_graph_mthd *mthds)
 {
-	u32 ustat = nv_rd32(priv, 0x409c18);
+	struct nvc0_graph_mthd *mthd;
+	struct nvc0_graph_init *init;
+	int i = 0, j;
+	u32 data;
 
-	if (ustat & 0x00000001)
-		nv_error(priv, "CTXCTRL ucode error\n");
-	if (ustat & 0x00080000)
-		nv_error(priv, "CTXCTRL watchdog timeout\n");
-	if (ustat & ~0x00080001)
-		nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
+	while ((mthd = &mthds[i++]) && (init = mthd->init)) {
+		u32  addr = 0x80000000 | mthd->oclass;
+		for (data = 0; init->count; init++) {
+			if (data != init->data) {
+				nv_wr32(priv, 0x40448c, init->data);
+				data = init->data;
+			}
 
-	nvc0_graph_ctxctl_debug(priv);
-	nv_wr32(priv, 0x409c20, ustat);
+			addr = (addr & 0x8000ffff) | (init->addr << 14);
+			for (j = 0; j < init->count; j++) {
+				nv_wr32(priv, 0x404488, addr);
+				addr += init->pitch << 14;
+			}
+		}
+	}
+}
+
+u64
+nvc0_graph_units(struct nouveau_graph *graph)
+{
+	struct nvc0_graph_priv *priv = (void *)graph;
+	u64 cfg;
+
+	cfg  = (u32)priv->gpc_nr;
+	cfg |= (u32)priv->tpc_total << 8;
+	cfg |= (u64)priv->rop_nr << 32;
+
+	return cfg;
+}
+
+static const struct nouveau_enum nve0_sked_error[] = {
+	{ 7, "CONSTANT_BUFFER_SIZE" },
+	{ 9, "LOCAL_MEMORY_SIZE_POS" },
+	{ 10, "LOCAL_MEMORY_SIZE_NEG" },
+	{ 11, "WARP_CSTACK_SIZE" },
+	{ 12, "TOTAL_TEMP_SIZE" },
+	{ 13, "REGISTER_COUNT" },
+	{ 18, "TOTAL_THREADS" },
+	{ 20, "PROGRAM_OFFSET" },
+	{ 21, "SHARED_MEMORY_SIZE" },
+	{ 25, "SHARED_CONFIG_TOO_SMALL" },
+	{ 26, "TOTAL_REGISTER_COUNT" },
+	{}
+};
+
+static const struct nouveau_enum nvc0_gpc_rop_error[] = {
+	{ 1, "RT_PITCH_OVERRUN" },
+	{ 4, "RT_WIDTH_OVERRUN" },
+	{ 5, "RT_HEIGHT_OVERRUN" },
+	{ 7, "ZETA_STORAGE_TYPE_MISMATCH" },
+	{ 8, "RT_STORAGE_TYPE_MISMATCH" },
+	{ 10, "RT_LINEAR_MISMATCH" },
+	{}
+};
+
+static void
+nvc0_graph_trap_gpc_rop(struct nvc0_graph_priv *priv, int gpc)
+{
+	u32 trap[4];
+	int i;
+
+	trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
+	trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434));
+	trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438));
+	trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c));
+
+	nv_error(priv, "GPC%d/PROP trap:", gpc);
+	for (i = 0; i <= 29; ++i) {
+		if (!(trap[0] & (1 << i)))
+			continue;
+		pr_cont(" ");
+		nouveau_enum_print(nvc0_gpc_rop_error, i);
+	}
+	pr_cont("\n");
+
+	nv_error(priv, "x = %u, y = %u, format = %x, storage type = %x\n",
+		 trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f,
+		 trap[3] & 0xff);
+	nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+}
+
+static const struct nouveau_enum nvc0_mp_warp_error[] = {
+	{ 0x00, "NO_ERROR" },
+	{ 0x01, "STACK_MISMATCH" },
+	{ 0x05, "MISALIGNED_PC" },
+	{ 0x08, "MISALIGNED_GPR" },
+	{ 0x09, "INVALID_OPCODE" },
+	{ 0x0d, "GPR_OUT_OF_BOUNDS" },
+	{ 0x0e, "MEM_OUT_OF_BOUNDS" },
+	{ 0x0f, "UNALIGNED_MEM_ACCESS" },
+	{ 0x11, "INVALID_PARAM" },
+	{}
+};
+
+static const struct nouveau_bitfield nvc0_mp_global_error[] = {
+	{ 0x00000004, "MULTIPLE_WARP_ERRORS" },
+	{ 0x00000008, "OUT_OF_STACK_SPACE" },
+	{}
+};
+
+static void
+nvc0_graph_trap_mp(struct nvc0_graph_priv *priv, int gpc, int tpc)
+{
+	u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x648));
+	u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x650));
+
+	nv_error(priv, "GPC%i/TPC%i/MP trap:", gpc, tpc);
+	nouveau_bitfield_print(nvc0_mp_global_error, gerr);
+	if (werr) {
+		pr_cont(" ");
+		nouveau_enum_print(nvc0_mp_warp_error, werr & 0xffff);
+	}
+	pr_cont("\n");
+
+	nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x648), 0x00000000);
+	nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x650), gerr);
 }
 
 static void
@@ -246,18 +458,11 @@
 		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224));
 		nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap);
 		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000001);
 		stat &= ~0x00000001;
 	}
 
 	if (stat & 0x00000002) {
-		u32 trap0 = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0644));
-		u32 trap1 = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x064c));
-		nv_error(priv, "GPC%d/TPC%d/MP: 0x%08x 0x%08x\n",
-			       gpc, tpc, trap0, trap1);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0644), 0x001ffffe);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x064c), 0x0000000f);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000002);
+		nvc0_graph_trap_mp(priv, gpc, tpc);
 		stat &= ~0x00000002;
 	}
 
@@ -265,7 +470,6 @@
 		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084));
 		nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap);
 		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000004);
 		stat &= ~0x00000004;
 	}
 
@@ -273,13 +477,11 @@
 		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c));
 		nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap);
 		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000008);
 		stat &= ~0x00000008;
 	}
 
 	if (stat) {
 		nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat);
-		nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), stat);
 	}
 }
 
@@ -290,10 +492,7 @@
 	int tpc;
 
 	if (stat & 0x00000001) {
-		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
-		nv_error(priv, "GPC%d/PROP: 0x%08x\n", gpc, trap);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000001);
+		nvc0_graph_trap_gpc_rop(priv, gpc);
 		stat &= ~0x00000001;
 	}
 
@@ -301,7 +500,6 @@
 		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900));
 		nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap);
 		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000002);
 		stat &= ~0x00000002;
 	}
 
@@ -309,7 +507,6 @@
 		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028));
 		nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap);
 		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000004);
 		stat &= ~0x00000004;
 	}
 
@@ -317,7 +514,6 @@
 		u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824));
 		nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap);
 		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000008);
 		stat &= ~0x00000009;
 	}
 
@@ -332,7 +528,6 @@
 
 	if (stat) {
 		nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), stat);
 	}
 }
 
@@ -340,7 +535,7 @@
 nvc0_graph_trap_intr(struct nvc0_graph_priv *priv)
 {
 	u32 trap = nv_rd32(priv, 0x400108);
-	int rop, gpc;
+	int rop, gpc, i;
 
 	if (trap & 0x00000001) {
 		u32 stat = nv_rd32(priv, 0x404000);
@@ -390,6 +585,24 @@
 		trap &= ~0x00000080;
 	}
 
+	if (trap & 0x00000100) {
+		u32 stat = nv_rd32(priv, 0x407020);
+
+		nv_error(priv, "SKED:");
+		for (i = 0; i <= 29; ++i) {
+			if (!(stat & (1 << i)))
+				continue;
+			pr_cont(" ");
+			nouveau_enum_print(nve0_sked_error, i);
+		}
+		pr_cont("\n");
+
+		if (stat & 0x3fffffff)
+			nv_wr32(priv, 0x407020, 0x40000000);
+		nv_wr32(priv, 0x400108, 0x00000100);
+		trap &= ~0x00000100;
+	}
+
 	if (trap & 0x01000000) {
 		u32 stat = nv_rd32(priv, 0x400118);
 		for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) {
@@ -424,6 +637,46 @@
 }
 
 static void
+nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base)
+{
+	nv_error(priv, "%06x - done 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x400));
+	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
+		 nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
+	nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+		 nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
+		 nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
+}
+
+void
+nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv)
+{
+	u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
+	u32 gpc;
+
+	nvc0_graph_ctxctl_debug_unit(priv, 0x409000);
+	for (gpc = 0; gpc < gpcnr; gpc++)
+		nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
+}
+
+static void
+nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
+{
+	u32 ustat = nv_rd32(priv, 0x409c18);
+
+	if (ustat & 0x00000001)
+		nv_error(priv, "CTXCTL ucode error\n");
+	if (ustat & 0x00080000)
+		nv_error(priv, "CTXCTL watchdog timeout\n");
+	if (ustat & ~0x00080001)
+		nv_error(priv, "CTXCTL 0x%08x\n", ustat);
+
+	nvc0_graph_ctxctl_debug(priv);
+	nv_wr32(priv, 0x409c20, ustat);
+}
+
+static void
 nvc0_graph_intr(struct nouveau_subdev *subdev)
 {
 	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
@@ -499,6 +752,332 @@
 	nouveau_engctx_put(engctx);
 }
 
+void
+nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base,
+		   struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
+{
+	int i;
+
+	nv_wr32(priv, fuc_base + 0x01c0, 0x01000000);
+	for (i = 0; i < data->size / 4; i++)
+		nv_wr32(priv, fuc_base + 0x01c4, data->data[i]);
+
+	nv_wr32(priv, fuc_base + 0x0180, 0x01000000);
+	for (i = 0; i < code->size / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, fuc_base + 0x0188, i >> 6);
+		nv_wr32(priv, fuc_base + 0x0184, code->data[i]);
+	}
+}
+
+static void
+nvc0_graph_init_csdata(struct nvc0_graph_priv *priv,
+		       struct nvc0_graph_init *init,
+		       u32 falcon, u32 starstar, u32 base)
+{
+	u32 addr = init->addr;
+	u32 next = addr;
+	u32 star, temp;
+
+	nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar);
+	star = nv_rd32(priv, falcon + 0x01c4);
+	temp = nv_rd32(priv, falcon + 0x01c4);
+	if (temp > star)
+		star = temp;
+	nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star);
+
+	do {
+		if (init->addr != next) {
+			while (addr < next) {
+				u32 nr = min((int)(next - addr) / 4, 32);
+				nv_wr32(priv, falcon + 0x01c4,
+					((nr - 1) << 26) | (addr - base));
+				addr += nr * 4;
+				star += 4;
+			}
+			addr = next = init->addr;
+		}
+		next += init->count * 4;
+	} while ((init++)->count);
+
+	nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar);
+	nv_wr32(priv, falcon + 0x01c4, star);
+}
+
+int
+nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
+{
+	struct nvc0_graph_oclass *oclass = (void *)nv_object(priv)->oclass;
+	struct nvc0_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass;
+	struct nvc0_graph_init *init;
+	u32 r000260;
+	int i;
+
+	if (priv->firmware) {
+		/* load fuc microcode */
+		r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+		nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c,
+						   &priv->fuc409d);
+		nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac,
+						   &priv->fuc41ad);
+		nv_wr32(priv, 0x000260, r000260);
+
+		/* start both of them running */
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x41a10c, 0x00000000);
+		nv_wr32(priv, 0x40910c, 0x00000000);
+		nv_wr32(priv, 0x41a100, 0x00000002);
+		nv_wr32(priv, 0x409100, 0x00000002);
+		if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
+			nv_warn(priv, "0x409800 wait failed\n");
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x7fffffff);
+		nv_wr32(priv, 0x409504, 0x00000021);
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000010);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x10 timeout\n");
+			return -EBUSY;
+		}
+		priv->size = nv_rd32(priv, 0x409800);
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000016);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x16 timeout\n");
+			return -EBUSY;
+		}
+
+		nv_wr32(priv, 0x409840, 0xffffffff);
+		nv_wr32(priv, 0x409500, 0x00000000);
+		nv_wr32(priv, 0x409504, 0x00000025);
+		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+			nv_error(priv, "fuc09 req 0x25 timeout\n");
+			return -EBUSY;
+		}
+
+		if (nv_device(priv)->chipset >= 0xe0) {
+			nv_wr32(priv, 0x409800, 0x00000000);
+			nv_wr32(priv, 0x409500, 0x00000001);
+			nv_wr32(priv, 0x409504, 0x00000030);
+			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+				nv_error(priv, "fuc09 req 0x30 timeout\n");
+				return -EBUSY;
+			}
+
+			nv_wr32(priv, 0x409810, 0xb00095c8);
+			nv_wr32(priv, 0x409800, 0x00000000);
+			nv_wr32(priv, 0x409500, 0x00000001);
+			nv_wr32(priv, 0x409504, 0x00000031);
+			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+				nv_error(priv, "fuc09 req 0x31 timeout\n");
+				return -EBUSY;
+			}
+
+			nv_wr32(priv, 0x409810, 0x00080420);
+			nv_wr32(priv, 0x409800, 0x00000000);
+			nv_wr32(priv, 0x409500, 0x00000001);
+			nv_wr32(priv, 0x409504, 0x00000032);
+			if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+				nv_error(priv, "fuc09 req 0x32 timeout\n");
+				return -EBUSY;
+			}
+
+			nv_wr32(priv, 0x409614, 0x00000070);
+			nv_wr32(priv, 0x409614, 0x00000770);
+			nv_wr32(priv, 0x40802c, 0x00000001);
+		}
+
+		if (priv->data == NULL) {
+			int ret = nvc0_grctx_generate(priv);
+			if (ret) {
+				nv_error(priv, "failed to construct context\n");
+				return ret;
+			}
+		}
+
+		return 0;
+	}
+
+	/* load HUB microcode */
+	r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+	nv_wr32(priv, 0x4091c0, 0x01000000);
+	for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++)
+		nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]);
+
+	nv_wr32(priv, 0x409180, 0x01000000);
+	for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, 0x409188, i >> 6);
+		nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]);
+	}
+
+	for (i = 0; (init = cclass->hub[i]); i++) {
+		nvc0_graph_init_csdata(priv, init, 0x409000, 0x000, 0x000000);
+	}
+
+	/* load GPC microcode */
+	nv_wr32(priv, 0x41a1c0, 0x01000000);
+	for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++)
+		nv_wr32(priv, 0x41a1c4, oclass->gpccs.ucode->data.data[i]);
+
+	nv_wr32(priv, 0x41a180, 0x01000000);
+	for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) {
+		if ((i & 0x3f) == 0)
+			nv_wr32(priv, 0x41a188, i >> 6);
+		nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]);
+	}
+	nv_wr32(priv, 0x000260, r000260);
+
+	if ((init = cclass->gpc[0]))
+		nvc0_graph_init_csdata(priv, init, 0x41a000, 0x000, 0x418000);
+	if ((init = cclass->gpc[2]))
+		nvc0_graph_init_csdata(priv, init, 0x41a000, 0x004, 0x419800);
+	if ((init = cclass->gpc[3]))
+		nvc0_graph_init_csdata(priv, init, 0x41a000, 0x008, 0x41be00);
+
+	/* start HUB ucode running, it'll init the GPCs */
+	nv_wr32(priv, 0x40910c, 0x00000000);
+	nv_wr32(priv, 0x409100, 0x00000002);
+	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
+		nv_error(priv, "HUB_INIT timed out\n");
+		nvc0_graph_ctxctl_debug(priv);
+		return -EBUSY;
+	}
+
+	priv->size = nv_rd32(priv, 0x409804);
+	if (priv->data == NULL) {
+		int ret = nvc0_grctx_generate(priv);
+		if (ret) {
+			nv_error(priv, "failed to construct context\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+int
+nvc0_graph_init(struct nouveau_object *object)
+{
+	struct nvc0_graph_oclass *oclass = (void *)object->oclass;
+	struct nvc0_graph_priv *priv = (void *)object;
+	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+	u32 data[TPC_MAX / 8] = {};
+	u8  tpcnr[GPC_MAX];
+	int gpc, tpc, rop;
+	int ret, i;
+
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+	for (i = 0; oclass->mmio[i]; i++)
+		nvc0_graph_mmio(priv, oclass->mmio[i]);
+
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+		data[i / 8] |= tpc << ((i % 8) * 4);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+			priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+			priv->tpc_total);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+	}
+
+	if (nv_device(priv)->chipset != 0xd7)
+		nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
+	else
+		nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+
+	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+
+	nv_wr32(priv, 0x409c24, 0x000f0000);
+	nv_wr32(priv, 0x404000, 0xc0000000);
+	nv_wr32(priv, 0x404600, 0xc0000000);
+	nv_wr32(priv, 0x408030, 0xc0000000);
+	nv_wr32(priv, 0x40601c, 0xc0000000);
+	nv_wr32(priv, 0x404490, 0xc0000000);
+	nv_wr32(priv, 0x406018, 0xc0000000);
+	nv_wr32(priv, 0x405840, 0xc0000000);
+	nv_wr32(priv, 0x405844, 0x00ffffff);
+	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+		}
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+	}
+
+	for (rop = 0; rop < priv->rop_nr; rop++) {
+		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+	}
+
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400118, 0xffffffff);
+	nv_wr32(priv, 0x400130, 0xffffffff);
+	nv_wr32(priv, 0x40011c, 0xffffffff);
+	nv_wr32(priv, 0x400134, 0xffffffff);
+
+	nv_wr32(priv, 0x400054, 0x34ce3464);
+	return nvc0_graph_init_ctxctl(priv);
+}
+
+static void
+nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
+{
+	kfree(fuc->data);
+	fuc->data = NULL;
+}
+
 int
 nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
 		   struct nvc0_graph_fuc *fuc)
@@ -525,24 +1104,42 @@
 	return (fuc->data != NULL) ? 0 : -ENOMEM;
 }
 
-static int
+void
+nvc0_graph_dtor(struct nouveau_object *object)
+{
+	struct nvc0_graph_priv *priv = (void *)object;
+
+	kfree(priv->data);
+
+	nvc0_graph_dtor_fw(&priv->fuc409c);
+	nvc0_graph_dtor_fw(&priv->fuc409d);
+	nvc0_graph_dtor_fw(&priv->fuc41ac);
+	nvc0_graph_dtor_fw(&priv->fuc41ad);
+
+	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+	nouveau_graph_destroy(&priv->base);
+}
+
+int
 nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_oclass *bclass, void *data, u32 size,
 		struct nouveau_object **pobject)
 {
+	struct nvc0_graph_oclass *oclass = (void *)bclass;
 	struct nouveau_device *device = nv_device(parent);
 	struct nvc0_graph_priv *priv;
-	bool enable = device->chipset != 0xd7;
 	int ret, i;
 
-	ret = nouveau_graph_create(parent, engine, oclass, enable, &priv);
+	ret = nouveau_graph_create(parent, engine, bclass,
+				   (oclass->fecs.ucode != NULL), &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	nv_subdev(priv)->unit = 0x18001000;
 	nv_subdev(priv)->intr = nvc0_graph_intr;
-	nv_engine(priv)->cclass = &nvc0_graph_cclass;
 
 	priv->base.units = nvc0_graph_units;
 
@@ -556,18 +1153,6 @@
 		priv->firmware = true;
 	}
 
-	switch (nvc0_graph_class(priv)) {
-	case 0x9097:
-		nv_engine(priv)->sclass = nvc0_graph_sclass;
-		break;
-	case 0x9197:
-		nv_engine(priv)->sclass = nvc1_graph_sclass;
-		break;
-	case 0x9297:
-		nv_engine(priv)->sclass = nvc8_graph_sclass;
-		break;
-	}
-
 	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
 				&priv->unk4188b4);
 	if (ret)
@@ -621,344 +1206,65 @@
 	case 0xcf: /* 4/0/0/0, 3 */
 		priv->magic_not_rop_nr = 0x03;
 		break;
+	case 0xd7:
 	case 0xd9: /* 1/0/0/0, 1 */
 		priv->magic_not_rop_nr = 0x01;
 		break;
 	}
 
+	nv_engine(priv)->cclass = *oclass->cclass;
+	nv_engine(priv)->sclass =  oclass->sclass;
 	return 0;
 }
 
-static void
-nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
-{
-	kfree(fuc->data);
-	fuc->data = NULL;
-}
+struct nvc0_graph_init *
+nvc0_graph_init_mmio[] = {
+	nvc0_graph_init_regs,
+	nvc0_graph_init_unk40xx,
+	nvc0_graph_init_unk44xx,
+	nvc0_graph_init_unk78xx,
+	nvc0_graph_init_unk60xx,
+	nvc0_graph_init_unk58xx,
+	nvc0_graph_init_unk80xx,
+	nvc0_graph_init_gpc,
+	nvc0_graph_init_tpc,
+	nvc0_graph_init_unk88xx,
+	nvc0_graph_tpc_0,
+	NULL
+};
 
-void
-nvc0_graph_dtor(struct nouveau_object *object)
-{
-	struct nvc0_graph_priv *priv = (void *)object;
+#include "fuc/hubnvc0.fuc.h"
 
-	kfree(priv->data);
+struct nvc0_graph_ucode
+nvc0_graph_fecs_ucode = {
+	.code.data = nvc0_grhub_code,
+	.code.size = sizeof(nvc0_grhub_code),
+	.data.data = nvc0_grhub_data,
+	.data.size = sizeof(nvc0_grhub_data),
+};
 
-	nvc0_graph_dtor_fw(&priv->fuc409c);
-	nvc0_graph_dtor_fw(&priv->fuc409d);
-	nvc0_graph_dtor_fw(&priv->fuc41ac);
-	nvc0_graph_dtor_fw(&priv->fuc41ad);
+#include "fuc/gpcnvc0.fuc.h"
 
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+struct nvc0_graph_ucode
+nvc0_graph_gpccs_ucode = {
+	.code.data = nvc0_grgpc_code,
+	.code.size = sizeof(nvc0_grgpc_code),
+	.data.data = nvc0_grgpc_data,
+	.data.size = sizeof(nvc0_grgpc_data),
+};
 
-	nouveau_graph_destroy(&priv->base);
-}
-
-static void
-nvc0_graph_init_obj418880(struct nvc0_graph_priv *priv)
-{
-	int i;
-
-	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-}
-
-static void
-nvc0_graph_init_regs(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x400080, 0x003083c2);
-	nv_wr32(priv, 0x400088, 0x00006fe7);
-	nv_wr32(priv, 0x40008c, 0x00000000);
-	nv_wr32(priv, 0x400090, 0x00000030);
-	nv_wr32(priv, 0x40013c, 0x013901f7);
-	nv_wr32(priv, 0x400140, 0x00000100);
-	nv_wr32(priv, 0x400144, 0x00000000);
-	nv_wr32(priv, 0x400148, 0x00000110);
-	nv_wr32(priv, 0x400138, 0x00000000);
-	nv_wr32(priv, 0x400130, 0x00000000);
-	nv_wr32(priv, 0x400134, 0x00000000);
-	nv_wr32(priv, 0x400124, 0x00000002);
-}
-
-static void
-nvc0_graph_init_gpc_0(struct nvc0_graph_priv *priv)
-{
-	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
-	u32 data[TPC_MAX / 8];
-	u8  tpcnr[GPC_MAX];
-	int i, gpc, tpc;
-
-	nv_wr32(priv, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */
-
-	/*
-	 *      TP      ROP UNKVAL(magic_not_rop_nr)
-	 * 450: 4/0/0/0 2        3
-	 * 460: 3/4/0/0 4        1
-	 * 465: 3/4/4/0 4        7
-	 * 470: 3/3/4/4 5        5
-	 * 480: 3/4/4/4 6        6
-	 */
-
-	memset(data, 0x00, sizeof(data));
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-		data[i / 8] |= tpc << ((i % 8) * 4);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
-						  priv->tpc_nr[gpc]);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
-	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-}
-
-static void
-nvc0_graph_init_units(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x409c24, 0x000f0000);
-	nv_wr32(priv, 0x404000, 0xc0000000); /* DISPATCH */
-	nv_wr32(priv, 0x404600, 0xc0000000); /* M2MF */
-	nv_wr32(priv, 0x408030, 0xc0000000);
-	nv_wr32(priv, 0x40601c, 0xc0000000);
-	nv_wr32(priv, 0x404490, 0xc0000000); /* MACRO */
-	nv_wr32(priv, 0x406018, 0xc0000000);
-	nv_wr32(priv, 0x405840, 0xc0000000);
-	nv_wr32(priv, 0x405844, 0x00ffffff);
-	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
-	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
-}
-
-static void
-nvc0_graph_init_gpc_1(struct nvc0_graph_priv *priv)
-{
-	int gpc, tpc;
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
-		}
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-}
-
-static void
-nvc0_graph_init_rop(struct nvc0_graph_priv *priv)
-{
-	int rop;
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-}
-
-void
-nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base,
-		   struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
-{
-	int i;
-
-	nv_wr32(priv, fuc_base + 0x01c0, 0x01000000);
-	for (i = 0; i < data->size / 4; i++)
-		nv_wr32(priv, fuc_base + 0x01c4, data->data[i]);
-
-	nv_wr32(priv, fuc_base + 0x0180, 0x01000000);
-	for (i = 0; i < code->size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(priv, fuc_base + 0x0188, i >> 6);
-		nv_wr32(priv, fuc_base + 0x0184, code->data[i]);
-	}
-}
-
-static int
-nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
-{
-	u32 r000260;
-	int i;
-
-	if (priv->firmware) {
-		/* load fuc microcode */
-		r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
-		nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c,
-						   &priv->fuc409d);
-		nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac,
-						   &priv->fuc41ad);
-		nv_wr32(priv, 0x000260, r000260);
-
-		/* start both of them running */
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x41a10c, 0x00000000);
-		nv_wr32(priv, 0x40910c, 0x00000000);
-		nv_wr32(priv, 0x41a100, 0x00000002);
-		nv_wr32(priv, 0x409100, 0x00000002);
-		if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
-			nv_warn(priv, "0x409800 wait failed\n");
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x7fffffff);
-		nv_wr32(priv, 0x409504, 0x00000021);
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000010);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x10 timeout\n");
-			return -EBUSY;
-		}
-		priv->size = nv_rd32(priv, 0x409800);
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000016);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x16 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000025);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x25 timeout\n");
-			return -EBUSY;
-		}
-
-		if (priv->data == NULL) {
-			int ret = nvc0_grctx_generate(priv);
-			if (ret) {
-				nv_error(priv, "failed to construct context\n");
-				return ret;
-			}
-		}
-
-		return 0;
-	}
-
-	/* load HUB microcode */
-	r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x4091c0, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++)
-		nv_wr32(priv, 0x4091c4, nvc0_grhub_data[i]);
-
-	nv_wr32(priv, 0x409180, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(priv, 0x409188, i >> 6);
-		nv_wr32(priv, 0x409184, nvc0_grhub_code[i]);
-	}
-
-	/* load GPC microcode */
-	nv_wr32(priv, 0x41a1c0, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++)
-		nv_wr32(priv, 0x41a1c4, nvc0_grgpc_data[i]);
-
-	nv_wr32(priv, 0x41a180, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(priv, 0x41a188, i >> 6);
-		nv_wr32(priv, 0x41a184, nvc0_grgpc_code[i]);
-	}
-	nv_wr32(priv, 0x000260, r000260);
-
-	/* start HUB ucode running, it'll init the GPCs */
-	nv_wr32(priv, 0x409800, nv_device(priv)->chipset);
-	nv_wr32(priv, 0x40910c, 0x00000000);
-	nv_wr32(priv, 0x409100, 0x00000002);
-	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
-		nv_error(priv, "HUB_INIT timed out\n");
-		nvc0_graph_ctxctl_debug(priv);
-		return -EBUSY;
-	}
-
-	priv->size = nv_rd32(priv, 0x409804);
-	if (priv->data == NULL) {
-		int ret = nvc0_grctx_generate(priv);
-		if (ret) {
-			nv_error(priv, "failed to construct context\n");
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int
-nvc0_graph_init(struct nouveau_object *object)
-{
-	struct nvc0_graph_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nvc0_graph_init_obj418880(priv);
-	nvc0_graph_init_regs(priv);
-	/*nvc0_graph_init_unitplemented_magics(priv);*/
-	nvc0_graph_init_gpc_0(priv);
-	/*nvc0_graph_init_unitplemented_c242(priv);*/
-
-	nv_wr32(priv, 0x400500, 0x00010001);
-	nv_wr32(priv, 0x400100, 0xffffffff);
-	nv_wr32(priv, 0x40013c, 0xffffffff);
-
-	nvc0_graph_init_units(priv);
-	nvc0_graph_init_gpc_1(priv);
-	nvc0_graph_init_rop(priv);
-
-	nv_wr32(priv, 0x400108, 0xffffffff);
-	nv_wr32(priv, 0x400138, 0xffffffff);
-	nv_wr32(priv, 0x400118, 0xffffffff);
-	nv_wr32(priv, 0x400130, 0xffffffff);
-	nv_wr32(priv, 0x40011c, 0xffffffff);
-	nv_wr32(priv, 0x400134, 0xffffffff);
-	nv_wr32(priv, 0x400054, 0x34ce3464);
-
-	ret = nvc0_graph_init_ctxctl(priv);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass
-nvc0_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0xc0),
-	.ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nvc0_graph_oclass = &(struct nvc0_graph_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xc0),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nvc0_graph_ctor,
 		.dtor = nvc0_graph_dtor,
 		.init = nvc0_graph_init,
 		.fini = _nouveau_graph_fini,
 	},
-};
+	.cclass = &nvc0_grctx_oclass,
+	.sclass =  nvc0_graph_sclass,
+	.mmio = nvc0_graph_init_mmio,
+	.fecs.ucode = &nvc0_graph_fecs_ucode,
+	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
index c870dad..ea17a80 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
@@ -38,8 +38,8 @@
 #include <engine/fifo.h>
 #include <engine/graph.h>
 
-#define GPC_MAX 4
-#define TPC_MAX 32
+#define GPC_MAX 32
+#define TPC_MAX (GPC_MAX * 8)
 
 #define ROP_BCAST(r)      (0x408800 + (r))
 #define ROP_UNIT(u, r)    (0x410000 + (u) * 0x400 + (r))
@@ -102,74 +102,187 @@
 	} data[4];
 };
 
-static inline u32
-nvc0_graph_class(void *obj)
-{
-	struct nouveau_device *device = nv_device(obj);
-
-	switch (device->chipset) {
-	case 0xc0:
-	case 0xc3:
-	case 0xc4:
-	case 0xce: /* guess, mmio trace shows only 0x9097 state */
-	case 0xcf: /* guess, mmio trace shows only 0x9097 state */
-		return 0x9097;
-	case 0xc1:
-		return 0x9197;
-	case 0xc8:
-	case 0xd9:
-	case 0xd7:
-		return 0x9297;
-	case 0xe4:
-	case 0xe7:
-	case 0xe6:
-		return 0xa097;
-	default:
-		return 0;
-	}
-}
-
-void nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data);
-
-static inline void
-nv_mthd(struct nvc0_graph_priv *priv, u32 class, u32 mthd, u32 data)
-{
-	nv_wr32(priv, 0x40448c, data);
-	nv_wr32(priv, 0x404488, 0x80000000 | (mthd << 14) | class);
-}
-
-struct nvc0_grctx {
-	struct nvc0_graph_priv *priv;
-	struct nvc0_graph_data *data;
-	struct nvc0_graph_mmio *mmio;
-	struct nouveau_gpuobj *chan;
-	int buffer_nr;
-	u64 buffer[4];
-	u64 addr;
-};
-
 int  nvc0_grctx_generate(struct nvc0_graph_priv *);
-int  nvc0_grctx_init(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nvc0_grctx_data(struct nvc0_grctx *, u32, u32, u32);
-void nvc0_grctx_mmio(struct nvc0_grctx *, u32, u32, u32, u32);
-int  nvc0_grctx_fini(struct nvc0_grctx *);
 
-int  nve0_grctx_generate(struct nvc0_graph_priv *);
-
-#define mmio_data(s,a,p) nvc0_grctx_data(&info, (s), (a), (p))
-#define mmio_list(r,d,s,b) nvc0_grctx_mmio(&info, (r), (d), (s), (b))
-
-void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *);
-int  nvc0_graph_ctor_fw(struct nvc0_graph_priv *, const char *,
-			struct nvc0_graph_fuc *);
-void nvc0_graph_dtor(struct nouveau_object *);
-void nvc0_graph_init_fw(struct nvc0_graph_priv *, u32 base,
-			struct nvc0_graph_fuc *, struct nvc0_graph_fuc *);
 int  nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *,
 			     struct nouveau_oclass *, void *, u32,
 			     struct nouveau_object **);
 void nvc0_graph_context_dtor(struct nouveau_object *);
 
-u64 nvc0_graph_units(struct nouveau_graph *);
+void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *);
+
+u64  nvc0_graph_units(struct nouveau_graph *);
+int  nvc0_graph_ctor(struct nouveau_object *, struct nouveau_object *,
+		     struct nouveau_oclass *, void *data, u32 size,
+		     struct nouveau_object **);
+void nvc0_graph_dtor(struct nouveau_object *);
+int  nvc0_graph_init(struct nouveau_object *);
+int  nve4_graph_init(struct nouveau_object *);
+
+extern struct nouveau_oclass nvc0_graph_sclass[];
+
+extern struct nouveau_oclass nvc8_graph_sclass[];
+
+struct nvc0_graph_init {
+	u32 addr;
+	u8  count;
+	u8  pitch;
+	u32 data;
+};
+
+struct nvc0_graph_mthd {
+	u16 oclass;
+	struct nvc0_graph_init *init;
+};
+
+struct nvc0_grctx {
+	struct nvc0_graph_priv *priv;
+	struct nvc0_graph_data *data;
+	struct nvc0_graph_mmio *mmio;
+	int buffer_nr;
+	u64 buffer[4];
+	u64 addr;
+};
+
+struct nvc0_grctx_oclass {
+	struct nouveau_oclass base;
+	/* main context generation function */
+	void  (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *);
+	/* context-specific modify-on-first-load list generation function */
+	void  (*mods)(struct nvc0_graph_priv *, struct nvc0_grctx *);
+	void  (*unkn)(struct nvc0_graph_priv *);
+	/* mmio context data */
+	struct nvc0_graph_init **hub;
+	struct nvc0_graph_init **gpc;
+	/* indirect context data, generated with icmds/mthds */
+	struct nvc0_graph_init *icmd;
+	struct nvc0_graph_mthd *mthd;
+};
+
+struct nvc0_graph_ucode {
+	struct nvc0_graph_fuc code;
+	struct nvc0_graph_fuc data;
+};
+
+extern struct nvc0_graph_ucode nvc0_graph_fecs_ucode;
+extern struct nvc0_graph_ucode nvc0_graph_gpccs_ucode;
+
+struct nvc0_graph_oclass {
+	struct nouveau_oclass base;
+	struct nouveau_oclass **cclass;
+	struct nouveau_oclass *sclass;
+	struct nvc0_graph_init **mmio;
+	struct {
+		struct nvc0_graph_ucode *ucode;
+	} fecs;
+	struct {
+		struct nvc0_graph_ucode *ucode;
+	} gpccs;
+};
+
+void nvc0_graph_mmio(struct nvc0_graph_priv *, struct nvc0_graph_init *);
+void nvc0_graph_icmd(struct nvc0_graph_priv *, struct nvc0_graph_init *);
+void nvc0_graph_mthd(struct nvc0_graph_priv *, struct nvc0_graph_mthd *);
+int  nvc0_graph_init_ctxctl(struct nvc0_graph_priv *);
+
+extern struct nvc0_graph_init nvc0_graph_init_regs[];
+extern struct nvc0_graph_init nvc0_graph_init_unk40xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk44xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk78xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk60xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk58xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk80xx[];
+extern struct nvc0_graph_init nvc0_graph_init_gpc[];
+extern struct nvc0_graph_init nvc0_graph_init_unk88xx[];
+extern struct nvc0_graph_init nvc0_graph_tpc_0[];
+
+extern struct nvc0_graph_init nvc3_graph_init_unk58xx[];
+
+extern struct nvc0_graph_init nvd9_graph_init_unk58xx[];
+extern struct nvc0_graph_init nvd9_graph_init_unk64xx[];
+
+extern struct nvc0_graph_init nve4_graph_init_regs[];
+extern struct nvc0_graph_init nve4_graph_init_unk[];
+extern struct nvc0_graph_init nve4_graph_init_unk88xx[];
+
+int  nvc0_grctx_generate(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc0_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *);
+void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *);
+
+extern struct nouveau_oclass *nvc0_grctx_oclass;
+extern struct nvc0_graph_init *nvc0_grctx_init_hub[];
+extern struct nvc0_graph_init nvc0_grctx_init_base[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk40xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk44xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk46xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk47xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk60xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk64xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk78xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk80xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_gpc_0[];
+extern struct nvc0_graph_init nvc0_grctx_init_gpc_1[];
+extern struct nvc0_graph_init nvc0_grctx_init_tpc[];
+extern struct nvc0_graph_init nvc0_grctx_init_icmd[];
+extern struct nvc0_graph_init nvd9_grctx_init_icmd[]; //
+
+extern struct nvc0_graph_mthd nvc0_grctx_init_mthd[];
+extern struct nvc0_graph_init nvc0_grctx_init_902d[];
+extern struct nvc0_graph_init nvc0_grctx_init_9039[];
+extern struct nvc0_graph_init nvc0_grctx_init_90c0[];
+extern struct nvc0_graph_init nvc0_grctx_init_mthd_magic[];
+
+void nvc1_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *);
+extern struct nouveau_oclass *nvc1_grctx_oclass;
+extern struct nvc0_graph_init nvc1_grctx_init_9097[];
+
+extern struct nouveau_oclass *nvc3_grctx_oclass;
+
+extern struct nouveau_oclass *nvc8_grctx_oclass;
+extern struct nvc0_graph_init nvc8_grctx_init_9197[];
+extern struct nvc0_graph_init nvc8_grctx_init_9297[];
+
+extern struct nouveau_oclass *nvd7_grctx_oclass;
+
+extern struct nouveau_oclass *nvd9_grctx_oclass;
+extern struct nvc0_graph_init nvd9_grctx_init_rop[];
+extern struct nvc0_graph_mthd nvd9_grctx_init_mthd[];
+
+void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nve4_grctx_generate_unkn(struct nvc0_graph_priv *);
+extern struct nouveau_oclass *nve4_grctx_oclass;
+extern struct nvc0_graph_init nve4_grctx_init_unk46xx[];
+extern struct nvc0_graph_init nve4_grctx_init_unk47xx[];
+extern struct nvc0_graph_init nve4_grctx_init_unk58xx[];
+extern struct nvc0_graph_init nve4_grctx_init_unk80xx[];
+extern struct nvc0_graph_init nve4_grctx_init_unk90xx[];
+
+extern struct nouveau_oclass *nvf0_grctx_oclass;
+
+#define mmio_data(s,a,p) do {                                                  \
+	info->buffer[info->buffer_nr] = round_up(info->addr, (a));             \
+	info->addr = info->buffer[info->buffer_nr++] + (s);                    \
+	info->data->size = (s);                                                \
+	info->data->align = (a);                                               \
+	info->data->access = (p);                                              \
+	info->data++;                                                          \
+} while(0)
+
+#define mmio_list(r,d,s,b) do {                                                \
+	info->mmio->addr = (r);                                                \
+	info->mmio->data = (d);                                                \
+	info->mmio->shift = (s);                                               \
+	info->mmio->buffer = (b);                                              \
+	info->mmio++;                                                          \
+	nv_wr32(priv, (r), (d) | ((s) ? (info->buffer[(b)] >> (s)) : 0));      \
+} while(0)
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
new file mode 100644
index 0000000..bc4a469
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nvc1_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0x9039, &nouveau_object_ofuncs },
+	{ 0x9097, &nouveau_object_ofuncs },
+	{ 0x90c0, &nouveau_object_ofuncs },
+	{ 0x9197, &nouveau_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static struct nvc0_graph_init
+nvc1_graph_init_gpc[] = {
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x00000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{ 0x418814,   3, 0x04, 0x00000000 },
+	{ 0x418b04,   1, 0x04, 0x00000000 },
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000003 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x41900c,   1, 0x04, 0x00000000 },
+	{ 0x419018,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvc1_graph_init_tpc[] = {
+	{ 0x419d08,   2, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x41980c,   2, 0x04, 0x00000000 },
+	{ 0x419814,   1, 0x04, 0x00000004 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc5 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{ 0x419880,   1, 0x04, 0x00000002 },
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x80000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00008bf4 },
+	{ 0x419cbc,   1, 0x04, 0x28137606 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419bd4,   1, 0x04, 0x00800000 },
+	{ 0x419bdc,   1, 0x04, 0x00000000 },
+	{ 0x419d2c,   1, 0x04, 0x00000000 },
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00001100 },
+	{ 0x419eac,   1, 0x04, 0x11100702 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0e063818 },
+	{ 0x419ecc,   1, 0x04, 0x0e060e06 },
+	{ 0x419ed0,   1, 0x04, 0x00003818 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init *
+nvc1_graph_init_mmio[] = {
+	nvc0_graph_init_regs,
+	nvc0_graph_init_unk40xx,
+	nvc0_graph_init_unk44xx,
+	nvc0_graph_init_unk78xx,
+	nvc0_graph_init_unk60xx,
+	nvc3_graph_init_unk58xx,
+	nvc0_graph_init_unk80xx,
+	nvc1_graph_init_gpc,
+	nvc1_graph_init_tpc,
+	nvc0_graph_init_unk88xx,
+	nvc0_graph_tpc_0,
+	NULL
+};
+
+struct nouveau_oclass *
+nvc1_graph_oclass = &(struct nvc0_graph_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xc1),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nvc0_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+	.cclass = &nvc1_grctx_oclass,
+	.sclass = nvc1_graph_sclass,
+	.mmio = nvc1_graph_init_mmio,
+	.fecs.ucode = &nvc0_graph_fecs_ucode,
+	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c
new file mode 100644
index 0000000..d44b3b3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvc0_graph_init
+nvc3_graph_init_unk58xx[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x00002834 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvc3_graph_init_tpc[] = {
+	{ 0x419d08,   2, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x41980c,   3, 0x04, 0x00000000 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc5 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{ 0x419880,   1, 0x04, 0x00000002 },
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x80000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00008bf4 },
+	{ 0x419cbc,   1, 0x04, 0x28137606 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419bd4,   1, 0x04, 0x00800000 },
+	{ 0x419bdc,   1, 0x04, 0x00000000 },
+	{ 0x419d2c,   1, 0x04, 0x00000000 },
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00001100 },
+	{ 0x419eac,   1, 0x04, 0x11100702 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0e063818 },
+	{ 0x419ecc,   1, 0x04, 0x0e060e06 },
+	{ 0x419ed0,   1, 0x04, 0x00003818 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init *
+nvc3_graph_init_mmio[] = {
+	nvc0_graph_init_regs,
+	nvc0_graph_init_unk40xx,
+	nvc0_graph_init_unk44xx,
+	nvc0_graph_init_unk78xx,
+	nvc0_graph_init_unk60xx,
+	nvc3_graph_init_unk58xx,
+	nvc0_graph_init_unk80xx,
+	nvc0_graph_init_gpc,
+	nvc3_graph_init_tpc,
+	nvc0_graph_init_unk88xx,
+	nvc0_graph_tpc_0,
+	NULL
+};
+
+struct nouveau_oclass *
+nvc3_graph_oclass = &(struct nvc0_graph_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xc3),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nvc0_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+	.cclass = &nvc3_grctx_oclass,
+	.sclass = nvc0_graph_sclass,
+	.mmio = nvc3_graph_init_mmio,
+	.fecs.ucode = &nvc0_graph_fecs_ucode,
+	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
new file mode 100644
index 0000000..02845e5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nouveau_oclass
+nvc8_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0x9039, &nouveau_object_ofuncs },
+	{ 0x9097, &nouveau_object_ofuncs },
+	{ 0x90c0, &nouveau_object_ofuncs },
+	{ 0x9197, &nouveau_object_ofuncs },
+	{ 0x9297, &nouveau_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static struct nvc0_graph_init
+nvc8_graph_init_gpc[] = {
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x80000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{ 0x418814,   3, 0x04, 0x00000000 },
+	{ 0x418b04,   1, 0x04, 0x00000000 },
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000050 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x41900c,   1, 0x04, 0x00000000 },
+	{ 0x419018,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvc8_graph_init_tpc[] = {
+	{ 0x419d08,   2, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x41980c,   3, 0x04, 0x00000000 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc5 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x80000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00008bf4 },
+	{ 0x419cbc,   1, 0x04, 0x28137606 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419bd4,   1, 0x04, 0x00800000 },
+	{ 0x419bdc,   1, 0x04, 0x00000000 },
+	{ 0x419d2c,   1, 0x04, 0x00000000 },
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00001100 },
+	{ 0x419eac,   1, 0x04, 0x11100f02 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x06060618 },
+	{ 0x419ed0,   1, 0x04, 0x0eff0e38 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init *
+nvc8_graph_init_mmio[] = {
+	nvc0_graph_init_regs,
+	nvc0_graph_init_unk40xx,
+	nvc0_graph_init_unk44xx,
+	nvc0_graph_init_unk78xx,
+	nvc0_graph_init_unk60xx,
+	nvc0_graph_init_unk58xx,
+	nvc0_graph_init_unk80xx,
+	nvc8_graph_init_gpc,
+	nvc8_graph_init_tpc,
+	nvc0_graph_init_unk88xx,
+	nvc0_graph_tpc_0,
+	NULL
+};
+
+struct nouveau_oclass *
+nvc8_graph_oclass = &(struct nvc0_graph_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xc8),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nvc0_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+	.cclass = &nvc8_grctx_oclass,
+	.sclass = nvc8_graph_sclass,
+	.mmio = nvc8_graph_init_mmio,
+	.fecs.ucode = &nvc0_graph_fecs_ucode,
+	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
new file mode 100644
index 0000000..5052d7a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+#include "fuc/hubnvd7.fuc.h"
+
+struct nvc0_graph_ucode
+nvd7_graph_fecs_ucode = {
+	.code.data = nvd7_grhub_code,
+	.code.size = sizeof(nvd7_grhub_code),
+	.data.data = nvd7_grhub_data,
+	.data.size = sizeof(nvd7_grhub_data),
+};
+
+#include "fuc/gpcnvd7.fuc.h"
+
+struct nvc0_graph_ucode
+nvd7_graph_gpccs_ucode = {
+	.code.data = nvd7_grgpc_code,
+	.code.size = sizeof(nvd7_grgpc_code),
+	.data.data = nvd7_grgpc_data,
+	.data.size = sizeof(nvd7_grgpc_data),
+};
+
+static struct nvc0_graph_init
+nvd7_graph_init_gpc[] = {
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{ 0x4184a4,   2, 0x04, 0x00000000 },
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x00000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{ 0x418814,   3, 0x04, 0x00000000 },
+	{ 0x418b04,   1, 0x04, 0x00000000 },
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c64,   1, 0x04, 0x00000000 },
+	{ 0x418c68,   1, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{ 0x418cb4,   2, 0x04, 0x00000000 },
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418d28,   1, 0x04, 0x00000000 },
+	{ 0x418f00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418f20,   2, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000003 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x418e1c,   1, 0x04, 0x00000000 },
+	{ 0x418e20,   1, 0x04, 0x00000000 },
+	{ 0x41900c,   1, 0x04, 0x00000000 },
+	{ 0x419018,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd7_graph_init_tpc[] = {
+	{ 0x419d08,   2, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x419ab4,   1, 0x04, 0x00000000 },
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x00005bc8 },
+	{ 0x419850,   2, 0x04, 0x00000000 },
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x80000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00008bf4 },
+	{ 0x419cbc,   1, 0x04, 0x28137606 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x02001100 },
+	{ 0x419eac,   1, 0x04, 0x11100702 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0e063818 },
+	{ 0x419ecc,   1, 0x04, 0x0e060e06 },
+	{ 0x419ed0,   1, 0x04, 0x00003818 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd7_graph_init_tpc_0[] = {
+	{ 0x40402c,   1, 0x04, 0x00000000 },
+	{ 0x4040f0,   1, 0x04, 0x00000000 },
+	{ 0x404174,   1, 0x04, 0x00000000 },
+	{ 0x503018,   1, 0x04, 0x00000001 },
+	{}
+};
+
+static struct nvc0_graph_init *
+nvd7_graph_init_mmio[] = {
+	nvc0_graph_init_regs,
+	nvc0_graph_init_unk40xx,
+	nvc0_graph_init_unk44xx,
+	nvc0_graph_init_unk78xx,
+	nvc0_graph_init_unk60xx,
+	nvd9_graph_init_unk64xx,
+	nvd9_graph_init_unk58xx,
+	nvc0_graph_init_unk80xx,
+	nvd7_graph_init_gpc,
+	nvd7_graph_init_tpc,
+	nve4_graph_init_unk,
+	nvc0_graph_init_unk88xx,
+	nvd7_graph_init_tpc_0,
+	NULL
+};
+
+struct nouveau_oclass *
+nvd7_graph_oclass = &(struct nvc0_graph_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xd7),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nvc0_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+	.cclass = &nvd7_grctx_oclass,
+	.sclass = nvc8_graph_sclass,
+	.mmio = nvd7_graph_init_mmio,
+	.fecs.ucode = &nvd7_graph_fecs_ucode,
+	.gpccs.ucode = &nvd7_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
new file mode 100644
index 0000000..652098e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvc0_graph_init
+nvd9_graph_init_unk64xx[] = {
+	{ 0x4064f0,   3, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nvd9_graph_init_unk58xx[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x00002834 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{ 0x405928,   1, 0x04, 0x00000000 },
+	{ 0x40592c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd9_graph_init_gpc[] = {
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{ 0x4184a4,   2, 0x04, 0x00000000 },
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x00000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{ 0x418814,   3, 0x04, 0x00000000 },
+	{ 0x418b04,   1, 0x04, 0x00000000 },
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c64,   1, 0x04, 0x00000000 },
+	{ 0x418c68,   1, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{ 0x418cb4,   2, 0x04, 0x00000000 },
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418d28,   1, 0x04, 0x00000000 },
+	{ 0x418d2c,   1, 0x04, 0x00000000 },
+	{ 0x418f00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418f20,   2, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000003 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x418e1c,   1, 0x04, 0x00000000 },
+	{ 0x418e20,   1, 0x04, 0x00000000 },
+	{ 0x41900c,   1, 0x04, 0x00000000 },
+	{ 0x419018,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvd9_graph_init_tpc[] = {
+	{ 0x419d08,   2, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x419ab4,   1, 0x04, 0x00000000 },
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419810,   1, 0x04, 0x00000000 },
+	{ 0x419814,   1, 0x04, 0x00000004 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x41984c,   1, 0x04, 0x0000a918 },
+	{ 0x419850,   4, 0x04, 0x00000000 },
+	{ 0x419880,   1, 0x04, 0x00000002 },
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x80000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00008bf4 },
+	{ 0x419cbc,   1, 0x04, 0x28137606 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419bd4,   1, 0x04, 0x00800000 },
+	{ 0x419bdc,   1, 0x04, 0x00000000 },
+	{ 0x419bf8,   1, 0x04, 0x00000000 },
+	{ 0x419bfc,   1, 0x04, 0x00000000 },
+	{ 0x419d2c,   1, 0x04, 0x00000000 },
+	{ 0x419d48,   1, 0x04, 0x00000000 },
+	{ 0x419d4c,   1, 0x04, 0x00000000 },
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x02001100 },
+	{ 0x419eac,   1, 0x04, 0x11100702 },
+	{ 0x419eb0,   1, 0x04, 0x00000003 },
+	{ 0x419eb4,   4, 0x04, 0x00000000 },
+	{ 0x419ec8,   1, 0x04, 0x0e063818 },
+	{ 0x419ecc,   1, 0x04, 0x0e060e06 },
+	{ 0x419ed0,   1, 0x04, 0x00003818 },
+	{ 0x419ed4,   1, 0x04, 0x011104f1 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f2c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init *
+nvd9_graph_init_mmio[] = {
+	nvc0_graph_init_regs,
+	nvc0_graph_init_unk40xx,
+	nvc0_graph_init_unk44xx,
+	nvc0_graph_init_unk78xx,
+	nvc0_graph_init_unk60xx,
+	nvd9_graph_init_unk64xx,
+	nvd9_graph_init_unk58xx,
+	nvc0_graph_init_unk80xx,
+	nvd9_graph_init_gpc,
+	nvd9_graph_init_tpc,
+	nvc0_graph_init_unk88xx,
+	nvc0_graph_tpc_0,
+	NULL
+};
+
+struct nouveau_oclass *
+nvd9_graph_oclass = &(struct nvc0_graph_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xd9),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nvc0_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+	.cclass = &nvd9_grctx_oclass,
+	.sclass = nvc8_graph_sclass,
+	.mmio = nvd9_graph_init_mmio,
+	.fecs.ucode = &nvc0_graph_fecs_ucode,
+	.gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
deleted file mode 100644
index 678c16f..0000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-#include "fuc/hubnve0.fuc.h"
-#include "fuc/gpcnve0.fuc.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_graph_sclass[] = {
-	{ 0x902d, &nouveau_object_ofuncs },
-	{ 0xa040, &nouveau_object_ofuncs },
-	{ 0xa097, &nouveau_object_ofuncs },
-	{ 0xa0c0, &nouveau_object_ofuncs },
-	{ 0xa0b5, &nouveau_object_ofuncs },
-	{}
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_graph_cclass = {
-	.handle = NV_ENGCTX(GR, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nvc0_graph_context_ctor,
-		.dtor = nvc0_graph_context_dtor,
-		.init = _nouveau_graph_context_init,
-		.fini = _nouveau_graph_context_fini,
-		.rd32 = _nouveau_graph_context_rd32,
-		.wr32 = _nouveau_graph_context_wr32,
-	},
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static void
-nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
-{
-	u32 ustat = nv_rd32(priv, 0x409c18);
-
-	if (ustat & 0x00000001)
-		nv_error(priv, "CTXCTRL ucode error\n");
-	if (ustat & 0x00080000)
-		nv_error(priv, "CTXCTRL watchdog timeout\n");
-	if (ustat & ~0x00080001)
-		nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
-
-	nvc0_graph_ctxctl_debug(priv);
-	nv_wr32(priv, 0x409c20, ustat);
-}
-
-static const struct nouveau_enum nve0_mp_warp_error[] = {
-	{ 0x00, "NO_ERROR" },
-	{ 0x01, "STACK_MISMATCH" },
-	{ 0x05, "MISALIGNED_PC" },
-	{ 0x08, "MISALIGNED_GPR" },
-	{ 0x09, "INVALID_OPCODE" },
-	{ 0x0d, "GPR_OUT_OF_BOUNDS" },
-	{ 0x0e, "MEM_OUT_OF_BOUNDS" },
-	{ 0x0f, "UNALIGNED_MEM_ACCESS" },
-	{ 0x11, "INVALID_PARAM" },
-	{}
-};
-
-static const struct nouveau_enum nve0_mp_global_error[] = {
-	{ 2, "MULTIPLE_WARP_ERRORS" },
-	{ 3, "OUT_OF_STACK_SPACE" },
-	{}
-};
-
-static const struct nouveau_enum nve0_gpc_rop_error[] = {
-	{ 1, "RT_PITCH_OVERRUN" },
-	{ 4, "RT_WIDTH_OVERRUN" },
-	{ 5, "RT_HEIGHT_OVERRUN" },
-	{ 7, "ZETA_STORAGE_TYPE_MISMATCH" },
-	{ 8, "RT_STORAGE_TYPE_MISMATCH" },
-	{ 10, "RT_LINEAR_MISMATCH" },
-	{}
-};
-
-static const struct nouveau_enum nve0_sked_error[] = {
-	{ 7, "CONSTANT_BUFFER_SIZE" },
-	{ 9, "LOCAL_MEMORY_SIZE_POS" },
-	{ 10, "LOCAL_MEMORY_SIZE_NEG" },
-	{ 11, "WARP_CSTACK_SIZE" },
-	{ 12, "TOTAL_TEMP_SIZE" },
-	{ 13, "REGISTER_COUNT" },
-	{ 18, "TOTAL_THREADS" },
-	{ 20, "PROGRAM_OFFSET" },
-	{ 21, "SHARED_MEMORY_SIZE" },
-	{ 25, "SHARED_CONFIG_TOO_SMALL" },
-	{ 26, "TOTAL_REGISTER_COUNT" },
-	{}
-};
-
-static void
-nve0_graph_mp_trap(struct nvc0_graph_priv *priv, int gpc, int tp)
-{
-	int i;
-	u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x648));
-	u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x650));
-
-	nv_error(priv, "GPC%i/TP%i/MP trap:", gpc, tp);
-
-	for (i = 0; i <= 31; ++i) {
-		if (!(gerr & (1 << i)))
-			continue;
-		pr_cont(" ");
-		nouveau_enum_print(nve0_mp_global_error, i);
-	}
-	if (werr) {
-		pr_cont(" ");
-		nouveau_enum_print(nve0_mp_warp_error, werr & 0xffff);
-	}
-	pr_cont("\n");
-
-	/* disable MP trap to avoid spam */
-	nv_mask(priv, TPC_UNIT(gpc, tp, 0x50c), 0x2, 0x0);
-
-	/* TODO: figure out how to resume after an MP trap */
-}
-
-static void
-nve0_graph_tp_trap(struct nvc0_graph_priv *priv, int gpc, int tp)
-{
-	u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x508));
-
-	if (stat & 0x1) {
-		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x224));
-		nv_error(priv, "GPC%i/TP%i/TEX trap: %08x\n",
-			 gpc, tp, trap);
-
-		nv_wr32(priv, TPC_UNIT(gpc, tp, 0x224), 0xc0000000);
-		stat &= ~0x1;
-	}
-
-	if (stat & 0x2) {
-		nve0_graph_mp_trap(priv, gpc, tp);
-		stat &= ~0x2;
-	}
-
-	if (stat & 0x4) {
-		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x084));
-		nv_error(priv, "GPC%i/TP%i/POLY trap: %08x\n",
-			 gpc, tp, trap);
-
-		nv_wr32(priv, TPC_UNIT(gpc, tp, 0x084), 0xc0000000);
-		stat &= ~0x4;
-	}
-
-	if (stat & 0x8) {
-		u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x48c));
-		nv_error(priv, "GPC%i/TP%i/L1C trap: %08x\n",
-			 gpc, tp, trap);
-
-		nv_wr32(priv, TPC_UNIT(gpc, tp, 0x48c), 0xc0000000);
-		stat &= ~0x8;
-	}
-
-	if (stat) {
-		nv_error(priv, "GPC%i/TP%i: unknown stat %08x\n",
-			 gpc, tp, stat);
-	}
-}
-
-static void
-nve0_graph_gpc_trap(struct nvc0_graph_priv *priv)
-{
-	const u32 mask = nv_rd32(priv, 0x400118);
-	int gpc;
-
-	for (gpc = 0; gpc < 4; ++gpc) {
-		u32 stat;
-		int tp;
-
-		if (!(mask & (1 << gpc)))
-			continue;
-		stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90));
-
-		if (stat & 0x0001) {
-			u32 trap[4];
-			int i;
-
-			trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
-			trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434));
-			trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438));
-			trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c));
-
-			nv_error(priv, "GPC%i/PROP trap:", gpc);
-			for (i = 0; i <= 29; ++i) {
-				if (!(trap[0] & (1 << i)))
-					continue;
-				pr_cont(" ");
-				nouveau_enum_print(nve0_gpc_rop_error, i);
-			}
-			pr_cont("\n");
-
-			nv_error(priv, "x = %u, y = %u, "
-				 "format = %x, storage type = %x\n",
-				 trap[1] & 0xffff,
-				 trap[1] >> 16,
-				 (trap[2] >> 8) & 0x3f,
-				 trap[3] & 0xff);
-
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-			stat &= ~0x0001;
-		}
-
-		if (stat & 0x0002) {
-			u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900));
-			nv_error(priv, "GPC%i/ZCULL trap: %08x\n", gpc,
-				 trap);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-			stat &= ~0x0002;
-		}
-
-		if (stat & 0x0004) {
-			u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028));
-			nv_error(priv, "GPC%i/CCACHE trap: %08x\n", gpc,
-				 trap);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-			stat &= ~0x0004;
-		}
-
-		if (stat & 0x0008) {
-			u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824));
-			nv_error(priv, "GPC%i/ESETUP trap %08x\n", gpc,
-				 trap);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-			stat &= ~0x0008;
-		}
-
-		for (tp = 0; tp < 8; ++tp) {
-			if (stat & (1 << (16 + tp)))
-				nve0_graph_tp_trap(priv, gpc, tp);
-		}
-		stat &= ~0xff0000;
-
-		if (stat) {
-			nv_error(priv, "GPC%i: unknown stat %08x\n",
-				 gpc, stat);
-		}
-	}
-}
-
-
-static void
-nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst,
-		struct nouveau_object *engctx)
-{
-	u32 trap = nv_rd32(priv, 0x400108);
-	int i;
-	int rop;
-
-	if (trap & 0x00000001) {
-		u32 stat = nv_rd32(priv, 0x404000);
-		nv_error(priv, "DISPATCH ch %d [0x%010llx %s] 0x%08x\n",
-			 chid, inst, nouveau_client_name(engctx), stat);
-		nv_wr32(priv, 0x404000, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x00000001);
-		trap &= ~0x00000001;
-	}
-
-	if (trap & 0x00000010) {
-		u32 stat = nv_rd32(priv, 0x405840);
-		nv_error(priv, "SHADER ch %d [0x%010llx %s] 0x%08x\n",
-			 chid, inst, nouveau_client_name(engctx), stat);
-		nv_wr32(priv, 0x405840, 0xc0000000);
-		nv_wr32(priv, 0x400108, 0x00000010);
-		trap &= ~0x00000010;
-	}
-
-	if (trap & 0x00000100) {
-		u32 stat = nv_rd32(priv, 0x407020);
-		nv_error(priv, "SKED ch %d [0x%010llx %s]:",
-			 chid, inst, nouveau_client_name(engctx));
-
-		for (i = 0; i <= 29; ++i) {
-			if (!(stat & (1 << i)))
-				continue;
-			pr_cont(" ");
-			nouveau_enum_print(nve0_sked_error, i);
-		}
-		pr_cont("\n");
-
-		if (stat & 0x3fffffff)
-			nv_wr32(priv, 0x407020, 0x40000000);
-		nv_wr32(priv, 0x400108, 0x00000100);
-		trap &= ~0x00000100;
-	}
-
-	if (trap & 0x01000000) {
-		nv_error(priv, "GPC ch %d [0x%010llx %s]:\n",
-			 chid, inst, nouveau_client_name(engctx));
-		nve0_graph_gpc_trap(priv);
-		trap &= ~0x01000000;
-	}
-
-	if (trap & 0x02000000) {
-		for (rop = 0; rop < priv->rop_nr; rop++) {
-			u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
-			u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
-			nv_error(priv,
-				 "ROP%d ch %d [0x%010llx %s] 0x%08x 0x%08x\n",
-				 rop, chid, inst, nouveau_client_name(engctx),
-				 statz, statc);
-			nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
-			nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
-		}
-		nv_wr32(priv, 0x400108, 0x02000000);
-		trap &= ~0x02000000;
-	}
-
-	if (trap) {
-		nv_error(priv, "TRAP ch %d [0x%010llx %s] 0x%08x\n",
-			 chid, inst, nouveau_client_name(engctx), trap);
-		nv_wr32(priv, 0x400108, trap);
-	}
-}
-
-static void
-nve0_graph_intr(struct nouveau_subdev *subdev)
-{
-	struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
-	struct nouveau_engine *engine = nv_engine(subdev);
-	struct nouveau_object *engctx;
-	struct nouveau_handle *handle;
-	struct nvc0_graph_priv *priv = (void *)subdev;
-	u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff;
-	u32 stat = nv_rd32(priv, 0x400100);
-	u32 addr = nv_rd32(priv, 0x400704);
-	u32 mthd = (addr & 0x00003ffc);
-	u32 subc = (addr & 0x00070000) >> 16;
-	u32 data = nv_rd32(priv, 0x400708);
-	u32 code = nv_rd32(priv, 0x400110);
-	u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
-	int chid;
-
-	engctx = nouveau_engctx_get(engine, inst);
-	chid   = pfifo->chid(pfifo, engctx);
-
-	if (stat & 0x00000010) {
-		handle = nouveau_handle_get_class(engctx, class);
-		if (!handle || nv_call(handle->object, mthd, data)) {
-			nv_error(priv,
-				 "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-				 chid, inst, nouveau_client_name(engctx), subc,
-				 class, mthd, data);
-		}
-		nouveau_handle_put(handle);
-		nv_wr32(priv, 0x400100, 0x00000010);
-		stat &= ~0x00000010;
-	}
-
-	if (stat & 0x00000020) {
-		nv_error(priv,
-			 "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			 chid, inst, nouveau_client_name(engctx), subc, class,
-			 mthd, data);
-		nv_wr32(priv, 0x400100, 0x00000020);
-		stat &= ~0x00000020;
-	}
-
-	if (stat & 0x00100000) {
-		nv_error(priv, "DATA_ERROR [");
-		nouveau_enum_print(nv50_data_error_names, code);
-		pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
-			chid, inst, nouveau_client_name(engctx), subc, class,
-			mthd, data);
-		nv_wr32(priv, 0x400100, 0x00100000);
-		stat &= ~0x00100000;
-	}
-
-	if (stat & 0x00200000) {
-		nve0_graph_trap_isr(priv, chid, inst, engctx);
-		nv_wr32(priv, 0x400100, 0x00200000);
-		stat &= ~0x00200000;
-	}
-
-	if (stat & 0x00080000) {
-		nve0_graph_ctxctl_isr(priv);
-		nv_wr32(priv, 0x400100, 0x00080000);
-		stat &= ~0x00080000;
-	}
-
-	if (stat) {
-		nv_error(priv, "unknown stat 0x%08x\n", stat);
-		nv_wr32(priv, 0x400100, stat);
-	}
-
-	nv_wr32(priv, 0x400500, 0x00010001);
-	nouveau_engctx_put(engctx);
-}
-
-static int
-nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-	       struct nouveau_oclass *oclass, void *data, u32 size,
-	       struct nouveau_object **pobject)
-{
-	struct nouveau_device *device = nv_device(parent);
-	struct nvc0_graph_priv *priv;
-	int ret, i;
-
-	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
-
-	nv_subdev(priv)->unit = 0x18001000;
-	nv_subdev(priv)->intr = nve0_graph_intr;
-	nv_engine(priv)->cclass = &nve0_graph_cclass;
-	nv_engine(priv)->sclass = nve0_graph_sclass;
-
-	priv->base.units = nvc0_graph_units;
-
-	if (nouveau_boolopt(device->cfgopt, "NvGrUseFW", false)) {
-		nv_info(priv, "using external firmware\n");
-		if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
-		    nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
-		    nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
-		    nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
-			return -EINVAL;
-		priv->firmware = true;
-	}
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
-				&priv->unk4188b4);
-	if (ret)
-		return ret;
-
-	ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
-				&priv->unk4188b8);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < 0x1000; i += 4) {
-		nv_wo32(priv->unk4188b4, i, 0x00000010);
-		nv_wo32(priv->unk4188b8, i, 0x00000010);
-	}
-
-	priv->gpc_nr =  nv_rd32(priv, 0x409604) & 0x0000001f;
-	priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
-	for (i = 0; i < priv->gpc_nr; i++) {
-		priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
-		priv->tpc_total += priv->tpc_nr[i];
-	}
-
-	switch (nv_device(priv)->chipset) {
-	case 0xe4:
-		if (priv->tpc_total == 8)
-			priv->magic_not_rop_nr = 3;
-		else
-		if (priv->tpc_total == 7)
-			priv->magic_not_rop_nr = 1;
-		break;
-	case 0xe7:
-	case 0xe6:
-		priv->magic_not_rop_nr = 1;
-		break;
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static void
-nve0_graph_init_obj418880(struct nvc0_graph_priv *priv)
-{
-	int i;
-
-	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
-	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-}
-
-static void
-nve0_graph_init_regs(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x400080, 0x003083c2);
-	nv_wr32(priv, 0x400088, 0x0001ffe7);
-	nv_wr32(priv, 0x40008c, 0x00000000);
-	nv_wr32(priv, 0x400090, 0x00000030);
-	nv_wr32(priv, 0x40013c, 0x003901f7);
-	nv_wr32(priv, 0x400140, 0x00000100);
-	nv_wr32(priv, 0x400144, 0x00000000);
-	nv_wr32(priv, 0x400148, 0x00000110);
-	nv_wr32(priv, 0x400138, 0x00000000);
-	nv_wr32(priv, 0x400130, 0x00000000);
-	nv_wr32(priv, 0x400134, 0x00000000);
-	nv_wr32(priv, 0x400124, 0x00000002);
-}
-
-static void
-nve0_graph_init_units(struct nvc0_graph_priv *priv)
-{
-	nv_wr32(priv, 0x409ffc, 0x00000000);
-	nv_wr32(priv, 0x409c14, 0x00003e3e);
-	nv_wr32(priv, 0x409c24, 0x000f0000);
-
-	nv_wr32(priv, 0x404000, 0xc0000000);
-	nv_wr32(priv, 0x404600, 0xc0000000);
-	nv_wr32(priv, 0x408030, 0xc0000000);
-	nv_wr32(priv, 0x404490, 0xc0000000);
-	nv_wr32(priv, 0x406018, 0xc0000000);
-	nv_wr32(priv, 0x407020, 0xc0000000);
-	nv_wr32(priv, 0x405840, 0xc0000000);
-	nv_wr32(priv, 0x405844, 0x00ffffff);
-
-	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
-	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
-
-}
-
-static void
-nve0_graph_init_gpc_0(struct nvc0_graph_priv *priv)
-{
-	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
-	u32 data[TPC_MAX / 8];
-	u8  tpcnr[GPC_MAX];
-	int i, gpc, tpc;
-
-	nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
-
-	memset(data, 0x00, sizeof(data));
-	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
-		do {
-			gpc = (gpc + 1) % priv->gpc_nr;
-		} while (!tpcnr[gpc]);
-		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
-		data[i / 8] |= tpc << ((i % 8) * 4);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
-						  priv->tpc_nr[gpc]);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
-	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-}
-
-static void
-nve0_graph_init_gpc_1(struct nvc0_graph_priv *priv)
-{
-	int gpc, tpc;
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
-			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
-		}
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-}
-
-static void
-nve0_graph_init_rop(struct nvc0_graph_priv *priv)
-{
-	int rop;
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
-		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-}
-
-static int
-nve0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
-{
-	u32 r000260;
-	int i;
-
-	if (priv->firmware) {
-		/* load fuc microcode */
-		r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
-		nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, &priv->fuc409d);
-		nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
-		nv_wr32(priv, 0x000260, r000260);
-
-		/* start both of them running */
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x41a10c, 0x00000000);
-		nv_wr32(priv, 0x40910c, 0x00000000);
-		nv_wr32(priv, 0x41a100, 0x00000002);
-		nv_wr32(priv, 0x409100, 0x00000002);
-		if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
-			nv_error(priv, "0x409800 wait failed\n");
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x7fffffff);
-		nv_wr32(priv, 0x409504, 0x00000021);
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000010);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x10 timeout\n");
-			return -EBUSY;
-		}
-		priv->size = nv_rd32(priv, 0x409800);
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000016);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x16 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(priv, 0x409840, 0xffffffff);
-		nv_wr32(priv, 0x409500, 0x00000000);
-		nv_wr32(priv, 0x409504, 0x00000025);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x25 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(priv, 0x409800, 0x00000000);
-		nv_wr32(priv, 0x409500, 0x00000001);
-		nv_wr32(priv, 0x409504, 0x00000030);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x30 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(priv, 0x409810, 0xb00095c8);
-		nv_wr32(priv, 0x409800, 0x00000000);
-		nv_wr32(priv, 0x409500, 0x00000001);
-		nv_wr32(priv, 0x409504, 0x00000031);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x31 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(priv, 0x409810, 0x00080420);
-		nv_wr32(priv, 0x409800, 0x00000000);
-		nv_wr32(priv, 0x409500, 0x00000001);
-		nv_wr32(priv, 0x409504, 0x00000032);
-		if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
-			nv_error(priv, "fuc09 req 0x32 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(priv, 0x409614, 0x00000070);
-		nv_wr32(priv, 0x409614, 0x00000770);
-		nv_wr32(priv, 0x40802c, 0x00000001);
-
-		if (priv->data == NULL) {
-			int ret = nve0_grctx_generate(priv);
-			if (ret) {
-				nv_error(priv, "failed to construct context\n");
-				return ret;
-			}
-		}
-
-		return 0;
-	}
-
-	/* load HUB microcode */
-	r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
-	nv_wr32(priv, 0x4091c0, 0x01000000);
-	for (i = 0; i < sizeof(nve0_grhub_data) / 4; i++)
-		nv_wr32(priv, 0x4091c4, nve0_grhub_data[i]);
-
-	nv_wr32(priv, 0x409180, 0x01000000);
-	for (i = 0; i < sizeof(nve0_grhub_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(priv, 0x409188, i >> 6);
-		nv_wr32(priv, 0x409184, nve0_grhub_code[i]);
-	}
-
-	/* load GPC microcode */
-	nv_wr32(priv, 0x41a1c0, 0x01000000);
-	for (i = 0; i < sizeof(nve0_grgpc_data) / 4; i++)
-		nv_wr32(priv, 0x41a1c4, nve0_grgpc_data[i]);
-
-	nv_wr32(priv, 0x41a180, 0x01000000);
-	for (i = 0; i < sizeof(nve0_grgpc_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(priv, 0x41a188, i >> 6);
-		nv_wr32(priv, 0x41a184, nve0_grgpc_code[i]);
-	}
-	nv_wr32(priv, 0x000260, r000260);
-
-	/* start HUB ucode running, it'll init the GPCs */
-	nv_wr32(priv, 0x409800, nv_device(priv)->chipset);
-	nv_wr32(priv, 0x40910c, 0x00000000);
-	nv_wr32(priv, 0x409100, 0x00000002);
-	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
-		nv_error(priv, "HUB_INIT timed out\n");
-		nvc0_graph_ctxctl_debug(priv);
-		return -EBUSY;
-	}
-
-	priv->size = nv_rd32(priv, 0x409804);
-	if (priv->data == NULL) {
-		int ret = nve0_grctx_generate(priv);
-		if (ret) {
-			nv_error(priv, "failed to construct context\n");
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static int
-nve0_graph_init(struct nouveau_object *object)
-{
-	struct nvc0_graph_priv *priv = (void *)object;
-	int ret;
-
-	ret = nouveau_graph_init(&priv->base);
-	if (ret)
-		return ret;
-
-	nve0_graph_init_obj418880(priv);
-	nve0_graph_init_regs(priv);
-	nve0_graph_init_gpc_0(priv);
-
-	nv_wr32(priv, 0x400500, 0x00010001);
-	nv_wr32(priv, 0x400100, 0xffffffff);
-	nv_wr32(priv, 0x40013c, 0xffffffff);
-
-	nve0_graph_init_units(priv);
-	nve0_graph_init_gpc_1(priv);
-	nve0_graph_init_rop(priv);
-
-	nv_wr32(priv, 0x400108, 0xffffffff);
-	nv_wr32(priv, 0x400138, 0xffffffff);
-	nv_wr32(priv, 0x400118, 0xffffffff);
-	nv_wr32(priv, 0x400130, 0xffffffff);
-	nv_wr32(priv, 0x40011c, 0xffffffff);
-	nv_wr32(priv, 0x400134, 0xffffffff);
-	nv_wr32(priv, 0x400054, 0x34ce3464);
-
-	ret = nve0_graph_init_ctxctl(priv);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-struct nouveau_oclass
-nve0_graph_oclass = {
-	.handle = NV_ENGINE(GR, 0xe0),
-	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = nve0_graph_ctor,
-		.dtor = nvc0_graph_dtor,
-		.init = nve0_graph_init,
-		.fini = _nouveau_graph_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
new file mode 100644
index 0000000..05ec09c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nve4_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0xa040, &nouveau_object_ofuncs },
+	{ 0xa097, &nouveau_object_ofuncs },
+	{ 0xa0c0, &nouveau_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvc0_graph_init
+nve4_graph_init_regs[] = {
+	{ 0x400080,   1, 0x04, 0x003083c2 },
+	{ 0x400088,   1, 0x04, 0x0001ffe7 },
+	{ 0x40008c,   1, 0x04, 0x00000000 },
+	{ 0x400090,   1, 0x04, 0x00000030 },
+	{ 0x40013c,   1, 0x04, 0x003901f7 },
+	{ 0x400140,   1, 0x04, 0x00000100 },
+	{ 0x400144,   1, 0x04, 0x00000000 },
+	{ 0x400148,   1, 0x04, 0x00000110 },
+	{ 0x400138,   1, 0x04, 0x00000000 },
+	{ 0x400130,   2, 0x04, 0x00000000 },
+	{ 0x400124,   1, 0x04, 0x00000002 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_graph_init_unk58xx[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x0000ff34 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{ 0x405928,   1, 0x04, 0x00000000 },
+	{ 0x40592c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_graph_init_unk70xx[] = {
+	{ 0x407010,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nve4_graph_init_unk5bxx[] = {
+	{ 0x405b50,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_graph_init_gpc[] = {
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{ 0x4184a4,   2, 0x04, 0x00000000 },
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x00000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{ 0x418814,   3, 0x04, 0x00000000 },
+	{ 0x418b04,   1, 0x04, 0x00000000 },
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c64,   1, 0x04, 0x00000000 },
+	{ 0x418c68,   1, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{ 0x418cb4,   2, 0x04, 0x00000000 },
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418d28,   1, 0x04, 0x00000000 },
+	{ 0x418d2c,   1, 0x04, 0x00000000 },
+	{ 0x418f00,   1, 0x04, 0x00000000 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418f20,   2, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000060 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x418e1c,   1, 0x04, 0x00000000 },
+	{ 0x418e20,   1, 0x04, 0x00000000 },
+	{ 0x41900c,   1, 0x04, 0x00000000 },
+	{ 0x419018,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nve4_graph_init_tpc[] = {
+	{ 0x419d0c,   1, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x419ab4,   1, 0x04, 0x00000000 },
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x419850,   1, 0x04, 0x00000004 },
+	{ 0x419854,   2, 0x04, 0x00000000 },
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x01000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00b08bea },
+	{ 0x419c84,   1, 0x04, 0x00010384 },
+	{ 0x419cbc,   1, 0x04, 0x28137646 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419c80,   1, 0x04, 0x00020232 },
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{ 0x419e00,   1, 0x04, 0x00000000 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ee4,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00000000 },
+	{ 0x419eb4,   1, 0x04, 0x00000000 },
+	{ 0x419eb8,   3, 0x04, 0x00000000 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419f74,   1, 0x04, 0x00000555 },
+	{}
+};
+
+struct nvc0_graph_init
+nve4_graph_init_unk[] = {
+	{ 0x41be04,   1, 0x04, 0x00000000 },
+	{ 0x41be08,   1, 0x04, 0x00000004 },
+	{ 0x41be0c,   1, 0x04, 0x00000000 },
+	{ 0x41be10,   1, 0x04, 0x003b8bc7 },
+	{ 0x41be14,   2, 0x04, 0x00000000 },
+	{ 0x41bfd4,   1, 0x04, 0x00800000 },
+	{ 0x41bfdc,   1, 0x04, 0x00000000 },
+	{ 0x41bff8,   1, 0x04, 0x00000000 },
+	{ 0x41bffc,   1, 0x04, 0x00000000 },
+	{ 0x41becc,   1, 0x04, 0x00000000 },
+	{ 0x41bee8,   1, 0x04, 0x00000000 },
+	{ 0x41beec,   1, 0x04, 0x00000000 },
+	{}
+};
+
+struct nvc0_graph_init
+nve4_graph_init_unk88xx[] = {
+	{ 0x40880c,   1, 0x04, 0x00000000 },
+	{ 0x408850,   1, 0x04, 0x00000004 },
+	{ 0x408910,   9, 0x04, 0x00000000 },
+	{ 0x408950,   1, 0x04, 0x00000000 },
+	{ 0x408954,   1, 0x04, 0x0000ffff },
+	{ 0x408958,   1, 0x04, 0x00000034 },
+	{ 0x408984,   1, 0x04, 0x00000000 },
+	{ 0x408988,   1, 0x04, 0x08040201 },
+	{ 0x40898c,   1, 0x04, 0x80402010 },
+	{}
+};
+
+int
+nve4_graph_init(struct nouveau_object *object)
+{
+	struct nvc0_graph_oclass *oclass = (void *)object->oclass;
+	struct nvc0_graph_priv *priv = (void *)object;
+	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+	u32 data[TPC_MAX / 8] = {};
+	u8  tpcnr[GPC_MAX];
+	int gpc, tpc, rop;
+	int ret, i;
+
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+	nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+	nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+	for (i = 0; oclass->mmio[i]; i++)
+		nvc0_graph_mmio(priv, oclass->mmio[i]);
+
+	nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+	memset(data, 0x00, sizeof(data));
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+	for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+		do {
+			gpc = (gpc + 1) % priv->gpc_nr;
+		} while (!tpcnr[gpc]);
+		tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+		data[i / 8] |= tpc << ((i % 8) * 4);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+	nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+	nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+	nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+			priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+			priv->tpc_total);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+	}
+
+	nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+	nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+
+	nv_wr32(priv, 0x409ffc, 0x00000000);
+	nv_wr32(priv, 0x409c14, 0x00003e3e);
+	nv_wr32(priv, 0x409c24, 0x000f0001);
+	nv_wr32(priv, 0x404000, 0xc0000000);
+	nv_wr32(priv, 0x404600, 0xc0000000);
+	nv_wr32(priv, 0x408030, 0xc0000000);
+	nv_wr32(priv, 0x404490, 0xc0000000);
+	nv_wr32(priv, 0x406018, 0xc0000000);
+	nv_wr32(priv, 0x407020, 0x40000000);
+	nv_wr32(priv, 0x405840, 0xc0000000);
+	nv_wr32(priv, 0x405844, 0x00ffffff);
+	nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+	nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+		nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+			nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+		}
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+		nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+	}
+
+	for (rop = 0; rop < priv->rop_nr; rop++) {
+		nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+		nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+		nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+	}
+
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400118, 0xffffffff);
+	nv_wr32(priv, 0x400130, 0xffffffff);
+	nv_wr32(priv, 0x40011c, 0xffffffff);
+	nv_wr32(priv, 0x400134, 0xffffffff);
+
+	nv_wr32(priv, 0x400054, 0x34ce3464);
+	return nvc0_graph_init_ctxctl(priv);
+}
+
+static struct nvc0_graph_init *
+nve4_graph_init_mmio[] = {
+	nve4_graph_init_regs,
+	nvc0_graph_init_unk40xx,
+	nvc0_graph_init_unk44xx,
+	nvc0_graph_init_unk78xx,
+	nvc0_graph_init_unk60xx,
+	nvd9_graph_init_unk64xx,
+	nve4_graph_init_unk58xx,
+	nvc0_graph_init_unk80xx,
+	nve4_graph_init_unk70xx,
+	nve4_graph_init_unk5bxx,
+	nve4_graph_init_gpc,
+	nve4_graph_init_tpc,
+	nve4_graph_init_unk,
+	nve4_graph_init_unk88xx,
+	NULL
+};
+
+#include "fuc/hubnve0.fuc.h"
+
+static struct nvc0_graph_ucode
+nve4_graph_fecs_ucode = {
+	.code.data = nve0_grhub_code,
+	.code.size = sizeof(nve0_grhub_code),
+	.data.data = nve0_grhub_data,
+	.data.size = sizeof(nve0_grhub_data),
+};
+
+#include "fuc/gpcnve0.fuc.h"
+
+static struct nvc0_graph_ucode
+nve4_graph_gpccs_ucode = {
+	.code.data = nve0_grgpc_code,
+	.code.size = sizeof(nve0_grgpc_code),
+	.data.data = nve0_grgpc_data,
+	.data.size = sizeof(nve0_grgpc_data),
+};
+
+struct nouveau_oclass *
+nve4_graph_oclass = &(struct nvc0_graph_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xe4),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nve4_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+	.cclass = &nve4_grctx_oclass,
+	.sclass = nve4_graph_sclass,
+	.mmio = nve4_graph_init_mmio,
+	.fecs.ucode = &nve4_graph_fecs_ucode,
+	.gpccs.ucode = &nve4_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
new file mode 100644
index 0000000..2f0ac78
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nvf0_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0xa140, &nouveau_object_ofuncs },
+	{ 0xa197, &nouveau_object_ofuncs },
+	{ 0xa1c0, &nouveau_object_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static struct nvc0_graph_init
+nvf0_graph_init_unk40xx[] = {
+	{ 0x40415c,   1, 0x04, 0x00000000 },
+	{ 0x404170,   1, 0x04, 0x00000000 },
+	{ 0x4041b4,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_unk58xx[] = {
+	{ 0x405844,   1, 0x04, 0x00ffffff },
+	{ 0x405850,   1, 0x04, 0x00000000 },
+	{ 0x405900,   1, 0x04, 0x0000ff00 },
+	{ 0x405908,   1, 0x04, 0x00000000 },
+	{ 0x405928,   1, 0x04, 0x00000000 },
+	{ 0x40592c,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_unk70xx[] = {
+	{ 0x407010,   1, 0x04, 0x00000000 },
+	{ 0x407040,   1, 0x04, 0x80440424 },
+	{ 0x407048,   1, 0x04, 0x0000000a },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_unk5bxx[] = {
+	{ 0x405b44,   1, 0x04, 0x00000000 },
+	{ 0x405b50,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_gpc[] = {
+	{ 0x418408,   1, 0x04, 0x00000000 },
+	{ 0x4184a0,   1, 0x04, 0x00000000 },
+	{ 0x4184a4,   2, 0x04, 0x00000000 },
+	{ 0x418604,   1, 0x04, 0x00000000 },
+	{ 0x418680,   1, 0x04, 0x00000000 },
+	{ 0x418714,   1, 0x04, 0x00000000 },
+	{ 0x418384,   1, 0x04, 0x00000000 },
+	{ 0x418814,   3, 0x04, 0x00000000 },
+	{ 0x418b04,   1, 0x04, 0x00000000 },
+	{ 0x4188c8,   2, 0x04, 0x00000000 },
+	{ 0x4188d0,   1, 0x04, 0x00010000 },
+	{ 0x4188d4,   1, 0x04, 0x00000001 },
+	{ 0x418910,   1, 0x04, 0x00010001 },
+	{ 0x418914,   1, 0x04, 0x00000301 },
+	{ 0x418918,   1, 0x04, 0x00800000 },
+	{ 0x418980,   1, 0x04, 0x77777770 },
+	{ 0x418984,   3, 0x04, 0x77777777 },
+	{ 0x418c04,   1, 0x04, 0x00000000 },
+	{ 0x418c64,   1, 0x04, 0x00000000 },
+	{ 0x418c68,   1, 0x04, 0x00000000 },
+	{ 0x418c88,   1, 0x04, 0x00000000 },
+	{ 0x418cb4,   2, 0x04, 0x00000000 },
+	{ 0x418d00,   1, 0x04, 0x00000000 },
+	{ 0x418d28,   1, 0x04, 0x00000000 },
+	{ 0x418d2c,   1, 0x04, 0x00000000 },
+	{ 0x418f00,   1, 0x04, 0x00000400 },
+	{ 0x418f08,   1, 0x04, 0x00000000 },
+	{ 0x418f20,   1, 0x04, 0x00000000 },
+	{ 0x418f24,   1, 0x04, 0x00000000 },
+	{ 0x418e00,   1, 0x04, 0x00000000 },
+	{ 0x418e08,   1, 0x04, 0x00000000 },
+	{ 0x418e1c,   2, 0x04, 0x00000000 },
+	{ 0x41900c,   1, 0x04, 0x00000000 },
+	{ 0x419018,   1, 0x04, 0x00000000 },
+	{}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_tpc[] = {
+	{ 0x419d0c,   1, 0x04, 0x00000000 },
+	{ 0x419d10,   1, 0x04, 0x00000014 },
+	{ 0x419ab0,   1, 0x04, 0x00000000 },
+	{ 0x419ac8,   1, 0x04, 0x00000000 },
+	{ 0x419ab8,   1, 0x04, 0x000000e7 },
+	{ 0x419aec,   1, 0x04, 0x00000000 },
+	{ 0x419abc,   2, 0x04, 0x00000000 },
+	{ 0x419ab4,   1, 0x04, 0x00000000 },
+	{ 0x419aa8,   2, 0x04, 0x00000000 },
+	{ 0x41980c,   1, 0x04, 0x00000010 },
+	{ 0x419844,   1, 0x04, 0x00000000 },
+	{ 0x419850,   1, 0x04, 0x00000004 },
+	{ 0x419854,   2, 0x04, 0x00000000 },
+	{ 0x419c98,   1, 0x04, 0x00000000 },
+	{ 0x419ca8,   1, 0x04, 0x00000000 },
+	{ 0x419cb0,   1, 0x04, 0x01000000 },
+	{ 0x419cb4,   1, 0x04, 0x00000000 },
+	{ 0x419cb8,   1, 0x04, 0x00b08bea },
+	{ 0x419c84,   1, 0x04, 0x00010384 },
+	{ 0x419cbc,   1, 0x04, 0x281b3646 },
+	{ 0x419cc0,   2, 0x04, 0x00000000 },
+	{ 0x419c80,   1, 0x04, 0x00020230 },
+	{ 0x419ccc,   2, 0x04, 0x00000000 },
+	{ 0x419c0c,   1, 0x04, 0x00000000 },
+	{ 0x419e00,   1, 0x04, 0x00000080 },
+	{ 0x419ea0,   1, 0x04, 0x00000000 },
+	{ 0x419ee4,   1, 0x04, 0x00000000 },
+	{ 0x419ea4,   1, 0x04, 0x00000100 },
+	{ 0x419ea8,   1, 0x04, 0x00000000 },
+	{ 0x419eb4,   1, 0x04, 0x00000000 },
+	{ 0x419ebc,   2, 0x04, 0x00000000 },
+	{ 0x419edc,   1, 0x04, 0x00000000 },
+	{ 0x419f00,   1, 0x04, 0x00000000 },
+	{ 0x419ed0,   1, 0x04, 0x00003234 },
+	{ 0x419f74,   1, 0x04, 0x00015555 },
+	{ 0x419f80,   4, 0x04, 0x00000000 },
+	{}
+};
+
+static int
+nvf0_graph_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nvc0_graph_priv *priv = (void *)object;
+	static const struct {
+		u32 addr;
+		u32 data;
+	} magic[] = {
+		{ 0x020520, 0xfffffffc },
+		{ 0x020524, 0xfffffffe },
+		{ 0x020524, 0xfffffffc },
+		{ 0x020524, 0xfffffff8 },
+		{ 0x020524, 0xffffffe0 },
+		{ 0x020530, 0xfffffffe },
+		{ 0x02052c, 0xfffffffa },
+		{ 0x02052c, 0xfffffff0 },
+		{ 0x02052c, 0xffffffc0 },
+		{ 0x02052c, 0xffffff00 },
+		{ 0x02052c, 0xfffffc00 },
+		{ 0x02052c, 0xfffcfc00 },
+		{ 0x02052c, 0xfff0fc00 },
+		{ 0x02052c, 0xff80fc00 },
+		{ 0x020528, 0xfffffffe },
+		{ 0x020528, 0xfffffffc },
+	};
+	int i;
+
+	nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
+	nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
+	for (i = 0; i < ARRAY_SIZE(magic); i++) {
+		nv_wr32(priv, magic[i].addr, magic[i].data);
+		nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
+	}
+
+	return nouveau_graph_fini(&priv->base, suspend);
+}
+
+static struct nvc0_graph_init *
+nvf0_graph_init_mmio[] = {
+	nve4_graph_init_regs,
+	nvf0_graph_init_unk40xx,
+	nvc0_graph_init_unk44xx,
+	nvc0_graph_init_unk78xx,
+	nvc0_graph_init_unk60xx,
+	nvd9_graph_init_unk64xx,
+	nvf0_graph_init_unk58xx,
+	nvc0_graph_init_unk80xx,
+	nvf0_graph_init_unk70xx,
+	nvf0_graph_init_unk5bxx,
+	nvf0_graph_init_gpc,
+	nvf0_graph_init_tpc,
+	nve4_graph_init_unk,
+	nve4_graph_init_unk88xx,
+	NULL
+};
+
+#include "fuc/hubnvf0.fuc.h"
+
+static struct nvc0_graph_ucode
+nvf0_graph_fecs_ucode = {
+	.code.data = nvf0_grhub_code,
+	.code.size = sizeof(nvf0_grhub_code),
+	.data.data = nvf0_grhub_data,
+	.data.size = sizeof(nvf0_grhub_data),
+};
+
+#include "fuc/gpcnvf0.fuc.h"
+
+static struct nvc0_graph_ucode
+nvf0_graph_gpccs_ucode = {
+	.code.data = nvf0_grgpc_code,
+	.code.size = sizeof(nvf0_grgpc_code),
+	.data.data = nvf0_grgpc_data,
+	.data.size = sizeof(nvf0_grgpc_data),
+};
+
+struct nouveau_oclass *
+nvf0_graph_oclass = &(struct nvc0_graph_oclass) {
+	.base.handle = NV_ENGINE(GR, 0xf0),
+	.base.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nve4_graph_init,
+		.fini = nvf0_graph_fini,
+	},
+	.cclass = &nvf0_grctx_oclass,
+	.sclass =  nvf0_graph_sclass,
+	.mmio = nvf0_graph_init_mmio,
+	.fecs.ucode = 0 ? &nvf0_graph_fecs_ucode : NULL,
+	.gpccs.ucode = &nvf0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
index bc7d12b3..37a2bd9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
@@ -125,13 +125,6 @@
  * PMPEG engine/subdev functions
  ******************************************************************************/
 
-int
-nv50_mpeg_tlb_flush(struct nouveau_engine *engine)
-{
-	nv50_vm_flush_engine(&engine->base, 0x08);
-	return 0;
-}
-
 void
 nv50_mpeg_intr(struct nouveau_subdev *subdev)
 {
@@ -191,7 +184,6 @@
 	nv_subdev(priv)->intr = nv50_vpe_intr;
 	nv_engine(priv)->cclass = &nv50_mpeg_cclass;
 	nv_engine(priv)->sclass = nv50_mpeg_sclass;
-	nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
index 8f805b4..96f5aa9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
@@ -88,7 +88,6 @@
 	nv_subdev(priv)->intr = nv50_mpeg_intr;
 	nv_engine(priv)->cclass = &nv84_mpeg_cclass;
 	nv_engine(priv)->sclass = nv84_mpeg_sclass;
-	nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
index ebf0d86..73719aa 100644
--- a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
@@ -22,8 +22,7 @@
  * Authors: Maarten Lankhorst
  */
 
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
 #include <engine/ppp.h>
 
 struct nvc0_ppp_priv {
@@ -91,6 +90,7 @@
 		return ret;
 
 	nv_subdev(priv)->unit = 0x00000002;
+	nv_subdev(priv)->intr = nouveau_falcon_intr;
 	nv_engine(priv)->cclass = &nvc0_ppp_cclass;
 	nv_engine(priv)->sclass = nvc0_ppp_sclass;
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
index 261cd96..fd6272b 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
@@ -19,24 +19,19 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  *
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs, Ilia Mirkin
  */
 
-#include <core/engctx.h>
-#include <core/class.h>
-
+#include <engine/xtensa.h>
 #include <engine/vp.h>
 
-struct nv84_vp_priv {
-	struct nouveau_engine base;
-};
-
 /*******************************************************************************
  * VP object classes
  ******************************************************************************/
 
 static struct nouveau_oclass
 nv84_vp_sclass[] = {
+	{ 0x7476, &nouveau_object_ofuncs },
 	{},
 };
 
@@ -48,7 +43,7 @@
 nv84_vp_cclass = {
 	.handle = NV_ENGCTX(VP, 0x84),
 	.ofuncs = &(struct nouveau_ofuncs) {
-		.ctor = _nouveau_engctx_ctor,
+		.ctor = _nouveau_xtensa_engctx_ctor,
 		.dtor = _nouveau_engctx_dtor,
 		.init = _nouveau_engctx_init,
 		.fini = _nouveau_engctx_fini,
@@ -66,10 +61,10 @@
 	     struct nouveau_oclass *oclass, void *data, u32 size,
 	     struct nouveau_object **pobject)
 {
-	struct nv84_vp_priv *priv;
+	struct nouveau_xtensa *priv;
 	int ret;
 
-	ret = nouveau_engine_create(parent, engine, oclass, true,
+	ret = nouveau_xtensa_create(parent, engine, oclass, 0xf000, true,
 				    "PVP", "vp", &priv);
 	*pobject = nv_object(priv);
 	if (ret)
@@ -78,6 +73,8 @@
 	nv_subdev(priv)->unit = 0x01020000;
 	nv_engine(priv)->cclass = &nv84_vp_cclass;
 	nv_engine(priv)->sclass = nv84_vp_sclass;
+	priv->fifo_val = 0x111;
+	priv->unkd28 = 0x9c544;
 	return 0;
 }
 
@@ -86,8 +83,10 @@
 	.handle = NV_ENGINE(VP, 0x84),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nv84_vp_ctor,
-		.dtor = _nouveau_engine_dtor,
-		.init = _nouveau_engine_init,
-		.fini = _nouveau_engine_fini,
+		.dtor = _nouveau_xtensa_dtor,
+		.init = _nouveau_xtensa_init,
+		.fini = _nouveau_xtensa_fini,
+		.rd32 = _nouveau_xtensa_rd32,
+		.wr32 = _nouveau_xtensa_wr32,
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
new file mode 100644
index 0000000..8a8236b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/engctx.h>
+#include <core/class.h>
+
+#include <engine/vp.h>
+
+struct nv98_vp_priv {
+	struct nouveau_engine base;
+};
+
+/*******************************************************************************
+ * VP object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_vp_sclass[] = {
+	{},
+};
+
+/*******************************************************************************
+ * PVP context
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_vp_cclass = {
+	.handle = NV_ENGCTX(VP, 0x98),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = _nouveau_engctx_ctor,
+		.dtor = _nouveau_engctx_dtor,
+		.init = _nouveau_engctx_init,
+		.fini = _nouveau_engctx_fini,
+		.rd32 = _nouveau_engctx_rd32,
+		.wr32 = _nouveau_engctx_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PVP engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	     struct nouveau_oclass *oclass, void *data, u32 size,
+	     struct nouveau_object **pobject)
+{
+	struct nv98_vp_priv *priv;
+	int ret;
+
+	ret = nouveau_engine_create(parent, engine, oclass, true,
+				    "PVP", "vp", &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x01020000;
+	nv_engine(priv)->cclass = &nv98_vp_cclass;
+	nv_engine(priv)->sclass = nv98_vp_sclass;
+	return 0;
+}
+
+struct nouveau_oclass
+nv98_vp_oclass = {
+	.handle = NV_ENGINE(VP, 0x98),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv98_vp_ctor,
+		.dtor = _nouveau_engine_dtor,
+		.init = _nouveau_engine_init,
+		.fini = _nouveau_engine_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
index f761949..ac1f62a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
@@ -22,8 +22,7 @@
  * Authors: Maarten Lankhorst
  */
 
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
 #include <engine/vp.h>
 
 struct nvc0_vp_priv {
@@ -91,6 +90,7 @@
 		return ret;
 
 	nv_subdev(priv)->unit = 0x00020000;
+	nv_subdev(priv)->intr = nouveau_falcon_intr;
 	nv_engine(priv)->cclass = &nvc0_vp_cclass;
 	nv_engine(priv)->sclass = nvc0_vp_sclass;
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
index 2384ce5..d4c3108 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
@@ -22,8 +22,7 @@
  * Authors: Ben Skeggs
  */
 
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
 #include <engine/vp.h>
 
 struct nve0_vp_priv {
@@ -91,6 +90,7 @@
 		return ret;
 
 	nv_subdev(priv)->unit = 0x00020000;
+	nv_subdev(priv)->intr = nouveau_falcon_intr;
 	nv_engine(priv)->cclass = &nve0_vp_cclass;
 	nv_engine(priv)->sclass = nve0_vp_sclass;
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
new file mode 100644
index 0000000..0639bc5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2013 Ilia Mirkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <engine/xtensa.h>
+
+u32
+_nouveau_xtensa_rd32(struct nouveau_object *object, u64 addr)
+{
+	struct nouveau_xtensa *xtensa = (void *)object;
+	return nv_rd32(xtensa, xtensa->addr + addr);
+}
+
+void
+_nouveau_xtensa_wr32(struct nouveau_object *object, u64 addr, u32 data)
+{
+	struct nouveau_xtensa *xtensa = (void *)object;
+	nv_wr32(xtensa, xtensa->addr + addr, data);
+}
+
+int
+_nouveau_xtensa_engctx_ctor(struct nouveau_object *parent,
+			    struct nouveau_object *engine,
+			    struct nouveau_oclass *oclass, void *data, u32 size,
+			    struct nouveau_object **pobject)
+{
+	struct nouveau_engctx *engctx;
+	int ret;
+
+	ret = nouveau_engctx_create(parent, engine, oclass, NULL,
+				    0x10000, 0x1000,
+				    NVOBJ_FLAG_ZERO_ALLOC, &engctx);
+	*pobject = nv_object(engctx);
+	return ret;
+}
+
+void
+_nouveau_xtensa_intr(struct nouveau_subdev *subdev)
+{
+	struct nouveau_xtensa *xtensa = (void *)subdev;
+	u32 unk104 = nv_ro32(xtensa, 0xd04);
+	u32 intr = nv_ro32(xtensa, 0xc20);
+	u32 chan = nv_ro32(xtensa, 0xc28);
+	u32 unk10c = nv_ro32(xtensa, 0xd0c);
+
+	if (intr & 0x10)
+		nv_warn(xtensa, "Watchdog interrupt, engine hung.\n");
+	nv_wo32(xtensa, 0xc20, intr);
+	intr = nv_ro32(xtensa, 0xc20);
+	if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) {
+		nv_debug(xtensa, "Enabling FIFO_CTRL\n");
+		nv_mask(xtensa, xtensa->addr + 0xd94, 0, xtensa->fifo_val);
+	}
+}
+
+int
+nouveau_xtensa_create_(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, u32 addr, bool enable,
+		       const char *iname, const char *fname,
+		       int length, void **pobject)
+{
+	struct nouveau_xtensa *xtensa;
+	int ret;
+
+	ret = nouveau_engine_create_(parent, engine, oclass, enable, iname,
+				     fname, length, pobject);
+	xtensa = *pobject;
+	if (ret)
+		return ret;
+
+	nv_subdev(xtensa)->intr = _nouveau_xtensa_intr;
+
+	xtensa->addr = addr;
+
+	return 0;
+}
+
+int
+_nouveau_xtensa_init(struct nouveau_object *object)
+{
+	struct nouveau_device *device = nv_device(object);
+	struct nouveau_xtensa *xtensa = (void *)object;
+	const struct firmware *fw;
+	char name[32];
+	int i, ret;
+	u32 tmp;
+
+	ret = nouveau_engine_init(&xtensa->base);
+	if (ret)
+		return ret;
+
+	if (!xtensa->gpu_fw) {
+		snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
+			 xtensa->addr >> 12);
+
+		ret = request_firmware(&fw, name, &device->pdev->dev);
+		if (ret) {
+			nv_warn(xtensa, "unable to load firmware %s\n", name);
+			return ret;
+		}
+
+		ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0,
+					 &xtensa->gpu_fw);
+		if (ret) {
+			release_firmware(fw);
+			return ret;
+		}
+
+		nv_debug(xtensa, "Loading firmware to address: 0x%llx\n",
+			 xtensa->gpu_fw->addr);
+
+		for (i = 0; i < fw->size / 4; i++)
+			nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i));
+		release_firmware(fw);
+	}
+
+	nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */
+	nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */
+
+	nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */
+	nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
+	nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
+
+	nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */
+	nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */
+	nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */
+
+	tmp = nv_rd32(xtensa, 0x0);
+	nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */
+
+	nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */
+
+	nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
+	nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
+
+	return 0;
+}
+
+int
+_nouveau_xtensa_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nouveau_xtensa *xtensa = (void *)object;
+
+	nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */
+	nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */
+
+	if (!suspend)
+		nouveau_gpuobj_ref(NULL, &xtensa->gpu_fw);
+
+	return nouveau_engine_fini(&xtensa->base, suspend);
+}
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h
index 05840f3..99b6600 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/device.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/device.h
@@ -17,8 +17,7 @@
 	NVDEV_SUBDEV_DEVINIT,
 	NVDEV_SUBDEV_GPIO,
 	NVDEV_SUBDEV_I2C,
-	NVDEV_SUBDEV_CLOCK,
-	NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_CLOCK,
+	NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C,
 
 	/* This grouping of subdevs are initialised right after they've
 	 * been created, and are allowed to assume any subdevs in the
@@ -35,6 +34,7 @@
 	NVDEV_SUBDEV_VM,
 	NVDEV_SUBDEV_BAR,
 	NVDEV_SUBDEV_VOLT,
+	NVDEV_SUBDEV_CLOCK,
 	NVDEV_SUBDEV_THERM,
 
 	NVDEV_ENGINE_DMAOBJ,
@@ -49,6 +49,7 @@
 	NVDEV_ENGINE_PPP,
 	NVDEV_ENGINE_COPY0,
 	NVDEV_ENGINE_COPY1,
+	NVDEV_ENGINE_COPY2,
 	NVDEV_ENGINE_UNK1C1,
 	NVDEV_ENGINE_VENC,
 	NVDEV_ENGINE_DISP,
diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h
index 2514e81..2bf7d0e 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/mm.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/mm.h
@@ -15,8 +15,6 @@
 	struct list_head nodes;
 	struct list_head free;
 
-	struct mutex mutex;
-
 	u32 block_size;
 	int heap_nodes;
 };
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
index 13ccdf5..67662e2 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
@@ -2,6 +2,7 @@
 #define __NOUVEAU_BSP_H__
 
 extern struct nouveau_oclass nv84_bsp_oclass;
+extern struct nouveau_oclass nv98_bsp_oclass;
 extern struct nouveau_oclass nvc0_bsp_oclass;
 extern struct nouveau_oclass nve0_bsp_oclass;
 
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/copy.h b/drivers/gpu/drm/nouveau/core/include/engine/copy.h
index 8cad2cf..316a28a 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/copy.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/copy.h
@@ -8,5 +8,6 @@
 extern struct nouveau_oclass nvc0_copy1_oclass;
 extern struct nouveau_oclass nve0_copy0_oclass;
 extern struct nouveau_oclass nve0_copy1_oclass;
+extern struct nouveau_oclass nve0_copy2_oclass;
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/falcon.h b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
similarity index 97%
rename from drivers/gpu/drm/nouveau/core/include/core/falcon.h
rename to drivers/gpu/drm/nouveau/core/include/engine/falcon.h
index 1edec38..181aa7d 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/falcon.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
@@ -72,6 +72,8 @@
 			   struct nouveau_oclass *, u32, bool, const char *,
 			   const char *, int, void **);
 
+void nouveau_falcon_intr(struct nouveau_subdev *subdev);
+
 #define _nouveau_falcon_dtor _nouveau_engine_dtor
 int  _nouveau_falcon_init(struct nouveau_object *);
 int  _nouveau_falcon_fini(struct nouveau_object *, bool);
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/graph.h b/drivers/gpu/drm/nouveau/core/include/engine/graph.h
index 5d39243..8e1b523 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/graph.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/graph.h
@@ -61,8 +61,14 @@
 extern struct nouveau_oclass nv35_graph_oclass;
 extern struct nouveau_oclass nv40_graph_oclass;
 extern struct nouveau_oclass nv50_graph_oclass;
-extern struct nouveau_oclass nvc0_graph_oclass;
-extern struct nouveau_oclass nve0_graph_oclass;
+extern struct nouveau_oclass *nvc0_graph_oclass;
+extern struct nouveau_oclass *nvc1_graph_oclass;
+extern struct nouveau_oclass *nvc3_graph_oclass;
+extern struct nouveau_oclass *nvc8_graph_oclass;
+extern struct nouveau_oclass *nvd7_graph_oclass;
+extern struct nouveau_oclass *nvd9_graph_oclass;
+extern struct nouveau_oclass *nve4_graph_oclass;
+extern struct nouveau_oclass *nvf0_graph_oclass;
 
 extern const struct nouveau_bitfield nv04_graph_nsource[];
 extern struct nouveau_ofuncs nv04_graph_ofuncs;
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
index bbf0d4a..1d1a89a 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
@@ -54,7 +54,6 @@
 int  nv50_mpeg_context_ctor(struct nouveau_object *, struct nouveau_object *,
 			    struct nouveau_oclass *, void *, u32,
 			    struct nouveau_object **);
-int  nv50_mpeg_tlb_flush(struct nouveau_engine *);
 void nv50_mpeg_intr(struct nouveau_subdev *);
 int  nv50_mpeg_init(struct nouveau_object *);
 
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/vp.h b/drivers/gpu/drm/nouveau/core/include/engine/vp.h
index d7b287b..39baebe 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/vp.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/vp.h
@@ -2,6 +2,7 @@
 #define __NOUVEAU_VP_H__
 
 extern struct nouveau_oclass nv84_vp_oclass;
+extern struct nouveau_oclass nv98_vp_oclass;
 extern struct nouveau_oclass nvc0_vp_oclass;
 extern struct nouveau_oclass nve0_vp_oclass;
 
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h b/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h
new file mode 100644
index 0000000..306100f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h
@@ -0,0 +1,38 @@
+#ifndef __NOUVEAU_XTENSA_H__
+#define __NOUVEAU_XTENSA_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+#include <core/gpuobj.h>
+
+struct nouveau_xtensa {
+	struct nouveau_engine base;
+
+	u32 addr;
+	struct nouveau_gpuobj *gpu_fw;
+	u32 fifo_val;
+	u32 unkd28;
+};
+
+#define nouveau_xtensa_create(p,e,c,b,d,i,f,r)				\
+	nouveau_xtensa_create_((p), (e), (c), (b), (d), (i), (f),	\
+			       sizeof(**r),(void **)r)
+
+int _nouveau_xtensa_engctx_ctor(struct nouveau_object *,
+				struct nouveau_object *,
+				struct nouveau_oclass *, void *, u32,
+				struct nouveau_object **);
+
+void _nouveau_xtensa_intr(struct nouveau_subdev *);
+int nouveau_xtensa_create_(struct nouveau_object *,
+			   struct nouveau_object *,
+			   struct nouveau_oclass *, u32, bool,
+			   const char *, const char *,
+			   int, void **);
+#define _nouveau_xtensa_dtor _nouveau_engine_dtor
+int _nouveau_xtensa_init(struct nouveau_object *);
+int _nouveau_xtensa_fini(struct nouveau_object *, bool);
+u32  _nouveau_xtensa_rd32(struct nouveau_object *, u64);
+void _nouveau_xtensa_wr32(struct nouveau_object *, u64, u32);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
index 41b7a6a..89ee289 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
@@ -10,8 +10,6 @@
 struct nouveau_clock {
 	struct nouveau_subdev base;
 
-	int (*pll_set)(struct nouveau_clock *, u32 type, u32 freq);
-
 	/*XXX: die, these are here *only* to support the completely
 	 *     bat-shit insane what-was-nouveau_hw.c code
 	 */
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
index 29e4cc1..685c9b1 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
@@ -8,6 +8,8 @@
 	struct nouveau_subdev base;
 	bool post;
 	void (*meminit)(struct nouveau_devinit *);
+	int  (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
+
 };
 
 static inline struct nouveau_devinit *
@@ -20,11 +22,20 @@
 	nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
 #define nouveau_devinit_destroy(p)                                             \
 	nouveau_subdev_destroy(&(p)->base)
+#define nouveau_devinit_init(p) ({                                             \
+	struct nouveau_devinit *d = (p);                                       \
+	_nouveau_devinit_init(nv_object(d));                                   \
+})
+#define nouveau_devinit_fini(p,s) ({                                           \
+	struct nouveau_devinit *d = (p);                                       \
+	_nouveau_devinit_fini(nv_object(d), (s));                              \
+})
 
 int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
 			    struct nouveau_oclass *, int, void **);
-int nouveau_devinit_init(struct nouveau_devinit *);
-int nouveau_devinit_fini(struct nouveau_devinit *, bool suspend);
+#define _nouveau_devinit_dtor _nouveau_subdev_dtor
+int _nouveau_devinit_init(struct nouveau_object *);
+int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);
 
 extern struct nouveau_oclass nv04_devinit_oclass;
 extern struct nouveau_oclass nv05_devinit_oclass;
@@ -32,9 +43,7 @@
 extern struct nouveau_oclass nv1a_devinit_oclass;
 extern struct nouveau_oclass nv20_devinit_oclass;
 extern struct nouveau_oclass nv50_devinit_oclass;
-
-void nv04_devinit_dtor(struct nouveau_object *);
-int  nv04_devinit_init(struct nouveau_object *);
-int  nv04_devinit_fini(struct nouveau_object *, bool);
+extern struct nouveau_oclass nva3_devinit_oclass;
+extern struct nouveau_oclass nvc0_devinit_oclass;
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
index da470e6..2e74050 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
@@ -53,31 +53,7 @@
 
 	bool (*memtype_valid)(struct nouveau_fb *, u32 memtype);
 
-	struct {
-		enum {
-			NV_MEM_TYPE_UNKNOWN = 0,
-			NV_MEM_TYPE_STOLEN,
-			NV_MEM_TYPE_SGRAM,
-			NV_MEM_TYPE_SDRAM,
-			NV_MEM_TYPE_DDR1,
-			NV_MEM_TYPE_DDR2,
-			NV_MEM_TYPE_DDR3,
-			NV_MEM_TYPE_GDDR2,
-			NV_MEM_TYPE_GDDR3,
-			NV_MEM_TYPE_GDDR4,
-			NV_MEM_TYPE_GDDR5
-		} type;
-		u64 stolen;
-		u64 size;
-
-		int ranks;
-		int parts;
-
-		int  (*init)(struct nouveau_fb *);
-		int  (*get)(struct nouveau_fb *, u64 size, u32 align,
-			    u32 size_nc, u32 type, struct nouveau_mem **);
-		void (*put)(struct nouveau_fb *, struct nouveau_mem **);
-	} ram;
+	struct nouveau_ram *ram;
 
 	struct nouveau_mm vram;
 	struct nouveau_mm tags;
@@ -102,18 +78,6 @@
 	return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB];
 }
 
-#define nouveau_fb_create(p,e,c,d)                                             \
-	nouveau_subdev_create((p), (e), (c), 0, "PFB", "fb", (d))
-int  nouveau_fb_preinit(struct nouveau_fb *);
-void nouveau_fb_destroy(struct nouveau_fb *);
-int  nouveau_fb_init(struct nouveau_fb *);
-#define nouveau_fb_fini(p,s)                                                   \
-	nouveau_subdev_fini(&(p)->base, (s))
-
-void _nouveau_fb_dtor(struct nouveau_object *);
-int  _nouveau_fb_init(struct nouveau_object *);
-#define _nouveau_fb_fini _nouveau_subdev_fini
-
 extern struct nouveau_oclass nv04_fb_oclass;
 extern struct nouveau_oclass nv10_fb_oclass;
 extern struct nouveau_oclass nv1a_fb_oclass;
@@ -132,40 +96,31 @@
 extern struct nouveau_oclass nv50_fb_oclass;
 extern struct nouveau_oclass nvc0_fb_oclass;
 
-struct nouveau_bios;
-int  nouveau_fb_bios_memtype(struct nouveau_bios *);
+struct nouveau_ram {
+	struct nouveau_object base;
+	enum {
+		NV_MEM_TYPE_UNKNOWN = 0,
+		NV_MEM_TYPE_STOLEN,
+		NV_MEM_TYPE_SGRAM,
+		NV_MEM_TYPE_SDRAM,
+		NV_MEM_TYPE_DDR1,
+		NV_MEM_TYPE_DDR2,
+		NV_MEM_TYPE_DDR3,
+		NV_MEM_TYPE_GDDR2,
+		NV_MEM_TYPE_GDDR3,
+		NV_MEM_TYPE_GDDR4,
+		NV_MEM_TYPE_GDDR5
+	} type;
+	u64 stolen;
+	u64 size;
+	u32 tags;
 
-bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
+	int ranks;
+	int parts;
 
-void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int  nv20_fb_vram_init(struct nouveau_fb *);
-void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int  nv30_fb_init(struct nouveau_object *);
-void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
-		       struct nouveau_fb_tile *);
-
-int  nv41_fb_vram_init(struct nouveau_fb *);
-int  nv41_fb_init(struct nouveau_object *);
-void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int  nv44_fb_vram_init(struct nouveau_fb *);
-int  nv44_fb_init(struct nouveau_object *);
-void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
-		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-void nv50_fb_vram_del(struct nouveau_fb *, struct nouveau_mem **);
+	int  (*get)(struct nouveau_fb *, u64 size, u32 align,
+		    u32 size_nc, u32 type, struct nouveau_mem **);
+	void (*put)(struct nouveau_fb *, struct nouveau_mem **);
+};
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
index 9d595ef..f2e87b1 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
@@ -58,7 +58,7 @@
 	int refcount;
 
 	struct list_head pgd_list;
-	atomic_t engref[64]; //NVDEV_SUBDEV_NR];
+	atomic_t engref[NVDEV_SUBDEV_NR];
 
 	struct nouveau_vm_pgt *pgt;
 	u32 fpde;
@@ -117,9 +117,6 @@
 		    struct nouveau_vm **);
 void nv04_vmmgr_dtor(struct nouveau_object *);
 
-void nv50_vm_flush_engine(struct nouveau_subdev *, int engine);
-void nvc0_vm_flush_engine(struct nouveau_subdev *, u64 addr, int type);
-
 /* nouveau_vm.c */
 int  nouveau_vm_create(struct nouveau_vmmgr *, u64 offset, u64 length,
 		       u64 mm_offset, u32 block, struct nouveau_vm **);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
index 649f1ce..160d27f3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
@@ -53,7 +53,6 @@
 		return ret;
 
 	nouveau_vm_map(vma, mem);
-	nv50_vm_flush_engine(nv_subdev(bar), 6);
 	return 0;
 }
 
@@ -69,7 +68,6 @@
 		return ret;
 
 	nouveau_vm_map(vma, mem);
-	nv50_vm_flush_engine(nv_subdev(bar), 6);
 	return 0;
 }
 
@@ -77,7 +75,6 @@
 nv50_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma)
 {
 	nouveau_vm_unmap(vma);
-	nv50_vm_flush_engine(nv_subdev(bar), 6);
 	nouveau_vm_put(vma);
 }
 
@@ -147,6 +144,8 @@
 	if (ret)
 		return ret;
 
+	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
 	ret = nouveau_gpuobj_new(nv_object(priv), heap,
 				 ((limit-- - start) >> 12) * 8, 0x1000,
 				 NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]);
@@ -179,6 +178,8 @@
 	if (ret)
 		return ret;
 
+	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
 	ret = nouveau_vm_ref(vm, &priv->bar1_vm, priv->pgd);
 	nouveau_vm_ref(NULL, &vm, NULL);
 	if (ret)
@@ -237,7 +238,11 @@
 
 	nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
 	nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
-	nv50_vm_flush_engine(nv_subdev(priv), 6);
+	nv_wr32(priv, 0x100c80, 0x00060001);
+	if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) {
+		nv_error(priv, "vm flush timeout\n");
+		return -EBUSY;
+	}
 
 	nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12);
 	nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
index f8a44956..b2ec741 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
@@ -51,7 +51,6 @@
 		return ret;
 
 	nouveau_vm_map(vma, mem);
-	nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[0].pgd->addr, 5);
 	return 0;
 }
 
@@ -68,18 +67,13 @@
 		return ret;
 
 	nouveau_vm_map(vma, mem);
-	nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[1].pgd->addr, 5);
 	return 0;
 }
 
 static void
 nvc0_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma)
 {
-	struct nvc0_bar_priv *priv = (void *)bar;
-	int i = !(vma->vm == priv->bar[0].vm);
-
 	nouveau_vm_unmap(vma);
-	nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[i].pgd->addr, 5);
 	nouveau_vm_put(vma);
 }
 
@@ -116,6 +110,8 @@
 	if (ret)
 		return ret;
 
+	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
 	ret = nouveau_gpuobj_new(nv_object(priv), NULL,
 				 (pci_resource_len(pdev, 3) >> 12) * 8,
 				 0x1000, NVOBJ_FLAG_ZERO_ALLOC,
@@ -150,6 +146,8 @@
 	if (ret)
 		return ret;
 
+	atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
 	ret = nouveau_vm_ref(vm, &priv->bar[1].vm, priv->bar[1].pgd);
 	nouveau_vm_ref(NULL, &vm, NULL);
 	if (ret)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
index 0e2c1a4..aa0fbbe 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
@@ -85,11 +85,15 @@
 nouveau_bios_shadow_pramin(struct nouveau_bios *bios)
 {
 	struct nouveau_device *device = nv_device(bios);
+	u64 addr = 0;
 	u32 bar0 = 0;
 	int i;
 
 	if (device->card_type >= NV_50) {
-		u64 addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8;
+		if (  device->card_type < NV_C0 ||
+		    !(nv_rd32(bios, 0x022500) & 0x00000001))
+			addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8;
+
 		if (!addr) {
 			addr  = (u64)nv_rd32(bios, 0x001700) << 16;
 			addr += 0xf0000;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
index c434d39..0687e64 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
@@ -10,7 +10,6 @@
 #include <subdev/bios/gpio.h>
 #include <subdev/bios/init.h>
 #include <subdev/devinit.h>
-#include <subdev/clock.h>
 #include <subdev/i2c.h>
 #include <subdev/vga.h>
 #include <subdev/gpio.h>
@@ -300,9 +299,9 @@
 static void
 init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
 {
-	struct nouveau_clock *clk = nouveau_clock(init->bios);
-	if (clk && clk->pll_set && init_exec(init)) {
-		int ret = clk->pll_set(clk, id, freq);
+	struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
+	if (devinit->pll_set && init_exec(init)) {
+		int ret = devinit->pll_set(devinit, id, freq);
 		if (ret)
 			warn("failed to prog pll 0x%08x to %dkHz\n", id, freq);
 	}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
index b7fd115..a142775 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
@@ -22,9 +22,10 @@
  * Authors: Ben Skeggs
  */
 
-#include <subdev/clock.h>
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
+#include <subdev/clock.h>
+#include <subdev/devinit/priv.h>
 
 #include "pll.h"
 
@@ -32,272 +33,12 @@
 	struct nouveau_clock base;
 };
 
-static int
-powerctrl_1_shift(int chip_version, int reg)
-{
-	int shift = -4;
-
-	if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
-		return shift;
-
-	switch (reg) {
-	case 0x680520:
-		shift += 4;
-	case 0x680508:
-		shift += 4;
-	case 0x680504:
-		shift += 4;
-	case 0x680500:
-		shift += 4;
-	}
-
-	/*
-	 * the shift for vpll regs is only used for nv3x chips with a single
-	 * stage pll
-	 */
-	if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
-			  chip_version == 0x36 || chip_version >= 0x40))
-		shift = -4;
-
-	return shift;
-}
-
-static void
-setPLL_single(struct nv04_clock_priv *priv, u32 reg,
-	      struct nouveau_pll_vals *pv)
-{
-	int chip_version = nouveau_bios(priv)->version.chip;
-	uint32_t oldpll = nv_rd32(priv, reg);
-	int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
-	uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
-	uint32_t saved_powerctrl_1 = 0;
-	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
-
-	if (oldpll == pll)
-		return;	/* already set */
-
-	if (shift_powerctrl_1 >= 0) {
-		saved_powerctrl_1 = nv_rd32(priv, 0x001584);
-		nv_wr32(priv, 0x001584,
-			(saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
-			1 << shift_powerctrl_1);
-	}
-
-	if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
-		/* upclock -- write new post divider first */
-		nv_wr32(priv, reg, pv->log2P << 16 | (oldpll & 0xffff));
-	else
-		/* downclock -- write new NM first */
-		nv_wr32(priv, reg, (oldpll & 0xffff0000) | pv->NM1);
-
-	if (chip_version < 0x17 && chip_version != 0x11)
-		/* wait a bit on older chips */
-		msleep(64);
-	nv_rd32(priv, reg);
-
-	/* then write the other half as well */
-	nv_wr32(priv, reg, pll);
-
-	if (shift_powerctrl_1 >= 0)
-		nv_wr32(priv, 0x001584, saved_powerctrl_1);
-}
-
-static uint32_t
-new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
-{
-	bool head_a = (reg1 == 0x680508);
-
-	if (ss)	/* single stage pll mode */
-		ramdac580 |= head_a ? 0x00000100 : 0x10000000;
-	else
-		ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
-
-	return ramdac580;
-}
-
-static void
-setPLL_double_highregs(struct nv04_clock_priv *priv, u32 reg1,
-		       struct nouveau_pll_vals *pv)
-{
-	int chip_version = nouveau_bios(priv)->version.chip;
-	bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
-	uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
-	uint32_t oldpll1 = nv_rd32(priv, reg1);
-	uint32_t oldpll2 = !nv3035 ? nv_rd32(priv, reg2) : 0;
-	uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
-	uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
-	uint32_t oldramdac580 = 0, ramdac580 = 0;
-	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;	/* nv41+ only */
-	uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
-	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
-
-	/* model specific additions to generic pll1 and pll2 set up above */
-	if (nv3035) {
-		pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
-		       (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
-		pll2 = 0;
-	}
-	if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */
-		oldramdac580 = nv_rd32(priv, 0x680580);
-		ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
-		if (oldramdac580 != ramdac580)
-			oldpll1 = ~0;	/* force mismatch */
-		if (single_stage)
-			/* magic value used by nvidia in single stage mode */
-			pll2 |= 0x011f;
-	}
-	if (chip_version > 0x70)
-		/* magic bits set by the blob (but not the bios) on g71-73 */
-		pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
-
-	if (oldpll1 == pll1 && oldpll2 == pll2)
-		return;	/* already set */
-
-	if (shift_powerctrl_1 >= 0) {
-		saved_powerctrl_1 = nv_rd32(priv, 0x001584);
-		nv_wr32(priv, 0x001584,
-			(saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
-			1 << shift_powerctrl_1);
-	}
-
-	if (chip_version >= 0x40) {
-		int shift_c040 = 14;
-
-		switch (reg1) {
-		case 0x680504:
-			shift_c040 += 2;
-		case 0x680500:
-			shift_c040 += 2;
-		case 0x680520:
-			shift_c040 += 2;
-		case 0x680508:
-			shift_c040 += 2;
-		}
-
-		savedc040 = nv_rd32(priv, 0xc040);
-		if (shift_c040 != 14)
-			nv_wr32(priv, 0xc040, savedc040 & ~(3 << shift_c040));
-	}
-
-	if (oldramdac580 != ramdac580)
-		nv_wr32(priv, 0x680580, ramdac580);
-
-	if (!nv3035)
-		nv_wr32(priv, reg2, pll2);
-	nv_wr32(priv, reg1, pll1);
-
-	if (shift_powerctrl_1 >= 0)
-		nv_wr32(priv, 0x001584, saved_powerctrl_1);
-	if (chip_version >= 0x40)
-		nv_wr32(priv, 0xc040, savedc040);
-}
-
-static void
-setPLL_double_lowregs(struct nv04_clock_priv *priv, u32 NMNMreg,
-		      struct nouveau_pll_vals *pv)
-{
-	/* When setting PLLs, there is a merry game of disabling and enabling
-	 * various bits of hardware during the process. This function is a
-	 * synthesis of six nv4x traces, nearly each card doing a subtly
-	 * different thing. With luck all the necessary bits for each card are
-	 * combined herein. Without luck it deviates from each card's formula
-	 * so as to not work on any :)
-	 */
-
-	uint32_t Preg = NMNMreg - 4;
-	bool mpll = Preg == 0x4020;
-	uint32_t oldPval = nv_rd32(priv, Preg);
-	uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
-	uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
-			0xc << 28 | pv->log2P << 16;
-	uint32_t saved4600 = 0;
-	/* some cards have different maskc040s */
-	uint32_t maskc040 = ~(3 << 14), savedc040;
-	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
-
-	if (nv_rd32(priv, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
-		return;
-
-	if (Preg == 0x4000)
-		maskc040 = ~0x333;
-	if (Preg == 0x4058)
-		maskc040 = ~(0xc << 24);
-
-	if (mpll) {
-		struct nvbios_pll info;
-		uint8_t Pval2;
-
-		if (nvbios_pll_parse(nouveau_bios(priv), Preg, &info))
-			return;
-
-		Pval2 = pv->log2P + info.bias_p;
-		if (Pval2 > info.max_p)
-			Pval2 = info.max_p;
-		Pval |= 1 << 28 | Pval2 << 20;
-
-		saved4600 = nv_rd32(priv, 0x4600);
-		nv_wr32(priv, 0x4600, saved4600 | 8 << 28);
-	}
-	if (single_stage)
-		Pval |= mpll ? 1 << 12 : 1 << 8;
-
-	nv_wr32(priv, Preg, oldPval | 1 << 28);
-	nv_wr32(priv, Preg, Pval & ~(4 << 28));
-	if (mpll) {
-		Pval |= 8 << 20;
-		nv_wr32(priv, 0x4020, Pval & ~(0xc << 28));
-		nv_wr32(priv, 0x4038, Pval & ~(0xc << 28));
-	}
-
-	savedc040 = nv_rd32(priv, 0xc040);
-	nv_wr32(priv, 0xc040, savedc040 & maskc040);
-
-	nv_wr32(priv, NMNMreg, NMNM);
-	if (NMNMreg == 0x4024)
-		nv_wr32(priv, 0x403c, NMNM);
-
-	nv_wr32(priv, Preg, Pval);
-	if (mpll) {
-		Pval &= ~(8 << 20);
-		nv_wr32(priv, 0x4020, Pval);
-		nv_wr32(priv, 0x4038, Pval);
-		nv_wr32(priv, 0x4600, saved4600);
-	}
-
-	nv_wr32(priv, 0xc040, savedc040);
-
-	if (mpll) {
-		nv_wr32(priv, 0x4020, Pval & ~(1 << 28));
-		nv_wr32(priv, 0x4038, Pval & ~(1 << 28));
-	}
-}
-
-int
-nv04_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
-{
-	struct nv04_clock_priv *priv = (void *)clk;
-	struct nouveau_pll_vals pv;
-	struct nvbios_pll info;
-	int ret;
-
-	ret = nvbios_pll_parse(nouveau_bios(priv), type > 0x405c ?
-			       type : type - 4, &info);
-	if (ret)
-		return ret;
-
-	ret = clk->pll_calc(clk, &info, freq, &pv);
-	if (!ret)
-		return ret;
-
-	return clk->pll_prog(clk, type, &pv);
-}
-
 int
 nv04_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
 		    int clk, struct nouveau_pll_vals *pv)
 {
 	int N1, M1, N2, M2, P;
-	int ret = nv04_pll_calc(clock, info, clk, &N1, &M1, &N2, &M2, &P);
+	int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P);
 	if (ret) {
 		pv->refclk = info->refclk;
 		pv->N1 = N1;
@@ -313,17 +54,17 @@
 nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1,
 		    struct nouveau_pll_vals *pv)
 {
-	struct nv04_clock_priv *priv = (void *)clk;
+	struct nouveau_devinit *devinit = nouveau_devinit(clk);
 	int cv = nouveau_bios(clk)->version.chip;
 
 	if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
 	    cv >= 0x40) {
 		if (reg1 > 0x405c)
-			setPLL_double_highregs(priv, reg1, pv);
+			setPLL_double_highregs(devinit, reg1, pv);
 		else
-			setPLL_double_lowregs(priv, reg1, pv);
+			setPLL_double_lowregs(devinit, reg1, pv);
 	} else
-		setPLL_single(priv, reg1, pv);
+		setPLL_single(devinit, reg1, pv);
 
 	return 0;
 }
@@ -341,7 +82,6 @@
 	if (ret)
 		return ret;
 
-	priv->base.pll_set = nv04_clock_pll_set;
 	priv->base.pll_calc = nv04_clock_pll_calc;
 	priv->base.pll_prog = nv04_clock_pll_prog;
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
index a4b2b7e..0db5dbf 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
@@ -41,7 +41,6 @@
 	if (ret)
 		return ret;
 
-	priv->base.pll_set = nv04_clock_pll_set;
 	priv->base.pll_calc = nv04_clock_pll_calc;
 	priv->base.pll_prog = nv04_clock_pll_prog;
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
index f4147f6..d09d3e7 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
@@ -33,50 +33,6 @@
 };
 
 static int
-nv50_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
-{
-	struct nv50_clock_priv *priv = (void *)clk;
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll info;
-	int N1, M1, N2, M2, P;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, type, &info);
-	if (ret) {
-		nv_error(clk, "failed to retrieve pll data, %d\n", ret);
-		return ret;
-	}
-
-	ret = nv04_pll_calc(clk, &info, freq, &N1, &M1, &N2, &M2, &P);
-	if (!ret) {
-		nv_error(clk, "failed pll calculation\n");
-		return ret;
-	}
-
-	switch (info.type) {
-	case PLL_VPLL0:
-	case PLL_VPLL1:
-		nv_wr32(priv, info.reg + 0, 0x10000611);
-		nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1);
-		nv_mask(priv, info.reg + 8, 0x7fff00ff, (P  << 28) |
-							(M2 << 16) | N2);
-		break;
-	case PLL_MEMORY:
-		nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) |
-						        (info.bias_p << 19) |
-							(P << 16));
-		nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
-		break;
-	default:
-		nv_mask(priv, info.reg + 0, 0x00070000, (P << 16));
-		nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
-		break;
-	}
-
-	return 0;
-}
-
-static int
 nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 		struct nouveau_oclass *oclass, void *data, u32 size,
 		struct nouveau_object **pobject)
@@ -89,7 +45,6 @@
 	if (ret)
 		return ret;
 
-	priv->base.pll_set = nv50_clock_pll_set;
 	priv->base.pll_calc = nv04_clock_pll_calc;
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
index 9068c98..f074cd2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
@@ -32,47 +32,13 @@
 	struct nouveau_clock base;
 };
 
-static int
-nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
-{
-	struct nva3_clock_priv *priv = (void *)clk;
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll info;
-	int N, fN, M, P;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, type, &info);
-	if (ret)
-		return ret;
-
-	ret = nva3_pll_calc(clk, &info, freq, &N, &fN, &M, &P);
-	if (ret < 0)
-		return ret;
-
-	switch (info.type) {
-	case PLL_VPLL0:
-	case PLL_VPLL1:
-		nv_wr32(priv, info.reg + 0, 0x50000610);
-		nv_mask(priv, info.reg + 4, 0x003fffff,
-					    (P << 16) | (M << 8) | N);
-		nv_wr32(priv, info.reg + 8, fN);
-		break;
-	default:
-		nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
 int
 nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
 		    int clk, struct nouveau_pll_vals *pv)
 {
 	int ret, N, M, P;
 
-	ret = nva3_pll_calc(clock, info, clk, &N, NULL, &M, &P);
+	ret = nva3_pll_calc(nv_subdev(clock), info, clk, &N, NULL, &M, &P);
 
 	if (ret > 0) {
 		pv->refclk = info->refclk;
@@ -97,7 +63,6 @@
 	if (ret)
 		return ret;
 
-	priv->base.pll_set = nva3_clock_pll_set;
 	priv->base.pll_calc = nva3_clock_pll_calc;
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
index 7c96262..439d81c2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
@@ -33,41 +33,6 @@
 };
 
 static int
-nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
-{
-	struct nvc0_clock_priv *priv = (void *)clk;
-	struct nouveau_bios *bios = nouveau_bios(priv);
-	struct nvbios_pll info;
-	int N, fN, M, P;
-	int ret;
-
-	ret = nvbios_pll_parse(bios, type, &info);
-	if (ret)
-		return ret;
-
-	ret = nva3_pll_calc(clk, &info, freq, &N, &fN, &M, &P);
-	if (ret < 0)
-		return ret;
-
-	switch (info.type) {
-	case PLL_VPLL0:
-	case PLL_VPLL1:
-	case PLL_VPLL2:
-	case PLL_VPLL3:
-		nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
-		nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
-		nv_wr32(priv, info.reg + 0x10, fN << 16);
-		break;
-	default:
-		nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-static int
 nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 		struct nouveau_oclass *oclass, void *data, u32 size,
 		struct nouveau_object **pobject)
@@ -80,7 +45,6 @@
 	if (ret)
 		return ret;
 
-	priv->base.pll_set = nvc0_clock_pll_set;
 	priv->base.pll_calc = nva3_clock_pll_calc;
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
index ef2c007..445b14c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
@@ -1,9 +1,9 @@
 #ifndef __NOUVEAU_PLL_H__
 #define __NOUVEAU_PLL_H__
 
-int nv04_pll_calc(struct nouveau_clock *, struct nvbios_pll *, u32 freq,
+int nv04_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq,
 		  int *N1, int *M1, int *N2, int *M2, int *P);
-int nva3_pll_calc(struct nouveau_clock *, struct nvbios_pll *, u32 freq,
+int nva3_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq,
 		  int *N, int *fN, int *M, int *P);
 
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
index a2ab6d0..cf1ed0d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
@@ -21,14 +21,13 @@
  * SOFTWARE.
  */
 
-#include <subdev/clock.h>
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
 
 #include "pll.h"
 
 static int
-getMNP_single(struct nouveau_clock *clock, struct nvbios_pll *info, int clk,
+getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
 	      int *pN, int *pM, int *pP)
 {
 	/* Find M, N and P for a single stage PLL
@@ -39,7 +38,7 @@
 	 * "clk" parameter in kHz
 	 * returns calculated clock
 	 */
-	int cv = nouveau_bios(clock)->version.chip;
+	int cv = nouveau_bios(subdev)->version.chip;
 	int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq;
 	int minM = info->vco1.min_m, maxM = info->vco1.max_m;
 	int minN = info->vco1.min_n, maxN = info->vco1.max_n;
@@ -124,7 +123,7 @@
 }
 
 static int
-getMNP_double(struct nouveau_clock *clock, struct nvbios_pll *info, int clk,
+getMNP_double(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
 	      int *pN1, int *pM1, int *pN2, int *pM2, int *pP)
 {
 	/* Find M, N and P for a two stage PLL
@@ -135,7 +134,7 @@
 	 * "clk" parameter in kHz
 	 * returns calculated clock
 	 */
-	int chip_version = nouveau_bios(clock)->version.chip;
+	int chip_version = nouveau_bios(subdev)->version.chip;
 	int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq;
 	int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq;
 	int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq;
@@ -223,20 +222,20 @@
 }
 
 int
-nv04_pll_calc(struct nouveau_clock *clk, struct nvbios_pll *info, u32 freq,
+nv04_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq,
 	      int *N1, int *M1, int *N2, int *M2, int *P)
 {
 	int ret;
 
 	if (!info->vco2.max_freq) {
-		ret = getMNP_single(clk, info, freq, N1, M1, P);
+		ret = getMNP_single(subdev, info, freq, N1, M1, P);
 		*N2 = 1;
 		*M2 = 1;
 	} else {
-		ret = getMNP_double(clk, info, freq, N1, M1, N2, M2, P);
+		ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P);
 	}
 
 	if (!ret)
-		nv_error(clk, "unable to compute acceptable pll values\n");
+		nv_error(subdev, "unable to compute acceptable pll values\n");
 	return ret;
 }
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
index eed5c16..2fe1f71 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
@@ -29,7 +29,7 @@
 #include "pll.h"
 
 int
-nva3_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
+nva3_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info,
 	      u32 freq, int *pN, int *pfN, int *pM, int *P)
 {
 	u32 best_err = ~0, err;
@@ -50,8 +50,15 @@
 		u32 tmp = freq * *P * M;
 		N  = tmp / info->refclk;
 		fN = tmp % info->refclk;
-		if (!pfN && fN >= info->refclk / 2)
-			N++;
+
+		if (!pfN) {
+			if (fN >= info->refclk / 2)
+				N++;
+		} else {
+			if (fN <  info->refclk / 2)
+				N--;
+			fN = tmp - (N * info->refclk);
+		}
 
 		if (N < info->vco1.min_n)
 			continue;
@@ -66,13 +73,14 @@
 		}
 
 		if (pfN) {
-			*pfN = (((fN << 13) / info->refclk) - 4096) & 0xffff;
+			*pfN = ((fN << 13) + info->refclk / 2) / info->refclk;
+			*pfN = (*pfN - 4096) & 0xffff;
 			return freq;
 		}
 	}
 
 	if (unlikely(best_err == ~0)) {
-		nv_error(clock, "unable to find matching pll values\n");
+		nv_error(subdev, "unable to find matching pll values\n");
 		return -EINVAL;
 	}
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
index 5a07a39..79c81d3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
@@ -29,18 +29,10 @@
 #include <subdev/bios/init.h>
 
 int
-nouveau_devinit_init(struct nouveau_devinit *devinit)
+_nouveau_devinit_fini(struct nouveau_object *object, bool suspend)
 {
-	int ret = nouveau_subdev_init(&devinit->base);
-	if (ret)
-		return ret;
+	struct nouveau_devinit *devinit = (void *)object;
 
-	return nvbios_init(&devinit->base, devinit->post);
-}
-
-int
-nouveau_devinit_fini(struct nouveau_devinit *devinit, bool suspend)
-{
 	/* force full reinit on resume */
 	if (suspend)
 		devinit->post = true;
@@ -49,6 +41,17 @@
 }
 
 int
+_nouveau_devinit_init(struct nouveau_object *object)
+{
+	struct nouveau_devinit *devinit = (void *)object;
+	int ret = nouveau_subdev_init(&devinit->base);
+	if (ret)
+		return ret;
+
+	return nvbios_init(&devinit->base, devinit->post);
+}
+
+int
 nouveau_devinit_create_(struct nouveau_object *parent,
 			struct nouveau_object *engine,
 			struct nouveau_oclass *oclass,
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
index 7a72d93..b22357d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
@@ -24,10 +24,10 @@
  *
  */
 
-#include <subdev/devinit.h>
 #include <subdev/vga.h>
 
 #include "fbmem.h"
+#include "priv.h"
 
 struct nv04_devinit_priv {
 	struct nouveau_devinit base;
@@ -111,33 +111,298 @@
 }
 
 static int
-nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
+powerctrl_1_shift(int chip_version, int reg)
 {
-	struct nv04_devinit_priv *priv;
-	int ret;
+	int shift = -4;
 
-	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
-		return ret;
+	if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
+		return shift;
 
-	priv->base.meminit = nv04_devinit_meminit;
-	priv->owner = -1;
-	return 0;
+	switch (reg) {
+	case 0x680520:
+		shift += 4;
+	case 0x680508:
+		shift += 4;
+	case 0x680504:
+		shift += 4;
+	case 0x680500:
+		shift += 4;
+	}
+
+	/*
+	 * the shift for vpll regs is only used for nv3x chips with a single
+	 * stage pll
+	 */
+	if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
+			  chip_version == 0x36 || chip_version >= 0x40))
+		shift = -4;
+
+	return shift;
 }
 
 void
-nv04_devinit_dtor(struct nouveau_object *object)
+setPLL_single(struct nouveau_devinit *devinit, u32 reg,
+	      struct nouveau_pll_vals *pv)
+{
+	int chip_version = nouveau_bios(devinit)->version.chip;
+	uint32_t oldpll = nv_rd32(devinit, reg);
+	int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
+	uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
+	uint32_t saved_powerctrl_1 = 0;
+	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
+
+	if (oldpll == pll)
+		return;	/* already set */
+
+	if (shift_powerctrl_1 >= 0) {
+		saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
+		nv_wr32(devinit, 0x001584,
+			(saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
+			1 << shift_powerctrl_1);
+	}
+
+	if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
+		/* upclock -- write new post divider first */
+		nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff));
+	else
+		/* downclock -- write new NM first */
+		nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1);
+
+	if (chip_version < 0x17 && chip_version != 0x11)
+		/* wait a bit on older chips */
+		msleep(64);
+	nv_rd32(devinit, reg);
+
+	/* then write the other half as well */
+	nv_wr32(devinit, reg, pll);
+
+	if (shift_powerctrl_1 >= 0)
+		nv_wr32(devinit, 0x001584, saved_powerctrl_1);
+}
+
+static uint32_t
+new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
+{
+	bool head_a = (reg1 == 0x680508);
+
+	if (ss)	/* single stage pll mode */
+		ramdac580 |= head_a ? 0x00000100 : 0x10000000;
+	else
+		ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
+
+	return ramdac580;
+}
+
+void
+setPLL_double_highregs(struct nouveau_devinit *devinit, u32 reg1,
+		       struct nouveau_pll_vals *pv)
+{
+	int chip_version = nouveau_bios(devinit)->version.chip;
+	bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
+	uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
+	uint32_t oldpll1 = nv_rd32(devinit, reg1);
+	uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0;
+	uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
+	uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
+	uint32_t oldramdac580 = 0, ramdac580 = 0;
+	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;	/* nv41+ only */
+	uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
+	int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
+
+	/* model specific additions to generic pll1 and pll2 set up above */
+	if (nv3035) {
+		pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
+		       (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
+		pll2 = 0;
+	}
+	if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */
+		oldramdac580 = nv_rd32(devinit, 0x680580);
+		ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
+		if (oldramdac580 != ramdac580)
+			oldpll1 = ~0;	/* force mismatch */
+		if (single_stage)
+			/* magic value used by nvidia in single stage mode */
+			pll2 |= 0x011f;
+	}
+	if (chip_version > 0x70)
+		/* magic bits set by the blob (but not the bios) on g71-73 */
+		pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
+
+	if (oldpll1 == pll1 && oldpll2 == pll2)
+		return;	/* already set */
+
+	if (shift_powerctrl_1 >= 0) {
+		saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
+		nv_wr32(devinit, 0x001584,
+			(saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
+			1 << shift_powerctrl_1);
+	}
+
+	if (chip_version >= 0x40) {
+		int shift_c040 = 14;
+
+		switch (reg1) {
+		case 0x680504:
+			shift_c040 += 2;
+		case 0x680500:
+			shift_c040 += 2;
+		case 0x680520:
+			shift_c040 += 2;
+		case 0x680508:
+			shift_c040 += 2;
+		}
+
+		savedc040 = nv_rd32(devinit, 0xc040);
+		if (shift_c040 != 14)
+			nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040));
+	}
+
+	if (oldramdac580 != ramdac580)
+		nv_wr32(devinit, 0x680580, ramdac580);
+
+	if (!nv3035)
+		nv_wr32(devinit, reg2, pll2);
+	nv_wr32(devinit, reg1, pll1);
+
+	if (shift_powerctrl_1 >= 0)
+		nv_wr32(devinit, 0x001584, saved_powerctrl_1);
+	if (chip_version >= 0x40)
+		nv_wr32(devinit, 0xc040, savedc040);
+}
+
+void
+setPLL_double_lowregs(struct nouveau_devinit *devinit, u32 NMNMreg,
+		      struct nouveau_pll_vals *pv)
+{
+	/* When setting PLLs, there is a merry game of disabling and enabling
+	 * various bits of hardware during the process. This function is a
+	 * synthesis of six nv4x traces, nearly each card doing a subtly
+	 * different thing. With luck all the necessary bits for each card are
+	 * combined herein. Without luck it deviates from each card's formula
+	 * so as to not work on any :)
+	 */
+
+	uint32_t Preg = NMNMreg - 4;
+	bool mpll = Preg == 0x4020;
+	uint32_t oldPval = nv_rd32(devinit, Preg);
+	uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
+	uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
+			0xc << 28 | pv->log2P << 16;
+	uint32_t saved4600 = 0;
+	/* some cards have different maskc040s */
+	uint32_t maskc040 = ~(3 << 14), savedc040;
+	bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
+
+	if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
+		return;
+
+	if (Preg == 0x4000)
+		maskc040 = ~0x333;
+	if (Preg == 0x4058)
+		maskc040 = ~(0xc << 24);
+
+	if (mpll) {
+		struct nvbios_pll info;
+		uint8_t Pval2;
+
+		if (nvbios_pll_parse(nouveau_bios(devinit), Preg, &info))
+			return;
+
+		Pval2 = pv->log2P + info.bias_p;
+		if (Pval2 > info.max_p)
+			Pval2 = info.max_p;
+		Pval |= 1 << 28 | Pval2 << 20;
+
+		saved4600 = nv_rd32(devinit, 0x4600);
+		nv_wr32(devinit, 0x4600, saved4600 | 8 << 28);
+	}
+	if (single_stage)
+		Pval |= mpll ? 1 << 12 : 1 << 8;
+
+	nv_wr32(devinit, Preg, oldPval | 1 << 28);
+	nv_wr32(devinit, Preg, Pval & ~(4 << 28));
+	if (mpll) {
+		Pval |= 8 << 20;
+		nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28));
+		nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28));
+	}
+
+	savedc040 = nv_rd32(devinit, 0xc040);
+	nv_wr32(devinit, 0xc040, savedc040 & maskc040);
+
+	nv_wr32(devinit, NMNMreg, NMNM);
+	if (NMNMreg == 0x4024)
+		nv_wr32(devinit, 0x403c, NMNM);
+
+	nv_wr32(devinit, Preg, Pval);
+	if (mpll) {
+		Pval &= ~(8 << 20);
+		nv_wr32(devinit, 0x4020, Pval);
+		nv_wr32(devinit, 0x4038, Pval);
+		nv_wr32(devinit, 0x4600, saved4600);
+	}
+
+	nv_wr32(devinit, 0xc040, savedc040);
+
+	if (mpll) {
+		nv_wr32(devinit, 0x4020, Pval & ~(1 << 28));
+		nv_wr32(devinit, 0x4038, Pval & ~(1 << 28));
+	}
+}
+
+int
+nv04_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
+{
+	struct nouveau_bios *bios = nouveau_bios(devinit);
+	struct nouveau_pll_vals pv;
+	struct nvbios_pll info;
+	int cv = bios->version.chip;
+	int N1, M1, N2, M2, P;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info);
+	if (ret)
+		return ret;
+
+	ret = nv04_pll_calc(nv_subdev(devinit), &info, freq,
+			   &N1, &M1, &N2, &M2, &P);
+	if (!ret)
+		return -EINVAL;
+
+	pv.refclk = info.refclk;
+	pv.N1 = N1;
+	pv.M1 = M1;
+	pv.N2 = N2;
+	pv.M2 = M2;
+	pv.log2P = P;
+
+	if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
+	    cv >= 0x40) {
+		if (type > 0x405c)
+			setPLL_double_highregs(devinit, type, &pv);
+		else
+			setPLL_double_lowregs(devinit, type, &pv);
+	} else
+		setPLL_single(devinit, type, &pv);
+
+	return 0;
+}
+
+int
+nv04_devinit_fini(struct nouveau_object *object, bool suspend)
 {
 	struct nv04_devinit_priv *priv = (void *)object;
 
-	/* restore vga owner saved at first init, and lock crtc regs  */
-	nv_wrvgaowner(priv, priv->owner);
-	nv_lockvgac(priv, true);
+	/* make i2c busses accessible */
+	nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
 
-	nouveau_devinit_destroy(&priv->base);
+	/* unlock extended vga crtc regs, and unslave crtcs */
+	nv_lockvgac(priv, false);
+	if (priv->owner < 0)
+		priv->owner = nv_rdvgaowner(priv);
+	nv_wrvgaowner(priv, 0);
+
+	return nouveau_devinit_fini(&priv->base, suspend);
 }
 
 int
@@ -160,21 +425,35 @@
 	return nouveau_devinit_init(&priv->base);
 }
 
-int
-nv04_devinit_fini(struct nouveau_object *object, bool suspend)
+void
+nv04_devinit_dtor(struct nouveau_object *object)
 {
 	struct nv04_devinit_priv *priv = (void *)object;
 
-	/* make i2c busses accessible */
-	nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
+	/* restore vga owner saved at first init, and lock crtc regs  */
+	nv_wrvgaowner(priv, priv->owner);
+	nv_lockvgac(priv, true);
 
-	/* unlock extended vga crtc regs, and unslave crtcs */
-	nv_lockvgac(priv, false);
-	if (priv->owner < 0)
-		priv->owner = nv_rdvgaowner(priv);
-	nv_wrvgaowner(priv, 0);
+	nouveau_devinit_destroy(&priv->base);
+}
 
-	return nouveau_devinit_fini(&priv->base, suspend);
+static int
+nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		  struct nouveau_oclass *oclass, void *data, u32 size,
+		  struct nouveau_object **pobject)
+{
+	struct nv04_devinit_priv *priv;
+	int ret;
+
+	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.meminit = nv04_devinit_meminit;
+	priv->base.pll_set = nv04_devinit_pll_set;
+	priv->owner = -1;
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
index 191447d..b1912a8a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
@@ -24,12 +24,12 @@
  *
  */
 
-#include <subdev/devinit.h>
 #include <subdev/bios.h>
 #include <subdev/bios/bmp.h>
 #include <subdev/vga.h>
 
 #include "fbmem.h"
+#include "priv.h"
 
 struct nv05_devinit_priv {
 	struct nouveau_devinit base;
@@ -144,6 +144,7 @@
 		return ret;
 
 	priv->base.meminit = nv05_devinit_meminit;
+	priv->base.pll_set = nv04_devinit_pll_set;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
index eb76ffa..463b08f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
@@ -24,10 +24,10 @@
  *
  */
 
-#include <subdev/devinit.h>
 #include <subdev/vga.h>
 
 #include "fbmem.h"
+#include "priv.h"
 
 struct nv10_devinit_priv {
 	struct nouveau_devinit base;
@@ -109,6 +109,7 @@
 		return ret;
 
 	priv->base.meminit = nv10_devinit_meminit;
+	priv->base.pll_set = nv04_devinit_pll_set;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
index 5b2ba63..e9743cd 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
@@ -22,8 +22,7 @@
  * Authors: Ben Skeggs
  */
 
-#include <subdev/devinit.h>
-#include <subdev/vga.h>
+#include "priv.h"
 
 struct nv1a_devinit_priv {
 	struct nouveau_devinit base;
@@ -43,6 +42,7 @@
 	if (ret)
 		return ret;
 
+	priv->base.pll_set = nv04_devinit_pll_set;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
index eb32e99..6cc6080 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
@@ -24,9 +24,7 @@
  *
  */
 
-#include <subdev/devinit.h>
-#include <subdev/vga.h>
-
+#include "priv.h"
 #include "fbmem.h"
 
 struct nv20_devinit_priv {
@@ -81,6 +79,7 @@
 		return ret;
 
 	priv->base.meminit = nv20_devinit_meminit;
+	priv->base.pll_set = nv04_devinit_pll_set;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
index 4a85778..6df7224 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012 Red Hat Inc.
+ * Copyright 2013 Red Hat Inc.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -26,37 +26,55 @@
 #include <subdev/bios/dcb.h>
 #include <subdev/bios/disp.h>
 #include <subdev/bios/init.h>
-#include <subdev/devinit.h>
 #include <subdev/vga.h>
 
-struct nv50_devinit_priv {
-	struct nouveau_devinit base;
-};
+#include "priv.h"
 
 static int
-nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-		  struct nouveau_oclass *oclass, void *data, u32 size,
-		  struct nouveau_object **pobject)
+nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
 {
-	struct nv50_devinit_priv *priv;
+	struct nv50_devinit_priv *priv = (void *)devinit;
+	struct nouveau_bios *bios = nouveau_bios(priv);
+	struct nvbios_pll info;
+	int N1, M1, N2, M2, P;
 	int ret;
 
-	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-	*pobject = nv_object(priv);
-	if (ret)
+	ret = nvbios_pll_parse(bios, type, &info);
+	if (ret) {
+		nv_error(devinit, "failed to retrieve pll data, %d\n", ret);
 		return ret;
+	}
+
+	ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P);
+	if (!ret) {
+		nv_error(devinit, "failed pll calculation\n");
+		return ret;
+	}
+
+	switch (info.type) {
+	case PLL_VPLL0:
+	case PLL_VPLL1:
+		nv_wr32(priv, info.reg + 0, 0x10000611);
+		nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1);
+		nv_mask(priv, info.reg + 8, 0x7fff00ff, (P  << 28) |
+							(M2 << 16) | N2);
+		break;
+	case PLL_MEMORY:
+		nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) |
+						        (info.bias_p << 19) |
+							(P << 16));
+		nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
+		break;
+	default:
+		nv_mask(priv, info.reg + 0, 0x00070000, (P << 16));
+		nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
+		break;
+	}
 
 	return 0;
 }
 
-static void
-nv50_devinit_dtor(struct nouveau_object *object)
-{
-	struct nv50_devinit_priv *priv = (void *)object;
-	nouveau_devinit_destroy(&priv->base);
-}
-
-static int
+int
 nv50_devinit_init(struct nouveau_object *object)
 {
 	struct nouveau_bios *bios = nouveau_bios(object);
@@ -103,10 +121,20 @@
 }
 
 static int
-nv50_devinit_fini(struct nouveau_object *object, bool suspend)
+nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		  struct nouveau_oclass *oclass, void *data, u32 size,
+		  struct nouveau_object **pobject)
 {
-	struct nv50_devinit_priv *priv = (void *)object;
-	return nouveau_devinit_fini(&priv->base, suspend);
+	struct nv50_devinit_priv *priv;
+	int ret;
+
+	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.pll_set = nv50_devinit_pll_set;
+	return 0;
 }
 
 struct nouveau_oclass
@@ -114,8 +142,8 @@
 	.handle = NV_SUBDEV(DEVINIT, 0x50),
 	.ofuncs = &(struct nouveau_ofuncs) {
 		.ctor = nv50_devinit_ctor,
-		.dtor = nv50_devinit_dtor,
+		.dtor = _nouveau_devinit_dtor,
 		.init = nv50_devinit_init,
-		.fini = nv50_devinit_fini,
+		.fini = _nouveau_devinit_fini,
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
new file mode 100644
index 0000000..76a68b2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
+{
+	struct nva3_devinit_priv *priv = (void *)devinit;
+	struct nouveau_bios *bios = nouveau_bios(priv);
+	struct nvbios_pll info;
+	int N, fN, M, P;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, type, &info);
+	if (ret)
+		return ret;
+
+	ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
+	if (ret < 0)
+		return ret;
+
+	switch (info.type) {
+	case PLL_VPLL0:
+	case PLL_VPLL1:
+		nv_wr32(priv, info.reg + 0, 0x50000610);
+		nv_mask(priv, info.reg + 4, 0x003fffff,
+					    (P << 16) | (M << 8) | N);
+		nv_wr32(priv, info.reg + 8, fN);
+		break;
+	default:
+		nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+nva3_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		  struct nouveau_oclass *oclass, void *data, u32 size,
+		  struct nouveau_object **pobject)
+{
+	struct nv50_devinit_priv *priv;
+	int ret;
+
+	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.pll_set = nva3_devinit_pll_set;
+	return 0;
+}
+
+struct nouveau_oclass
+nva3_devinit_oclass = {
+	.handle = NV_SUBDEV(DEVINIT, 0xa3),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nva3_devinit_ctor,
+		.dtor = _nouveau_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nouveau_devinit_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
new file mode 100644
index 0000000..19e265b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
+{
+	struct nvc0_devinit_priv *priv = (void *)devinit;
+	struct nouveau_bios *bios = nouveau_bios(priv);
+	struct nvbios_pll info;
+	int N, fN, M, P;
+	int ret;
+
+	ret = nvbios_pll_parse(bios, type, &info);
+	if (ret)
+		return ret;
+
+	ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
+	if (ret < 0)
+		return ret;
+
+	switch (info.type) {
+	case PLL_VPLL0:
+	case PLL_VPLL1:
+	case PLL_VPLL2:
+	case PLL_VPLL3:
+		nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
+		nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
+		nv_wr32(priv, info.reg + 0x10, fN << 16);
+		break;
+	default:
+		nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+nvc0_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		  struct nouveau_oclass *oclass, void *data, u32 size,
+		  struct nouveau_object **pobject)
+{
+	struct nv50_devinit_priv *priv;
+	int ret;
+
+	ret = nouveau_devinit_create(parent, engine, oclass, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	priv->base.pll_set = nvc0_devinit_pll_set;
+	if (nv_rd32(priv, 0x022500) & 0x00000001)
+		priv->base.post = true;
+	return 0;
+}
+
+struct nouveau_oclass
+nvc0_devinit_oclass = {
+	.handle = NV_SUBDEV(DEVINIT, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_devinit_ctor,
+		.dtor = _nouveau_devinit_dtor,
+		.init = nv50_devinit_init,
+		.fini = _nouveau_devinit_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
new file mode 100644
index 0000000..7d622e2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
@@ -0,0 +1,25 @@
+#ifndef __NVKM_DEVINIT_PRIV_H__
+#define __NVKM_DEVINIT_PRIV_H__
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clock/pll.h>
+#include <subdev/devinit.h>
+
+void nv04_devinit_dtor(struct nouveau_object *);
+int  nv04_devinit_init(struct nouveau_object *);
+int  nv04_devinit_fini(struct nouveau_object *, bool);
+int  nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32);
+
+void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+
+
+struct nv50_devinit_priv {
+	struct nouveau_devinit base;
+};
+
+int  nv50_devinit_init(struct nouveau_object *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
index d62045f..821cd75 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
@@ -57,7 +57,57 @@
 }
 
 int
-nouveau_fb_preinit(struct nouveau_fb *pfb)
+_nouveau_fb_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nouveau_fb *pfb = (void *)object;
+	int ret;
+
+	ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
+	if (ret && suspend)
+		return ret;
+
+	return nouveau_subdev_fini(&pfb->base, suspend);
+}
+
+int
+_nouveau_fb_init(struct nouveau_object *object)
+{
+	struct nouveau_fb *pfb = (void *)object;
+	int ret, i;
+
+	ret = nouveau_subdev_init(&pfb->base);
+	if (ret)
+		return ret;
+
+	ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
+	if (ret)
+		return ret;
+
+	for (i = 0; i < pfb->tile.regions; i++)
+		pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
+
+	return 0;
+}
+
+void
+_nouveau_fb_dtor(struct nouveau_object *object)
+{
+	struct nouveau_fb *pfb = (void *)object;
+	int i;
+
+	for (i = 0; i < pfb->tile.regions; i++)
+		pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
+	nouveau_mm_fini(&pfb->tags);
+	nouveau_mm_fini(&pfb->vram);
+
+	nouveau_object_ref(NULL, (struct nouveau_object **)&pfb->ram);
+	nouveau_subdev_destroy(&pfb->base);
+}
+
+int
+nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine,
+		   struct nouveau_oclass *oclass, struct nouveau_oclass *ramcls,
+		   int length, void **pobject)
 {
 	static const char *name[] = {
 		[NV_MEM_TYPE_UNKNOWN] = "unknown",
@@ -72,69 +122,42 @@
 		[NV_MEM_TYPE_GDDR4  ] = "GDDR4",
 		[NV_MEM_TYPE_GDDR5  ] = "GDDR5",
 	};
-	int ret, tags;
+	struct nouveau_object *ram;
+	struct nouveau_fb *pfb;
+	int ret;
 
-	tags = pfb->ram.init(pfb);
-	if (tags < 0 || !pfb->ram.size) {
+	ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PFB", "fb",
+				     length, pobject);
+	pfb = *pobject;
+	if (ret)
+		return ret;
+
+	ret = nouveau_object_ctor(nv_object(pfb), nv_object(pfb),
+				  ramcls, NULL, 0, &ram);
+	if (ret) {
 		nv_fatal(pfb, "error detecting memory configuration!!\n");
-		return (tags < 0) ? tags : -ERANGE;
+		return ret;
 	}
 
+	atomic_dec(&ram->parent->refcount);
+	atomic_dec(&ram->engine->refcount);
+	pfb->ram = (void *)ram;
+
 	if (!nouveau_mm_initialised(&pfb->vram)) {
-		ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram.size >> 12, 1);
+		ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1);
 		if (ret)
 			return ret;
 	}
 
 	if (!nouveau_mm_initialised(&pfb->tags)) {
-		ret = nouveau_mm_init(&pfb->tags, 0, tags ? ++tags : 0, 1);
+		ret = nouveau_mm_init(&pfb->tags, 0, pfb->ram->tags ?
+				     ++pfb->ram->tags : 0, 1);
 		if (ret)
 			return ret;
 	}
 
-	nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]);
-	nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20));
-	nv_info(pfb, "   ZCOMP: %d tags\n", tags);
+	nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]);
+	nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20));
+	nv_info(pfb, "   ZCOMP: %d tags\n", pfb->ram->tags);
 	return 0;
 }
-
-void
-nouveau_fb_destroy(struct nouveau_fb *pfb)
-{
-	int i;
-
-	for (i = 0; i < pfb->tile.regions; i++)
-		pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
-	nouveau_mm_fini(&pfb->tags);
-	nouveau_mm_fini(&pfb->vram);
-
-	nouveau_subdev_destroy(&pfb->base);
-}
-
-void
-_nouveau_fb_dtor(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = (void *)object;
-	nouveau_fb_destroy(pfb);
-}
-int
-nouveau_fb_init(struct nouveau_fb *pfb)
-{
-	int ret, i;
-
-	ret = nouveau_subdev_init(&pfb->base);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < pfb->tile.regions; i++)
-		pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
-
-	return 0;
-}
-
-int
-_nouveau_fb_init(struct nouveau_object *object)
-{
-	struct nouveau_fb *pfb = (void *)object;
-	return nouveau_fb_init(pfb);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
index 6e369f8..1f103c7 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
@@ -22,24 +22,8 @@
  * Authors: Ben Skeggs
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
-#define NV04_PFB_BOOT_0						0x00100000
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT			0x00000003
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB			0x00000000
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB			0x00000001
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB			0x00000002
-#	define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB			0x00000003
-#	define NV04_PFB_BOOT_0_RAM_WIDTH_128			0x00000004
-#	define NV04_PFB_BOOT_0_RAM_TYPE				0x00000028
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT		0x00000000
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT		0x00000008
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK	0x00000010
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT		0x00000018
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT		0x00000020
-#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16		0x00000028
-#	define NV04_PFB_BOOT_0_UMA_ENABLE			0x00000100
-#	define NV04_PFB_BOOT_0_UMA_SIZE				0x0000f000
 #define NV04_PFB_CFG0						0x00100200
 
 struct nv04_fb_priv {
@@ -56,37 +40,6 @@
 }
 
 static int
-nv04_fb_vram_init(struct nouveau_fb *pfb)
-{
-	u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
-	if (boot0 & 0x00000100) {
-		pfb->ram.size  = ((boot0 >> 12) & 0xf) * 2 + 2;
-		pfb->ram.size *= 1024 * 1024;
-	} else {
-		switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
-		case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
-			pfb->ram.size = 32 * 1024 * 1024;
-			break;
-		case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
-			pfb->ram.size = 16 * 1024 * 1024;
-			break;
-		case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
-			pfb->ram.size = 8 * 1024 * 1024;
-			break;
-		case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
-			pfb->ram.size = 4 * 1024 * 1024;
-			break;
-		}
-	}
-
-	if ((boot0 & 0x00000038) <= 0x10)
-		pfb->ram.type = NV_MEM_TYPE_SGRAM;
-	else
-		pfb->ram.type = NV_MEM_TYPE_SDRAM;
-	return 0;
-}
-
-static int
 nv04_fb_init(struct nouveau_object *object)
 {
 	struct nv04_fb_priv *priv = (void *)object;
@@ -112,14 +65,13 @@
 	struct nv04_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv04_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv04_fb_vram_init;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
index edbbe26..be069b5 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
@@ -24,25 +24,12 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv10_fb_priv {
 	struct nouveau_fb base;
 };
 
-static int
-nv10_fb_vram_init(struct nouveau_fb *pfb)
-{
-	u32 cfg0 = nv_rd32(pfb, 0x100200);
-	if (cfg0 & 0x00000001)
-		pfb->ram.type = NV_MEM_TYPE_DDR1;
-	else
-		pfb->ram.type = NV_MEM_TYPE_SDRAM;
-
-	pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
-	return 0;
-}
-
 void
 nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
 		  u32 flags, struct nouveau_fb_tile *tile)
@@ -78,18 +65,17 @@
 	struct nv10_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv10_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv10_fb_vram_init;
 	priv->base.tile.regions = 8;
 	priv->base.tile.init = nv10_fb_tile_init;
 	priv->base.tile.fini = nv10_fb_tile_fini;
 	priv->base.tile.prog = nv10_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
index 4836684..57a2af0 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
@@ -24,38 +24,13 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv1a_fb_priv {
 	struct nouveau_fb base;
 };
 
 static int
-nv1a_fb_vram_init(struct nouveau_fb *pfb)
-{
-	struct pci_dev *bridge;
-	u32 mem, mib;
-
-	bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
-	if (!bridge) {
-		nv_fatal(pfb, "no bridge device\n");
-		return -ENODEV;
-	}
-
-	if (nv_device(pfb)->chipset == 0x1a) {
-		pci_read_config_dword(bridge, 0x7c, &mem);
-		mib = ((mem >> 6) & 31) + 1;
-	} else {
-		pci_read_config_dword(bridge, 0x84, &mem);
-		mib = ((mem >> 4) & 127) + 1;
-	}
-
-	pfb->ram.type = NV_MEM_TYPE_STOLEN;
-	pfb->ram.size = mib * 1024 * 1024;
-	return 0;
-}
-
-static int
 nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	     struct nouveau_oclass *oclass, void *data, u32 size,
 	     struct nouveau_object **pobject)
@@ -63,18 +38,17 @@
 	struct nv1a_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv1a_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv1a_fb_vram_init;
 	priv->base.tile.regions = 8;
 	priv->base.tile.init = nv10_fb_tile_init;
 	priv->base.tile.fini = nv10_fb_tile_fini;
 	priv->base.tile.prog = nv10_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
index 5d14612..b18c4e6 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
@@ -24,29 +24,12 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv20_fb_priv {
 	struct nouveau_fb base;
 };
 
-int
-nv20_fb_vram_init(struct nouveau_fb *pfb)
-{
-	u32 pbus1218 = nv_rd32(pfb, 0x001218);
-
-	switch (pbus1218 & 0x00000300) {
-	case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break;
-	case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
-	case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
-	case 0x00000300: pfb->ram.type = NV_MEM_TYPE_GDDR2; break;
-	}
-	pfb->ram.size  = (nv_rd32(pfb, 0x10020c) & 0xff000000);
-	pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-
-	return nv_rd32(pfb, 0x100320);
-}
-
 void
 nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
 		  u32 flags, struct nouveau_fb_tile *tile)
@@ -65,7 +48,7 @@
 		  struct nouveau_fb_tile *tile)
 {
 	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram.parts, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
 	if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
 		if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
 		else              tile->zcomp = 0x04000000; /* Z24S8 */
@@ -105,19 +88,18 @@
 	struct nv20_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv20_fb_vram_init;
 	priv->base.tile.regions = 8;
 	priv->base.tile.init = nv20_fb_tile_init;
 	priv->base.tile.comp = nv20_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv20_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
index 0042ace..32ccabf 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
@@ -24,7 +24,7 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv25_fb_priv {
 	struct nouveau_fb base;
@@ -35,7 +35,7 @@
 		  struct nouveau_fb_tile *tile)
 {
 	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram.parts, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
 	if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
 		if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
 		else              tile->zcomp = 0x00200000; /* Z24S8 */
@@ -54,19 +54,18 @@
 	struct nv25_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv20_fb_vram_init;
 	priv->base.tile.regions = 8;
 	priv->base.tile.init = nv20_fb_tile_init;
 	priv->base.tile.comp = nv25_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv20_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
index a7ba0d0..bef756d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
@@ -24,7 +24,7 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv30_fb_priv {
 	struct nouveau_fb base;
@@ -54,7 +54,7 @@
 		  struct nouveau_fb_tile *tile)
 {
 	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram.parts, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
 	if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
 		if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
 		else           tile->zcomp |= 0x02000000; /* Z24S8 */
@@ -132,19 +132,18 @@
 	struct nv30_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv20_fb_vram_init;
 	priv->base.tile.regions = 8;
 	priv->base.tile.init = nv30_fb_tile_init;
 	priv->base.tile.comp = nv30_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv20_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
index 092f6f4..097d8e3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
@@ -24,7 +24,7 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv35_fb_priv {
 	struct nouveau_fb base;
@@ -35,7 +35,7 @@
 		  struct nouveau_fb_tile *tile)
 {
 	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram.parts, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
 	if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
 		if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
 		else           tile->zcomp |= 0x08000000; /* Z24S8 */
@@ -55,19 +55,18 @@
 	struct nv35_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv20_fb_vram_init;
 	priv->base.tile.regions = 8;
 	priv->base.tile.init = nv30_fb_tile_init;
 	priv->base.tile.comp = nv35_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv20_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
index 797ab3b..9d6d9df 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
@@ -24,7 +24,7 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv36_fb_priv {
 	struct nouveau_fb base;
@@ -35,7 +35,7 @@
 		  struct nouveau_fb_tile *tile)
 {
 	u32 tiles = DIV_ROUND_UP(size, 0x40);
-	u32 tags  = round_up(tiles / pfb->ram.parts, 0x40);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x40);
 	if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
 		if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
 		else           tile->zcomp |= 0x20000000; /* Z24S8 */
@@ -55,19 +55,18 @@
 	struct nv36_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv20_fb_vram_init;
 	priv->base.tile.regions = 8;
 	priv->base.tile.init = nv30_fb_tile_init;
 	priv->base.tile.comp = nv36_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv20_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
index 65e131b..33b4393 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
@@ -24,34 +24,18 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv40_fb_priv {
 	struct nouveau_fb base;
 };
 
-static int
-nv40_fb_vram_init(struct nouveau_fb *pfb)
-{
-	u32 pbus1218 = nv_rd32(pfb, 0x001218);
-	switch (pbus1218 & 0x00000300) {
-	case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break;
-	case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
-	case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
-	case 0x00000300: pfb->ram.type = NV_MEM_TYPE_DDR2; break;
-	}
-
-	pfb->ram.size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
-	pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-	return nv_rd32(pfb, 0x100320);
-}
-
 void
 nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
 		  struct nouveau_fb_tile *tile)
 {
 	u32 tiles = DIV_ROUND_UP(size, 0x80);
-	u32 tags  = round_up(tiles / pfb->ram.parts, 0x100);
+	u32 tags  = round_up(tiles / pfb->ram->parts, 0x100);
 	if ( (flags & 2) &&
 	    !nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
 		tile->zcomp  = 0x28000000; /* Z24S8_SPLIT_GRAD */
@@ -85,19 +69,18 @@
 	struct nv40_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv40_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv40_fb_vram_init;
 	priv->base.tile.regions = 8;
 	priv->base.tile.init = nv30_fb_tile_init;
 	priv->base.tile.comp = nv40_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv20_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
index e9e5a08..02cd837 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
@@ -24,28 +24,12 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv41_fb_priv {
 	struct nouveau_fb base;
 };
 
-int
-nv41_fb_vram_init(struct nouveau_fb *pfb)
-{
-	u32 pfb474 = nv_rd32(pfb, 0x100474);
-	if (pfb474 & 0x00000004)
-		pfb->ram.type = NV_MEM_TYPE_GDDR3;
-	if (pfb474 & 0x00000002)
-		pfb->ram.type = NV_MEM_TYPE_DDR2;
-	if (pfb474 & 0x00000001)
-		pfb->ram.type = NV_MEM_TYPE_DDR1;
-
-	pfb->ram.size =   nv_rd32(pfb, 0x10020c) & 0xff000000;
-	pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-	return nv_rd32(pfb, 0x100320);
-}
-
 void
 nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
 {
@@ -78,19 +62,18 @@
 	struct nv41_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv41_fb_vram_init;
 	priv->base.tile.regions = 12;
 	priv->base.tile.init = nv30_fb_tile_init;
 	priv->base.tile.comp = nv40_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv41_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
index ae89b50..c5246c2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
@@ -24,27 +24,12 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv44_fb_priv {
 	struct nouveau_fb base;
 };
 
-int
-nv44_fb_vram_init(struct nouveau_fb *pfb)
-{
-	u32 pfb474 = nv_rd32(pfb, 0x100474);
-	if (pfb474 & 0x00000004)
-		pfb->ram.type = NV_MEM_TYPE_GDDR3;
-	if (pfb474 & 0x00000002)
-		pfb->ram.type = NV_MEM_TYPE_DDR2;
-	if (pfb474 & 0x00000001)
-		pfb->ram.type = NV_MEM_TYPE_DDR1;
-
-	pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
-	return 0;
-}
-
 static void
 nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
 		  u32 flags, struct nouveau_fb_tile *tile)
@@ -87,18 +72,17 @@
 	struct nv44_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv44_fb_vram_init;
 	priv->base.tile.regions = 12;
 	priv->base.tile.init = nv44_fb_tile_init;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv44_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
index 589b93e..e2b5790 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
@@ -24,7 +24,7 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv46_fb_priv {
 	struct nouveau_fb base;
@@ -52,18 +52,17 @@
 	struct nv46_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv44_fb_vram_init;
 	priv->base.tile.regions = 15;
 	priv->base.tile.init = nv46_fb_tile_init;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv44_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
index 818bba3..fe6a227 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
@@ -24,7 +24,7 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv47_fb_priv {
 	struct nouveau_fb base;
@@ -38,19 +38,18 @@
 	struct nv47_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv41_fb_vram_init;
 	priv->base.tile.regions = 15;
 	priv->base.tile.init = nv30_fb_tile_init;
 	priv->base.tile.comp = nv40_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv41_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
index 84a31af..5eca99b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
@@ -24,30 +24,13 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv49_fb_priv {
 	struct nouveau_fb base;
 };
 
 static int
-nv49_fb_vram_init(struct nouveau_fb *pfb)
-{
-	u32 pfb914 = nv_rd32(pfb, 0x100914);
-
-	switch (pfb914 & 0x00000003) {
-	case 0x00000000: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
-	case 0x00000001: pfb->ram.type = NV_MEM_TYPE_DDR2; break;
-	case 0x00000002: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
-	case 0x00000003: break;
-	}
-
-	pfb->ram.size =   nv_rd32(pfb, 0x10020c) & 0xff000000;
-	pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-	return nv_rd32(pfb, 0x100320);
-}
-
-static int
 nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	     struct nouveau_oclass *oclass, void *data, u32 size,
 	     struct nouveau_object **pobject)
@@ -55,20 +38,18 @@
 	struct nv49_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv49_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv49_fb_vram_init;
 	priv->base.tile.regions = 15;
 	priv->base.tile.init = nv30_fb_tile_init;
 	priv->base.tile.comp = nv40_fb_tile_comp;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv41_fb_tile_prog;
-
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
index 797fd55..1190b78 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
@@ -24,21 +24,13 @@
  *
  */
 
-#include <subdev/fb.h>
+#include "priv.h"
 
 struct nv4e_fb_priv {
 	struct nouveau_fb base;
 };
 
 static int
-nv4e_fb_vram_init(struct nouveau_fb *pfb)
-{
-	pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
-	pfb->ram.type = NV_MEM_TYPE_STOLEN;
-	return 0;
-}
-
-static int
 nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 	     struct nouveau_oclass *oclass, void *data, u32 size,
 	     struct nouveau_object **pobject)
@@ -46,18 +38,17 @@
 	struct nv4e_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv4e_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nv04_fb_memtype_valid;
-	priv->base.ram.init = nv4e_fb_vram_init;
 	priv->base.tile.regions = 12;
 	priv->base.tile.init = nv46_fb_tile_init;
 	priv->base.tile.fini = nv20_fb_tile_fini;
 	priv->base.tile.prog = nv44_fb_tile_prog;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
index 0772ec9..da614ec 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
@@ -27,7 +27,7 @@
 #include <core/engctx.h>
 #include <core/object.h>
 
-#include <subdev/fb.h>
+#include "priv.h"
 #include <subdev/bios.h>
 
 struct nv50_fb_priv {
@@ -36,7 +36,8 @@
 	dma_addr_t r100c08;
 };
 
-static int types[0x80] = {
+int
+nv50_fb_memtype[0x80] = {
 	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
 	1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
@@ -50,192 +51,7 @@
 static bool
 nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
 {
-	return types[(memtype & 0xff00) >> 8] != 0;
-}
-
-static u32
-nv50_fb_vram_rblock(struct nouveau_fb *pfb)
-{
-	int i, parts, colbits, rowbitsa, rowbitsb, banks;
-	u64 rowsize, predicted;
-	u32 r0, r4, rt, ru, rblock_size;
-
-	r0 = nv_rd32(pfb, 0x100200);
-	r4 = nv_rd32(pfb, 0x100204);
-	rt = nv_rd32(pfb, 0x100250);
-	ru = nv_rd32(pfb, 0x001540);
-	nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
-
-	for (i = 0, parts = 0; i < 8; i++) {
-		if (ru & (0x00010000 << i))
-			parts++;
-	}
-
-	colbits  =  (r4 & 0x0000f000) >> 12;
-	rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
-	rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
-	banks    = 1 << (((r4 & 0x03000000) >> 24) + 2);
-
-	rowsize = parts * banks * (1 << colbits) * 8;
-	predicted = rowsize << rowbitsa;
-	if (r0 & 0x00000004)
-		predicted += rowsize << rowbitsb;
-
-	if (predicted != pfb->ram.size) {
-		nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
-			(u32)(pfb->ram.size >> 20));
-	}
-
-	rblock_size = rowsize;
-	if (rt & 1)
-		rblock_size *= 3;
-
-	nv_debug(pfb, "rblock %d bytes\n", rblock_size);
-	return rblock_size;
-}
-
-static int
-nv50_fb_vram_init(struct nouveau_fb *pfb)
-{
-	struct nouveau_device *device = nv_device(pfb);
-	struct nouveau_bios *bios = nouveau_bios(device);
-	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
-	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
-	u32 size, tags = 0;
-	int ret;
-
-	pfb->ram.size = nv_rd32(pfb, 0x10020c);
-	pfb->ram.size = (pfb->ram.size & 0xffffff00) |
-		       ((pfb->ram.size & 0x000000ff) << 32);
-
-	size = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail;
-	switch (device->chipset) {
-	case 0xaa:
-	case 0xac:
-	case 0xaf: /* IGPs, no reordering, no real VRAM */
-		ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1);
-		if (ret)
-			return ret;
-
-		pfb->ram.type   = NV_MEM_TYPE_STOLEN;
-		pfb->ram.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
-		break;
-	default:
-		switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
-		case 0: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
-		case 1:
-			if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
-				pfb->ram.type = NV_MEM_TYPE_DDR3;
-			else
-				pfb->ram.type = NV_MEM_TYPE_DDR2;
-			break;
-		case 2: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
-		case 3: pfb->ram.type = NV_MEM_TYPE_GDDR4; break;
-		case 4: pfb->ram.type = NV_MEM_TYPE_GDDR5; break;
-		default:
-			break;
-		}
-
-		ret = nouveau_mm_init(&pfb->vram, rsvd_head, size,
-				      nv50_fb_vram_rblock(pfb) >> 12);
-		if (ret)
-			return ret;
-
-		pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
-		tags = nv_rd32(pfb, 0x100320);
-		break;
-	}
-
-	return tags;
-}
-
-static int
-nv50_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
-		 u32 memtype, struct nouveau_mem **pmem)
-{
-	struct nv50_fb_priv *priv = (void *)pfb;
-	struct nouveau_mm *heap = &priv->base.vram;
-	struct nouveau_mm *tags = &priv->base.tags;
-	struct nouveau_mm_node *r;
-	struct nouveau_mem *mem;
-	int comp = (memtype & 0x300) >> 8;
-	int type = (memtype & 0x07f);
-	int back = (memtype & 0x800);
-	int min, max, ret;
-
-	max = (size >> 12);
-	min = ncmin ? (ncmin >> 12) : max;
-	align >>= 12;
-
-	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-	if (!mem)
-		return -ENOMEM;
-
-	mutex_lock(&pfb->base.mutex);
-	if (comp) {
-		if (align == 16) {
-			int n = (max >> 4) * comp;
-
-			ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag);
-			if (ret)
-				mem->tag = NULL;
-		}
-
-		if (unlikely(!mem->tag))
-			comp = 0;
-	}
-
-	INIT_LIST_HEAD(&mem->regions);
-	mem->memtype = (comp << 7) | type;
-	mem->size = max;
-
-	type = types[type];
-	do {
-		if (back)
-			ret = nouveau_mm_tail(heap, type, max, min, align, &r);
-		else
-			ret = nouveau_mm_head(heap, type, max, min, align, &r);
-		if (ret) {
-			mutex_unlock(&pfb->base.mutex);
-			pfb->ram.put(pfb, &mem);
-			return ret;
-		}
-
-		list_add_tail(&r->rl_entry, &mem->regions);
-		max -= r->length;
-	} while (max);
-	mutex_unlock(&pfb->base.mutex);
-
-	r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
-	mem->offset = (u64)r->offset << 12;
-	*pmem = mem;
-	return 0;
-}
-
-void
-nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
-	struct nv50_fb_priv *priv = (void *)pfb;
-	struct nouveau_mm_node *this;
-	struct nouveau_mem *mem;
-
-	mem = *pmem;
-	*pmem = NULL;
-	if (unlikely(mem == NULL))
-		return;
-
-	mutex_lock(&pfb->base.mutex);
-	while (!list_empty(&mem->regions)) {
-		this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
-
-		list_del(&this->rl_entry);
-		nouveau_mm_free(&priv->base.vram, &this);
-	}
-
-	nouveau_mm_free(&priv->base.tags, &mem->tag);
-	mutex_unlock(&pfb->base.mutex);
-
-	kfree(mem);
+	return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
 }
 
 static const struct nouveau_enum vm_dispatch_subclients[] = {
@@ -432,7 +248,7 @@
 	struct nv50_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nv50_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
@@ -449,11 +265,8 @@
 	}
 
 	priv->base.memtype_valid = nv50_fb_memtype_valid;
-	priv->base.ram.init = nv50_fb_vram_init;
-	priv->base.ram.get = nv50_fb_vram_new;
-	priv->base.ram.put = nv50_fb_vram_del;
 	nv_subdev(priv)->intr = nv50_fb_intr;
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 static void
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
index 86ad592..f35d76f 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
@@ -22,9 +22,7 @@
  * Authors: Ben Skeggs
  */
 
-#include <subdev/fb.h>
-#include <subdev/ltcg.h>
-#include <subdev/bios.h>
+#include "priv.h"
 
 struct nvc0_fb_priv {
 	struct nouveau_fb base;
@@ -34,7 +32,6 @@
 
 extern const u8 nvc0_pte_storage_type_map[256];
 
-
 static bool
 nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
 {
@@ -43,137 +40,6 @@
 }
 
 static int
-nvc0_fb_vram_init(struct nouveau_fb *pfb)
-{
-	struct nouveau_bios *bios = nouveau_bios(pfb);
-	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
-	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
-	u32 parts = nv_rd32(pfb, 0x022438);
-	u32 pmask = nv_rd32(pfb, 0x022554);
-	u32 bsize = nv_rd32(pfb, 0x10f20c);
-	u32 offset, length;
-	bool uniform = true;
-	int ret, part;
-
-	nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
-	nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
-
-	pfb->ram.type = nouveau_fb_bios_memtype(bios);
-	pfb->ram.ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
-
-	/* read amount of vram attached to each memory controller */
-	for (part = 0; part < parts; part++) {
-		if (!(pmask & (1 << part))) {
-			u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
-			if (psize != bsize) {
-				if (psize < bsize)
-					bsize = psize;
-				uniform = false;
-			}
-
-			nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
-			pfb->ram.size += (u64)psize << 20;
-		}
-	}
-
-	/* if all controllers have the same amount attached, there's no holes */
-	if (uniform) {
-		offset = rsvd_head;
-		length = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail;
-		return nouveau_mm_init(&pfb->vram, offset, length, 1);
-	}
-
-	/* otherwise, address lowest common amount from 0GiB */
-	ret = nouveau_mm_init(&pfb->vram, rsvd_head, (bsize << 8) * parts, 1);
-	if (ret)
-		return ret;
-
-	/* and the rest starting from (8GiB + common_size) */
-	offset = (0x0200000000ULL >> 12) + (bsize << 8);
-	length = (pfb->ram.size >> 12) - (bsize << 8) - rsvd_tail;
-
-	ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
-	if (ret) {
-		nouveau_mm_fini(&pfb->vram);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int
-nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
-		 u32 memtype, struct nouveau_mem **pmem)
-{
-	struct nouveau_mm *mm = &pfb->vram;
-	struct nouveau_mm_node *r;
-	struct nouveau_mem *mem;
-	int type = (memtype & 0x0ff);
-	int back = (memtype & 0x800);
-	int ret;
-	const bool comp = nvc0_pte_storage_type_map[type] != type;
-
-	size  >>= 12;
-	align >>= 12;
-	ncmin >>= 12;
-	if (!ncmin)
-		ncmin = size;
-
-	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
-	if (!mem)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&mem->regions);
-	mem->size = size;
-
-	mutex_lock(&pfb->base.mutex);
-	if (comp) {
-		struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb->base.base.parent);
-
-		/* compression only works with lpages */
-		if (align == (1 << (17 - 12))) {
-			int n = size >> 5;
-			ltcg->tags_alloc(ltcg, n, &mem->tag);
-		}
-		if (unlikely(!mem->tag))
-			type = nvc0_pte_storage_type_map[type];
-	}
-	mem->memtype = type;
-
-	do {
-		if (back)
-			ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
-		else
-			ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
-		if (ret) {
-			mutex_unlock(&pfb->base.mutex);
-			pfb->ram.put(pfb, &mem);
-			return ret;
-		}
-
-		list_add_tail(&r->rl_entry, &mem->regions);
-		size -= r->length;
-	} while (size);
-	mutex_unlock(&pfb->base.mutex);
-
-	r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
-	mem->offset = (u64)r->offset << 12;
-	*pmem = mem;
-	return 0;
-}
-
-static void
-nvc0_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
-	struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb->base.base.parent);
-
-	if ((*pmem)->tag)
-		ltcg->tags_free(ltcg, &(*pmem)->tag);
-
-	nv50_fb_vram_del(pfb, pmem);
-}
-
-static int
 nvc0_fb_init(struct nouveau_object *object)
 {
 	struct nvc0_fb_priv *priv = (void *)object;
@@ -212,15 +78,12 @@
 	struct nvc0_fb_priv *priv;
 	int ret;
 
-	ret = nouveau_fb_create(parent, engine, oclass, &priv);
+	ret = nouveau_fb_create(parent, engine, oclass, &nvc0_ram_oclass, &priv);
 	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
 	priv->base.memtype_valid = nvc0_fb_memtype_valid;
-	priv->base.ram.init = nvc0_fb_vram_init;
-	priv->base.ram.get = nvc0_fb_vram_new;
-	priv->base.ram.put = nvc0_fb_vram_del;
 
 	priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
 	if (priv->r100c10_page) {
@@ -231,7 +94,7 @@
 			return -EFAULT;
 	}
 
-	return nouveau_fb_preinit(&priv->base);
+	return 0;
 }
 
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
new file mode 100644
index 0000000..6c974dd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
@@ -0,0 +1,87 @@
+#ifndef __NVKM_FB_PRIV_H__
+#define __NVKM_FB_PRIV_H__
+
+#include <subdev/fb.h>
+
+#define nouveau_ram_create(p,e,o,d)                                            \
+	nouveau_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d)
+#define nouveau_ram_destroy(p)                                                 \
+	nouveau_object_destroy(&(p)->base)
+#define nouveau_ram_init(p)                                                    \
+	nouveau_object_init(&(p)->base)
+#define nouveau_ram_fini(p,s)                                                  \
+	nouveau_object_fini(&(p)->base, (s))
+
+#define _nouveau_ram_dtor nouveau_object_destroy
+#define _nouveau_ram_init nouveau_object_init
+#define _nouveau_ram_fini nouveau_object_fini
+
+extern struct nouveau_oclass nv04_ram_oclass;
+extern struct nouveau_oclass nv10_ram_oclass;
+extern struct nouveau_oclass nv1a_ram_oclass;
+extern struct nouveau_oclass nv20_ram_oclass;
+extern struct nouveau_oclass nv40_ram_oclass;
+extern struct nouveau_oclass nv41_ram_oclass;
+extern struct nouveau_oclass nv44_ram_oclass;
+extern struct nouveau_oclass nv49_ram_oclass;
+extern struct nouveau_oclass nv4e_ram_oclass;
+extern struct nouveau_oclass nv50_ram_oclass;
+extern struct nouveau_oclass nvc0_ram_oclass;
+
+#define nouveau_fb_create(p,e,c,r,d)                                           \
+	nouveau_fb_create_((p), (e), (c), (r), sizeof(**d), (void **)d)
+#define nouveau_fb_destroy(p) ({                                               \
+	struct nouveau_fb *pfb = (p);                                          \
+	_nouveau_fb_dtor(nv_object(pfb));                                      \
+})
+#define nouveau_fb_init(p) ({                                                  \
+	struct nouveau_fb *pfb = (p);                                          \
+	_nouveau_fb_init(nv_object(pfb));                                      \
+})
+#define nouveau_fb_fini(p,s) ({                                                \
+	struct nouveau_fb *pfb = (p);                                          \
+	_nouveau_fb_fini(nv_object(pfb), (s));                                 \
+})
+
+int nouveau_fb_create_(struct nouveau_object *, struct nouveau_object *,
+		       struct nouveau_oclass *, struct nouveau_oclass *,
+		       int length, void **pobject);
+void _nouveau_fb_dtor(struct nouveau_object *);
+int  _nouveau_fb_init(struct nouveau_object *);
+int  _nouveau_fb_fini(struct nouveau_object *, bool);
+
+struct nouveau_bios;
+int  nouveau_fb_bios_memtype(struct nouveau_bios *);
+
+bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
+
+void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
+void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
+void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+int  nv30_fb_init(struct nouveau_object *);
+void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
+
+void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
+		       struct nouveau_fb_tile *);
+
+int  nv41_fb_init(struct nouveau_object *);
+void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+int  nv44_fb_init(struct nouveau_object *);
+void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+		       u32 pitch, u32 flags, struct nouveau_fb_tile *);
+
+void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+extern int nv50_fb_memtype[0x80];
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
new file mode 100644
index 0000000..e781080
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NV04_PFB_BOOT_0						0x00100000
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT			0x00000003
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB			0x00000000
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB			0x00000001
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB			0x00000002
+#	define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB			0x00000003
+#	define NV04_PFB_BOOT_0_RAM_WIDTH_128			0x00000004
+#	define NV04_PFB_BOOT_0_RAM_TYPE				0x00000028
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT		0x00000000
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT		0x00000008
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK	0x00000010
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT		0x00000018
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT		0x00000020
+#	define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16		0x00000028
+#	define NV04_PFB_BOOT_0_UMA_ENABLE			0x00000100
+#	define NV04_PFB_BOOT_0_UMA_SIZE				0x0000f000
+
+#include "priv.h"
+
+static int
+nv04_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (boot0 & 0x00000100) {
+		ram->size  = ((boot0 >> 12) & 0xf) * 2 + 2;
+		ram->size *= 1024 * 1024;
+	} else {
+		switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
+			ram->size = 32 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
+			ram->size = 16 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
+			ram->size = 8 * 1024 * 1024;
+			break;
+		case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
+			ram->size = 4 * 1024 * 1024;
+			break;
+		}
+	}
+
+	if ((boot0 & 0x00000038) <= 0x10)
+		ram->type = NV_MEM_TYPE_SGRAM;
+	else
+		ram->type = NV_MEM_TYPE_SDRAM;
+	return 0;
+}
+
+struct nouveau_oclass
+nv04_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
new file mode 100644
index 0000000..8311f37
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv10_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	u32 cfg0 = nv_rd32(pfb, 0x100200);
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (cfg0 & 0x00000001)
+		ram->type = NV_MEM_TYPE_DDR1;
+	else
+		ram->type = NV_MEM_TYPE_SDRAM;
+
+	ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+	return 0;
+}
+
+
+struct nouveau_oclass
+nv10_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv10_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
new file mode 100644
index 0000000..d0caddf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv1a_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	struct pci_dev *bridge;
+	u32 mem, mib;
+	int ret;
+
+	bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
+	if (!bridge) {
+		nv_fatal(pfb, "no bridge device\n");
+		return -ENODEV;
+	}
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (nv_device(pfb)->chipset == 0x1a) {
+		pci_read_config_dword(bridge, 0x7c, &mem);
+		mib = ((mem >> 6) & 31) + 1;
+	} else {
+		pci_read_config_dword(bridge, 0x84, &mem);
+		mib = ((mem >> 4) & 127) + 1;
+	}
+
+	ram->type = NV_MEM_TYPE_STOLEN;
+	ram->size = mib * 1024 * 1024;
+	return 0;
+}
+
+struct nouveau_oclass
+nv1a_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv1a_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
new file mode 100644
index 0000000..fdc11bb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv20_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	u32 pbus1218 = nv_rd32(pfb, 0x001218);
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	switch (pbus1218 & 0x00000300) {
+	case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
+	case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
+	case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
+	case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break;
+	}
+	ram->size  = (nv_rd32(pfb, 0x10020c) & 0xff000000);
+	ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	ram->tags  = nv_rd32(pfb, 0x100320);
+	return 0;
+}
+
+struct nouveau_oclass
+nv20_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv20_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
new file mode 100644
index 0000000..ee49ac4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	u32 pbus1218 = nv_rd32(pfb, 0x001218);
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	switch (pbus1218 & 0x00000300) {
+	case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
+	case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
+	case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
+	case 0x00000300: ram->type = NV_MEM_TYPE_DDR2; break;
+	}
+
+	ram->size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	ram->tags  =  nv_rd32(pfb, 0x100320);
+	return 0;
+}
+
+
+struct nouveau_oclass
+nv40_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv40_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
new file mode 100644
index 0000000..1dab7e1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	u32 pfb474 = nv_rd32(pfb, 0x100474);
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (pfb474 & 0x00000004)
+		ram->type = NV_MEM_TYPE_GDDR3;
+	if (pfb474 & 0x00000002)
+		ram->type = NV_MEM_TYPE_DDR2;
+	if (pfb474 & 0x00000001)
+		ram->type = NV_MEM_TYPE_DDR1;
+
+	ram->size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+	ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	ram->tags  =  nv_rd32(pfb, 0x100320);
+	return 0;
+}
+
+struct nouveau_oclass
+nv41_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv41_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
new file mode 100644
index 0000000..25fff84
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	u32 pfb474 = nv_rd32(pfb, 0x100474);
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	if (pfb474 & 0x00000004)
+		ram->type = NV_MEM_TYPE_GDDR3;
+	if (pfb474 & 0x00000002)
+		ram->type = NV_MEM_TYPE_DDR2;
+	if (pfb474 & 0x00000001)
+		ram->type = NV_MEM_TYPE_DDR1;
+
+	ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+	return 0;
+}
+
+struct nouveau_oclass
+nv44_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv44_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
new file mode 100644
index 0000000..19e3a9a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	u32 pfb914 = nv_rd32(pfb, 0x100914);
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	switch (pfb914 & 0x00000003) {
+	case 0x00000000: pfb->ram->type = NV_MEM_TYPE_DDR1; break;
+	case 0x00000001: pfb->ram->type = NV_MEM_TYPE_DDR2; break;
+	case 0x00000002: pfb->ram->type = NV_MEM_TYPE_GDDR3; break;
+	case 0x00000003: break;
+	}
+
+	pfb->ram->size  =  nv_rd32(pfb, 0x10020c) & 0xff000000;
+	pfb->ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+	pfb->ram->tags  =  nv_rd32(pfb, 0x100320);
+	return 0;
+}
+
+struct nouveau_oclass
+nv49_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv49_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
new file mode 100644
index 0000000..7192aa6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv4e_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_ram *ram;
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+	pfb->ram->type = NV_MEM_TYPE_STOLEN;
+	return 0;
+}
+
+struct nouveau_oclass
+nv4e_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv4e_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
new file mode 100644
index 0000000..af5aa7e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <core/mm.h>
+#include "priv.h"
+
+void
+nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+	struct nouveau_mm_node *this;
+	struct nouveau_mem *mem;
+
+	mem = *pmem;
+	*pmem = NULL;
+	if (unlikely(mem == NULL))
+		return;
+
+	mutex_lock(&pfb->base.mutex);
+	while (!list_empty(&mem->regions)) {
+		this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
+
+		list_del(&this->rl_entry);
+		nouveau_mm_free(&pfb->vram, &this);
+	}
+
+	nouveau_mm_free(&pfb->tags, &mem->tag);
+	mutex_unlock(&pfb->base.mutex);
+
+	kfree(mem);
+}
+
+static int
+nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
+	     u32 memtype, struct nouveau_mem **pmem)
+{
+	struct nouveau_mm *heap = &pfb->vram;
+	struct nouveau_mm *tags = &pfb->tags;
+	struct nouveau_mm_node *r;
+	struct nouveau_mem *mem;
+	int comp = (memtype & 0x300) >> 8;
+	int type = (memtype & 0x07f);
+	int back = (memtype & 0x800);
+	int min, max, ret;
+
+	max = (size >> 12);
+	min = ncmin ? (ncmin >> 12) : max;
+	align >>= 12;
+
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	mutex_lock(&pfb->base.mutex);
+	if (comp) {
+		if (align == 16) {
+			int n = (max >> 4) * comp;
+
+			ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag);
+			if (ret)
+				mem->tag = NULL;
+		}
+
+		if (unlikely(!mem->tag))
+			comp = 0;
+	}
+
+	INIT_LIST_HEAD(&mem->regions);
+	mem->memtype = (comp << 7) | type;
+	mem->size = max;
+
+	type = nv50_fb_memtype[type];
+	do {
+		if (back)
+			ret = nouveau_mm_tail(heap, type, max, min, align, &r);
+		else
+			ret = nouveau_mm_head(heap, type, max, min, align, &r);
+		if (ret) {
+			mutex_unlock(&pfb->base.mutex);
+			pfb->ram->put(pfb, &mem);
+			return ret;
+		}
+
+		list_add_tail(&r->rl_entry, &mem->regions);
+		max -= r->length;
+	} while (max);
+	mutex_unlock(&pfb->base.mutex);
+
+	r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
+	mem->offset = (u64)r->offset << 12;
+	*pmem = mem;
+	return 0;
+}
+
+static u32
+nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram)
+{
+	int i, parts, colbits, rowbitsa, rowbitsb, banks;
+	u64 rowsize, predicted;
+	u32 r0, r4, rt, ru, rblock_size;
+
+	r0 = nv_rd32(pfb, 0x100200);
+	r4 = nv_rd32(pfb, 0x100204);
+	rt = nv_rd32(pfb, 0x100250);
+	ru = nv_rd32(pfb, 0x001540);
+	nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
+
+	for (i = 0, parts = 0; i < 8; i++) {
+		if (ru & (0x00010000 << i))
+			parts++;
+	}
+
+	colbits  =  (r4 & 0x0000f000) >> 12;
+	rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+	rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+	banks    = 1 << (((r4 & 0x03000000) >> 24) + 2);
+
+	rowsize = parts * banks * (1 << colbits) * 8;
+	predicted = rowsize << rowbitsa;
+	if (r0 & 0x00000004)
+		predicted += rowsize << rowbitsb;
+
+	if (predicted != ram->size) {
+		nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
+			(u32)(ram->size >> 20));
+	}
+
+	rblock_size = rowsize;
+	if (rt & 1)
+		rblock_size *= 3;
+
+	nv_debug(pfb, "rblock %d bytes\n", rblock_size);
+	return rblock_size;
+}
+
+static int
+nv50_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 datasize,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_device *device = nv_device(pfb);
+	struct nouveau_bios *bios = nouveau_bios(device);
+	struct nouveau_ram *ram;
+	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+	u32 size;
+	int ret;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	ram->size = nv_rd32(pfb, 0x10020c);
+	ram->size = (ram->size & 0xffffff00) |
+		       ((ram->size & 0x000000ff) << 32);
+
+	size = (ram->size >> 12) - rsvd_head - rsvd_tail;
+	switch (device->chipset) {
+	case 0xaa:
+	case 0xac:
+	case 0xaf: /* IGPs, no reordering, no real VRAM */
+		ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1);
+		if (ret)
+			return ret;
+
+		ram->type   = NV_MEM_TYPE_STOLEN;
+		ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
+		break;
+	default:
+		switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
+		case 0: ram->type = NV_MEM_TYPE_DDR1; break;
+		case 1:
+			if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
+				ram->type = NV_MEM_TYPE_DDR3;
+			else
+				ram->type = NV_MEM_TYPE_DDR2;
+			break;
+		case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
+		case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
+		case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
+		default:
+			break;
+		}
+
+		ret = nouveau_mm_init(&pfb->vram, rsvd_head, size,
+				      nv50_fb_vram_rblock(pfb, ram) >> 12);
+		if (ret)
+			return ret;
+
+		ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+		ram->tags  =  nv_rd32(pfb, 0x100320);
+		break;
+	}
+
+	ram->get = nv50_ram_get;
+	ram->put = nv50_ram_put;
+	return 0;
+}
+
+struct nouveau_oclass
+nv50_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
new file mode 100644
index 0000000..9c3634a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/ltcg.h>
+
+#include "priv.h"
+
+extern const u8 nvc0_pte_storage_type_map[256];
+
+void
+nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+	struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+
+	if ((*pmem)->tag)
+		ltcg->tags_free(ltcg, &(*pmem)->tag);
+
+	nv50_ram_put(pfb, pmem);
+}
+
+int
+nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
+	     u32 memtype, struct nouveau_mem **pmem)
+{
+	struct nouveau_mm *mm = &pfb->vram;
+	struct nouveau_mm_node *r;
+	struct nouveau_mem *mem;
+	int type = (memtype & 0x0ff);
+	int back = (memtype & 0x800);
+	const bool comp = nvc0_pte_storage_type_map[type] != type;
+	int ret;
+
+	size  >>= 12;
+	align >>= 12;
+	ncmin >>= 12;
+	if (!ncmin)
+		ncmin = size;
+
+	mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+	if (!mem)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&mem->regions);
+	mem->size = size;
+
+	mutex_lock(&pfb->base.mutex);
+	if (comp) {
+		struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+
+		/* compression only works with lpages */
+		if (align == (1 << (17 - 12))) {
+			int n = size >> 5;
+			ltcg->tags_alloc(ltcg, n, &mem->tag);
+		}
+
+		if (unlikely(!mem->tag))
+			type = nvc0_pte_storage_type_map[type];
+	}
+	mem->memtype = type;
+
+	do {
+		if (back)
+			ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
+		else
+			ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
+		if (ret) {
+			mutex_unlock(&pfb->base.mutex);
+			pfb->ram->put(pfb, &mem);
+			return ret;
+		}
+
+		list_add_tail(&r->rl_entry, &mem->regions);
+		size -= r->length;
+	} while (size);
+	mutex_unlock(&pfb->base.mutex);
+
+	r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
+	mem->offset = (u64)r->offset << 12;
+	*pmem = mem;
+	return 0;
+}
+
+static int
+nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nouveau_fb *pfb = nouveau_fb(parent);
+	struct nouveau_bios *bios = nouveau_bios(pfb);
+	struct nouveau_ram *ram;
+	const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+	const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+	u32 parts = nv_rd32(pfb, 0x022438);
+	u32 pmask = nv_rd32(pfb, 0x022554);
+	u32 bsize = nv_rd32(pfb, 0x10f20c);
+	u32 offset, length;
+	bool uniform = true;
+	int ret, part;
+
+	ret = nouveau_ram_create(parent, engine, oclass, &ram);
+	*pobject = nv_object(ram);
+	if (ret)
+		return ret;
+
+	nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
+	nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
+
+	ram->type = nouveau_fb_bios_memtype(bios);
+	ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
+
+	/* read amount of vram attached to each memory controller */
+	for (part = 0; part < parts; part++) {
+		if (!(pmask & (1 << part))) {
+			u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
+			if (psize != bsize) {
+				if (psize < bsize)
+					bsize = psize;
+				uniform = false;
+			}
+
+			nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
+			ram->size += (u64)psize << 20;
+		}
+	}
+
+	/* if all controllers have the same amount attached, there's no holes */
+	if (uniform) {
+		offset = rsvd_head;
+		length = (ram->size >> 12) - rsvd_head - rsvd_tail;
+		ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
+	} else {
+		/* otherwise, address lowest common amount from 0GiB */
+		ret = nouveau_mm_init(&pfb->vram, rsvd_head,
+				      (bsize << 8) * parts, 1);
+		if (ret)
+			return ret;
+
+		/* and the rest starting from (8GiB + common_size) */
+		offset = (0x0200000000ULL >> 12) + (bsize << 8);
+		length = (ram->size >> 12) - (bsize << 8) - rsvd_tail;
+
+		ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
+		if (ret)
+			nouveau_mm_fini(&pfb->vram);
+	}
+
+	if (ret)
+		return ret;
+
+	ram->get = nvc0_ram_get;
+	ram->put = nvc0_ram_put;
+	return 0;
+}
+
+struct nouveau_oclass
+nvc0_ram_oclass = {
+	.handle = 0,
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_ram_create,
+		.dtor = _nouveau_ram_dtor,
+		.init = _nouveau_ram_init,
+		.fini = _nouveau_ram_fini,
+	}
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
index cfc7e31..97bc5df 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
@@ -56,7 +56,7 @@
 	if (ret)
 		return ret;
 
-	ret = pfb->ram.get(pfb, size, align, 0, 0x800, &node->mem);
+	ret = pfb->ram->get(pfb, size, align, 0, 0x800, &node->mem);
 	if (ret)
 		return ret;
 
@@ -71,7 +71,7 @@
 {
 	struct nv50_instobj_priv *node = (void *)object;
 	struct nouveau_fb *pfb = nouveau_fb(object);
-	pfb->ram.put(pfb, &node->mem);
+	pfb->ram->put(pfb, &node->mem);
 	nouveau_instobj_destroy(&node->base);
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
index fb794e9..bcca883 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
@@ -122,7 +122,7 @@
 		nv_wr32(priv, 0x17e000, priv->part_nr);
 
 	/* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
-	priv->num_tags = (pfb->ram.size >> 17) / 4;
+	priv->num_tags = (pfb->ram->size >> 17) / 4;
 	if (priv->num_tags > (1 << 17))
 		priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
 	priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
index d796924..0cb322a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
@@ -35,6 +35,7 @@
 	{ 0x00001000, NVDEV_ENGINE_GR },
 	{ 0x00004000, NVDEV_ENGINE_CRYPT },	/* NV84- */
 	{ 0x00008000, NVDEV_ENGINE_BSP },	/* NV84- */
+	{ 0x00020000, NVDEV_ENGINE_VP },	/* NV84- */
 	{ 0x00100000, NVDEV_SUBDEV_TIMER },
 	{ 0x00200000, NVDEV_SUBDEV_GPIO },
 	{ 0x04000000, NVDEV_ENGINE_DISP },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
index 737bd4b..c5da3ba 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
@@ -33,6 +33,7 @@
 	{ 0x00000001, NVDEV_ENGINE_PPP },
 	{ 0x00000020, NVDEV_ENGINE_COPY0 },
 	{ 0x00000040, NVDEV_ENGINE_COPY1 },
+	{ 0x00000080, NVDEV_ENGINE_COPY2 },
 	{ 0x00000100, NVDEV_ENGINE_FIFO },
 	{ 0x00001000, NVDEV_ENGINE_GR },
 	{ 0x00008000, NVDEV_ENGINE_BSP },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
index 77c67fc..67fcb6c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
@@ -236,9 +236,9 @@
 			vmm->map_pgt(vpgd->obj, pde, vpgt->obj);
 		}
 
-		mutex_unlock(&vm->mm.mutex);
+		mutex_unlock(&nv_subdev(vmm)->mutex);
 		nouveau_gpuobj_ref(NULL, &pgt);
-		mutex_lock(&vm->mm.mutex);
+		mutex_lock(&nv_subdev(vmm)->mutex);
 	}
 }
 
@@ -256,18 +256,18 @@
 	pgt_size  = (1 << (vmm->pgt_bits + 12)) >> type;
 	pgt_size *= 8;
 
-	mutex_unlock(&vm->mm.mutex);
+	mutex_unlock(&nv_subdev(vmm)->mutex);
 	ret = nouveau_gpuobj_new(nv_object(vm->vmm), NULL, pgt_size, 0x1000,
 				 NVOBJ_FLAG_ZERO_ALLOC, &pgt);
-	mutex_lock(&vm->mm.mutex);
+	mutex_lock(&nv_subdev(vmm)->mutex);
 	if (unlikely(ret))
 		return ret;
 
 	/* someone beat us to filling the PDE while we didn't have the lock */
 	if (unlikely(vpgt->refcount[big]++)) {
-		mutex_unlock(&vm->mm.mutex);
+		mutex_unlock(&nv_subdev(vmm)->mutex);
 		nouveau_gpuobj_ref(NULL, &pgt);
-		mutex_lock(&vm->mm.mutex);
+		mutex_lock(&nv_subdev(vmm)->mutex);
 		return 0;
 	}
 
@@ -289,11 +289,11 @@
 	u32 fpde, lpde, pde;
 	int ret;
 
-	mutex_lock(&vm->mm.mutex);
+	mutex_lock(&nv_subdev(vmm)->mutex);
 	ret = nouveau_mm_head(&vm->mm, page_shift, msize, msize, align,
 			     &vma->node);
 	if (unlikely(ret != 0)) {
-		mutex_unlock(&vm->mm.mutex);
+		mutex_unlock(&nv_subdev(vmm)->mutex);
 		return ret;
 	}
 
@@ -314,13 +314,14 @@
 			if (pde != fpde)
 				nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1);
 			nouveau_mm_free(&vm->mm, &vma->node);
-			mutex_unlock(&vm->mm.mutex);
+			mutex_unlock(&nv_subdev(vmm)->mutex);
 			return ret;
 		}
 	}
-	mutex_unlock(&vm->mm.mutex);
+	mutex_unlock(&nv_subdev(vmm)->mutex);
 
-	vma->vm     = vm;
+	vma->vm = NULL;
+	nouveau_vm_ref(vm, &vma->vm, NULL);
 	vma->offset = (u64)vma->node->offset << 12;
 	vma->access = access;
 	return 0;
@@ -338,10 +339,12 @@
 	fpde = (vma->node->offset >> vmm->pgt_bits);
 	lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
 
-	mutex_lock(&vm->mm.mutex);
+	mutex_lock(&nv_subdev(vmm)->mutex);
 	nouveau_vm_unmap_pgt(vm, vma->node->type != vmm->spg_shift, fpde, lpde);
 	nouveau_mm_free(&vm->mm, &vma->node);
-	mutex_unlock(&vm->mm.mutex);
+	mutex_unlock(&nv_subdev(vmm)->mutex);
+
+	nouveau_vm_ref(NULL, &vma->vm, NULL);
 }
 
 int
@@ -362,7 +365,7 @@
 	vm->fpde = offset >> (vmm->pgt_bits + 12);
 	vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
 
-	vm->pgt  = kcalloc(vm->lpde - vm->fpde + 1, sizeof(*vm->pgt), GFP_KERNEL);
+	vm->pgt  = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt));
 	if (!vm->pgt) {
 		kfree(vm);
 		return -ENOMEM;
@@ -371,7 +374,7 @@
 	ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12,
 			      block >> 12);
 	if (ret) {
-		kfree(vm->pgt);
+		vfree(vm->pgt);
 		kfree(vm);
 		return ret;
 	}
@@ -405,24 +408,25 @@
 
 	nouveau_gpuobj_ref(pgd, &vpgd->obj);
 
-	mutex_lock(&vm->mm.mutex);
+	mutex_lock(&nv_subdev(vmm)->mutex);
 	for (i = vm->fpde; i <= vm->lpde; i++)
 		vmm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
 	list_add(&vpgd->head, &vm->pgd_list);
-	mutex_unlock(&vm->mm.mutex);
+	mutex_unlock(&nv_subdev(vmm)->mutex);
 	return 0;
 }
 
 static void
 nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
 {
+	struct nouveau_vmmgr *vmm = vm->vmm;
 	struct nouveau_vm_pgd *vpgd, *tmp;
 	struct nouveau_gpuobj *pgd = NULL;
 
 	if (!mpgd)
 		return;
 
-	mutex_lock(&vm->mm.mutex);
+	mutex_lock(&nv_subdev(vmm)->mutex);
 	list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
 		if (vpgd->obj == mpgd) {
 			pgd = vpgd->obj;
@@ -431,7 +435,7 @@
 			break;
 		}
 	}
-	mutex_unlock(&vm->mm.mutex);
+	mutex_unlock(&nv_subdev(vmm)->mutex);
 
 	nouveau_gpuobj_ref(NULL, &pgd);
 }
@@ -446,7 +450,7 @@
 	}
 
 	nouveau_mm_fini(&vm->mm);
-	kfree(vm->pgt);
+	vfree(vm->pgt);
 	kfree(vm);
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
index e067f81..07dd1fe 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
@@ -27,11 +27,11 @@
 
 #include <subdev/timer.h>
 #include <subdev/fb.h>
+#include <subdev/bar.h>
 #include <subdev/vm.h>
 
 struct nv50_vmmgr_priv {
 	struct nouveau_vmmgr base;
-	spinlock_t lock;
 };
 
 static void
@@ -86,8 +86,8 @@
 
 	/* IGPs don't have real VRAM, re-target to stolen system memory */
 	target = 0;
-	if (nouveau_fb(vma->vm->vmm)->ram.stolen) {
-		phys += nouveau_fb(vma->vm->vmm)->ram.stolen;
+	if (nouveau_fb(vma->vm->vmm)->ram->stolen) {
+		phys += nouveau_fb(vma->vm->vmm)->ram->stolen;
 		target = 3;
 	}
 
@@ -151,29 +151,42 @@
 static void
 nv50_vm_flush(struct nouveau_vm *vm)
 {
+	struct nv50_vmmgr_priv *priv = (void *)vm->vmm;
+	struct nouveau_bar *bar = nouveau_bar(priv);
 	struct nouveau_engine *engine;
-	int i;
+	int i, vme;
 
+	bar->flush(bar);
+
+	mutex_lock(&nv_subdev(priv)->mutex);
 	for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
-		if (atomic_read(&vm->engref[i])) {
-			engine = nouveau_engine(vm->vmm, i);
-			if (engine && engine->tlb_flush)
-				engine->tlb_flush(engine);
+		if (!atomic_read(&vm->engref[i]))
+			continue;
+
+		/* unfortunate hw bug workaround... */
+		engine = nouveau_engine(priv, i);
+		if (engine && engine->tlb_flush) {
+			engine->tlb_flush(engine);
+			continue;
 		}
+
+		switch (i) {
+		case NVDEV_ENGINE_GR   : vme = 0x00; break;
+		case NVDEV_ENGINE_VP   : vme = 0x01; break;
+		case NVDEV_SUBDEV_BAR  : vme = 0x06; break;
+		case NVDEV_ENGINE_MPEG : vme = 0x08; break;
+		case NVDEV_ENGINE_BSP  : vme = 0x09; break;
+		case NVDEV_ENGINE_CRYPT: vme = 0x0a; break;
+		case NVDEV_ENGINE_COPY0: vme = 0x0d; break;
+		default:
+			continue;
+		}
+
+		nv_wr32(priv, 0x100c80, (vme << 16) | 1);
+		if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
+			nv_error(priv, "vm flush timeout: engine %d\n", vme);
 	}
-}
-
-void
-nv50_vm_flush_engine(struct nouveau_subdev *subdev, int engine)
-{
-	struct nv50_vmmgr_priv *priv = (void *)nouveau_vmmgr(subdev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&priv->lock, flags);
-	nv_wr32(subdev, 0x100c80, (engine << 16) | 1);
-	if (!nv_wait(subdev, 0x100c80, 0x00000001, 0x00000000))
-		nv_error(subdev, "vm flush timeout: engine %d\n", engine);
-	spin_unlock_irqrestore(&priv->lock, flags);
+	mutex_unlock(&nv_subdev(priv)->mutex);
 }
 
 static int
@@ -211,7 +224,6 @@
 	priv->base.map_sg = nv50_vm_map_sg;
 	priv->base.unmap = nv50_vm_unmap;
 	priv->base.flush = nv50_vm_flush;
-	spin_lock_init(&priv->lock);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
index 4c3b0a2..668cf96 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
@@ -29,10 +29,10 @@
 #include <subdev/fb.h>
 #include <subdev/vm.h>
 #include <subdev/ltcg.h>
+#include <subdev/bar.h>
 
 struct nvc0_vmmgr_priv {
 	struct nouveau_vmmgr base;
-	spinlock_t lock;
 };
 
 
@@ -160,40 +160,40 @@
 	}
 }
 
-void
-nvc0_vm_flush_engine(struct nouveau_subdev *subdev, u64 addr, int type)
-{
-	struct nvc0_vmmgr_priv *priv = (void *)nouveau_vmmgr(subdev);
-	unsigned long flags;
-
-	/* looks like maybe a "free flush slots" counter, the
-	 * faster you write to 0x100cbc to more it decreases
-	 */
-	spin_lock_irqsave(&priv->lock, flags);
-	if (!nv_wait_ne(subdev, 0x100c80, 0x00ff0000, 0x00000000)) {
-		nv_error(subdev, "vm timeout 0: 0x%08x %d\n",
-			 nv_rd32(subdev, 0x100c80), type);
-	}
-
-	nv_wr32(subdev, 0x100cb8, addr >> 8);
-	nv_wr32(subdev, 0x100cbc, 0x80000000 | type);
-
-	/* wait for flush to be queued? */
-	if (!nv_wait(subdev, 0x100c80, 0x00008000, 0x00008000)) {
-		nv_error(subdev, "vm timeout 1: 0x%08x %d\n",
-			 nv_rd32(subdev, 0x100c80), type);
-	}
-	spin_unlock_irqrestore(&priv->lock, flags);
-}
-
 static void
 nvc0_vm_flush(struct nouveau_vm *vm)
 {
+	struct nvc0_vmmgr_priv *priv = (void *)vm->vmm;
+	struct nouveau_bar *bar = nouveau_bar(priv);
 	struct nouveau_vm_pgd *vpgd;
+	u32 type;
 
+	bar->flush(bar);
+
+	type = 0x00000001; /* PAGE_ALL */
+	if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR]))
+		type |= 0x00000004; /* HUB_ONLY */
+
+	mutex_lock(&nv_subdev(priv)->mutex);
 	list_for_each_entry(vpgd, &vm->pgd_list, head) {
-		nvc0_vm_flush_engine(nv_subdev(vm->vmm), vpgd->obj->addr, 1);
+		/* looks like maybe a "free flush slots" counter, the
+		 * faster you write to 0x100cbc to more it decreases
+		 */
+		if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) {
+			nv_error(priv, "vm timeout 0: 0x%08x %d\n",
+				 nv_rd32(priv, 0x100c80), type);
+		}
+
+		nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8);
+		nv_wr32(priv, 0x100cbc, 0x80000000 | type);
+
+		/* wait for flush to be queued? */
+		if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) {
+			nv_error(priv, "vm timeout 1: 0x%08x %d\n",
+				 nv_rd32(priv, 0x100c80), type);
+		}
 	}
+	mutex_unlock(&nv_subdev(priv)->mutex);
 }
 
 static int
@@ -227,7 +227,6 @@
 	priv->base.map_sg = nvc0_vm_map_sg;
 	priv->base.unmap = nvc0_vm_unmap;
 	priv->base.flush = nvc0_vm_flush;
-	spin_lock_init(&priv->lock);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 6aa2137..3e72876 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -1878,9 +1878,6 @@
 	if (dcb->version < 0x21)
 		merge_like_dcb_entries(dev, dcb);
 
-	if (!dcb->entries)
-		return -ENXIO;
-
 	/* dump connector table entries to log, if any exist */
 	idx = -1;
 	while ((conn = olddcb_conn(dev, ++idx))) {
@@ -2054,19 +2051,14 @@
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	unsigned htotal;
 
-	if (nv_device(drm->device)->card_type >= NV_50) {
-		if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
-		    NVReadVgaCrtc(dev, 0, 0x1a) == 0)
-			return false;
+	if (nv_device(drm->device)->card_type >= NV_50)
 		return true;
-	}
 
 	htotal  = NVReadVgaCrtc(dev, 0, 0x06);
 	htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8;
 	htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4;
 	htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10;
 	htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11;
-
 	return (htotal != 0);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 7ff1071..4e7ee5f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -148,6 +148,7 @@
 
 	if (unlikely(nvbo->gem))
 		DRM_ERROR("bo %p still attached to GEM object\n", bo);
+	WARN_ON(nvbo->pin_refcnt > 0);
 	nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
 	kfree(nvbo);
 }
@@ -197,6 +198,12 @@
 	size_t acc_size;
 	int ret;
 	int type = ttm_bo_type_device;
+	int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1);
+
+	if (size <= 0 || size > max_size) {
+		nv_warn(drm, "skipped size %x\n", (u32)size);
+		return -EINVAL;
+	}
 
 	if (sg)
 		type = ttm_bo_type_sg;
@@ -255,7 +262,7 @@
 {
 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
 	struct nouveau_fb *pfb = nouveau_fb(drm->device);
-	u32 vram_pages = pfb->ram.size >> PAGE_SHIFT;
+	u32 vram_pages = pfb->ram->size >> PAGE_SHIFT;
 
 	if (nv_device(drm->device)->card_type == NV_10 &&
 	    nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
@@ -340,13 +347,15 @@
 {
 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
 	struct ttm_buffer_object *bo = &nvbo->bo;
-	int ret;
+	int ret, ref;
 
 	ret = ttm_bo_reserve(bo, false, false, false, 0);
 	if (ret)
 		return ret;
 
-	if (--nvbo->pin_refcnt)
+	ref = --nvbo->pin_refcnt;
+	WARN_ON_ONCE(ref < 0);
+	if (ref)
 		goto out;
 
 	nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
@@ -578,7 +587,7 @@
 	int ret = RING_SPACE(chan, 2);
 	if (ret == 0) {
 		BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1);
-		OUT_RING  (chan, handle);
+		OUT_RING  (chan, handle & 0x0000ffff);
 		FIRE_RING (chan);
 	}
 	return ret;
@@ -968,12 +977,12 @@
 		     bool no_wait_gpu, struct ttm_mem_reg *new_mem)
 {
 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
-	struct nouveau_channel *chan = chan = drm->channel;
+	struct nouveau_channel *chan = chan = drm->ttm.chan;
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct ttm_mem_reg *old_mem = &bo->mem;
 	int ret;
 
-	mutex_lock(&chan->cli->mutex);
+	mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING);
 
 	/* create temporary vmas for the transfer and attach them to the
 	 * old nouveau_mem node, these will get cleaned up after ttm has
@@ -1014,7 +1023,7 @@
 			    struct ttm_mem_reg *, struct ttm_mem_reg *);
 		int (*init)(struct nouveau_channel *, u32 handle);
 	} _methods[] = {
-		{  "COPY", 0, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
+		{  "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
 		{  "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
 		{ "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
 		{ "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init },
@@ -1034,7 +1043,7 @@
 		struct nouveau_channel *chan;
 		u32 handle = (mthd->engine << 16) | mthd->oclass;
 
-		if (mthd->init == nve0_bo_move_init)
+		if (mthd->engine)
 			chan = drm->cechan;
 		else
 			chan = drm->channel;
@@ -1052,6 +1061,7 @@
 			}
 
 			drm->ttm.move = mthd->exec;
+			drm->ttm.chan = chan;
 			name = mthd->name;
 			break;
 		}
@@ -1550,13 +1560,8 @@
 nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
 {
 	if (vma->node) {
-		if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM) {
-			spin_lock(&nvbo->bo.bdev->fence_lock);
-			ttm_bo_wait(&nvbo->bo, false, false, false);
-			spin_unlock(&nvbo->bo.bdev->fence_lock);
+		if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM)
 			nouveau_vm_unmap(vma);
-		}
-
 		nouveau_vm_put(vma);
 		list_del(&vma->head);
 	}
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index eaa80a2..e84f4c3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -147,7 +147,7 @@
 		args.limit = client->vm->vmm->limit - 1;
 	} else
 	if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
-		u64 limit = pfb->ram.size - imem->reserved - 1;
+		u64 limit = pfb->ram->size - imem->reserved - 1;
 		if (device->card_type == NV_04) {
 			/* nv04 vram pushbuf hack, retarget to its location in
 			 * the framebuffer bar rather than direct vram access..
@@ -282,7 +282,7 @@
 		} else {
 			args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR;
 			args.start = 0;
-			args.limit = pfb->ram.size - imem->reserved - 1;
+			args.limit = pfb->ram->size - imem->reserved - 1;
 		}
 
 		ret = nouveau_object_new(nv_object(client), chan->handle, vram,
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 87afb0c..907d20e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -138,7 +138,7 @@
 {
 	struct nouveau_framebuffer *nouveau_fb;
 	struct drm_gem_object *gem;
-	int ret;
+	int ret = -ENOMEM;
 
 	gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
 	if (!gem)
@@ -146,15 +146,19 @@
 
 	nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
 	if (!nouveau_fb)
-		return ERR_PTR(-ENOMEM);
+		goto err_unref;
 
 	ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
-	if (ret) {
-		drm_gem_object_unreference(gem);
-		return ERR_PTR(ret);
-	}
+	if (ret)
+		goto err;
 
 	return &nouveau_fb->base;
+
+err:
+	kfree(nouveau_fb);
+err_unref:
+	drm_gem_object_unreference(gem);
+	return ERR_PTR(ret);
 }
 
 static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
@@ -333,10 +337,15 @@
 
 	if (nouveau_modeset == 1 ||
 	    (nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) {
-		if (nv_device(drm->device)->card_type < NV_50)
-			ret = nv04_display_create(dev);
-		else
-			ret = nv50_display_create(dev);
+		if (drm->vbios.dcb.entries) {
+			if (nv_device(drm->device)->card_type < NV_50)
+				ret = nv04_display_create(dev);
+			else
+				ret = nv50_display_create(dev);
+		} else {
+			ret = 0;
+		}
+
 		if (ret)
 			goto disp_create_err;
 
@@ -519,9 +528,12 @@
 	struct nouveau_page_flip_state *s;
 	struct nouveau_channel *chan = NULL;
 	struct nouveau_fence *fence;
-	struct list_head res;
-	struct ttm_validate_buffer res_val[2];
+	struct ttm_validate_buffer resv[2] = {
+		{ .bo = &old_bo->bo },
+		{ .bo = &new_bo->bo },
+	};
 	struct ww_acquire_ctx ticket;
+	LIST_HEAD(res);
 	int ret;
 
 	if (!drm->channel)
@@ -540,27 +552,19 @@
 		chan = drm->channel;
 	spin_unlock(&old_bo->bo.bdev->fence_lock);
 
-	mutex_lock(&chan->cli->mutex);
-
 	if (new_bo != old_bo) {
 		ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
-		if (likely(!ret)) {
-			res_val[0].bo = &old_bo->bo;
-			res_val[1].bo = &new_bo->bo;
-			INIT_LIST_HEAD(&res);
-			list_add_tail(&res_val[0].head, &res);
-			list_add_tail(&res_val[1].head, &res);
-			ret = ttm_eu_reserve_buffers(&ticket, &res);
-			if (ret)
-				nouveau_bo_unpin(new_bo);
-		}
-	} else
-		ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
+		if (ret)
+			goto fail_free;
 
-	if (ret) {
-		mutex_unlock(&chan->cli->mutex);
-		goto fail_free;
+		list_add(&resv[1].head, &res);
 	}
+	list_add(&resv[0].head, &res);
+
+	mutex_lock(&chan->cli->mutex);
+	ret = ttm_eu_reserve_buffers(&ticket, &res);
+	if (ret)
+		goto fail_unpin;
 
 	/* Initialize a page flip struct */
 	*s = (struct nouveau_page_flip_state)
@@ -571,10 +575,8 @@
 	/* Emit a page flip */
 	if (nv_device(drm->device)->card_type >= NV_50) {
 		ret = nv50_display_flip_next(crtc, fb, chan, 0);
-		if (ret) {
-			mutex_unlock(&chan->cli->mutex);
+		if (ret)
 			goto fail_unreserve;
-		}
 	}
 
 	ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence);
@@ -585,22 +587,18 @@
 	/* Update the crtc struct and cleanup */
 	crtc->fb = fb;
 
-	if (old_bo != new_bo) {
-		ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+	ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+	if (old_bo != new_bo)
 		nouveau_bo_unpin(old_bo);
-	} else {
-		nouveau_bo_fence(new_bo, fence);
-		ttm_bo_unreserve(&new_bo->bo);
-	}
 	nouveau_fence_unref(&fence);
 	return 0;
 
 fail_unreserve:
-	if (old_bo != new_bo) {
-		ttm_eu_backoff_reservation(&ticket, &res);
+	ttm_eu_backoff_reservation(&ticket, &res);
+fail_unpin:
+	mutex_unlock(&chan->cli->mutex);
+	if (old_bo != new_bo)
 		nouveau_bo_unpin(new_bo);
-	} else
-		ttm_bo_unreserve(&new_bo->bo);
 fail_free:
 	kfree(s);
 	return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 218a4b5..6197266 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -192,6 +192,18 @@
 
 		arg0 = NVE0_CHANNEL_IND_ENGINE_GR;
 		arg1 = 1;
+	} else
+	if (device->chipset >= 0xa3 &&
+	    device->chipset != 0xaa &&
+	    device->chipset != 0xac) {
+		ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE,
+					  NVDRM_CHAN + 1, NvDmaFB, NvDmaTT,
+					  &drm->cechan);
+		if (ret)
+			NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
+
+		arg0 = NvDmaFB;
+		arg1 = NvDmaTT;
 	} else {
 		arg0 = NvDmaFB;
 		arg1 = NvDmaTT;
@@ -284,8 +296,6 @@
 	return 0;
 }
 
-static struct lock_class_key drm_client_lock_class_key;
-
 static int
 nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 {
@@ -297,7 +307,6 @@
 	ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
 	if (ret)
 		return ret;
-	lockdep_set_class(&drm->client.mutex, &drm_client_lock_class_key);
 
 	dev->dev_private = drm;
 	drm->dev = dev;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index f2b30f8..41ff7e0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -96,6 +96,7 @@
 		int (*move)(struct nouveau_channel *,
 			    struct ttm_buffer_object *,
 			    struct ttm_mem_reg *, struct ttm_mem_reg *);
+		struct nouveau_channel *chan;
 		int mtrr;
 	} ttm;
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index ecbfe69..4c1bc06 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -385,6 +385,7 @@
 	mutex_unlock(&dev->struct_mutex);
 	if (chan)
 		nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma);
+	nouveau_bo_unmap(nvbo);
 out_unpin:
 	nouveau_bo_unpin(nvbo);
 out_unref:
@@ -472,10 +473,10 @@
 
 	drm_fb_helper_single_add_all_connectors(&fbcon->helper);
 
-	if (pfb->ram.size <= 32 * 1024 * 1024)
+	if (pfb->ram->size <= 32 * 1024 * 1024)
 		preferred_bpp = 8;
 	else
-	if (pfb->ram.size <= 64 * 1024 * 1024)
+	if (pfb->ram->size <= 64 * 1024 * 1024)
 		preferred_bpp = 16;
 	else
 		preferred_bpp = 32;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 6c94683..be31499 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -35,15 +35,34 @@
 
 #include <engine/fifo.h>
 
+struct fence_work {
+	struct work_struct base;
+	struct list_head head;
+	void (*func)(void *);
+	void *data;
+};
+
+static void
+nouveau_fence_signal(struct nouveau_fence *fence)
+{
+	struct fence_work *work, *temp;
+
+	list_for_each_entry_safe(work, temp, &fence->work, head) {
+		schedule_work(&work->base);
+		list_del(&work->head);
+	}
+
+	fence->channel = NULL;
+	list_del(&fence->head);
+}
+
 void
 nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
 {
 	struct nouveau_fence *fence, *fnext;
 	spin_lock(&fctx->lock);
 	list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
-		fence->channel = NULL;
-		list_del(&fence->head);
-		nouveau_fence_unref(&fence);
+		nouveau_fence_signal(fence);
 	}
 	spin_unlock(&fctx->lock);
 }
@@ -57,6 +76,50 @@
 }
 
 static void
+nouveau_fence_work_handler(struct work_struct *kwork)
+{
+	struct fence_work *work = container_of(kwork, typeof(*work), base);
+	work->func(work->data);
+	kfree(work);
+}
+
+void
+nouveau_fence_work(struct nouveau_fence *fence,
+		   void (*func)(void *), void *data)
+{
+	struct nouveau_channel *chan = fence->channel;
+	struct nouveau_fence_chan *fctx;
+	struct fence_work *work = NULL;
+
+	if (nouveau_fence_done(fence)) {
+		func(data);
+		return;
+	}
+
+	fctx = chan->fence;
+	work = kmalloc(sizeof(*work), GFP_KERNEL);
+	if (!work) {
+		WARN_ON(nouveau_fence_wait(fence, false, false));
+		func(data);
+		return;
+	}
+
+	spin_lock(&fctx->lock);
+	if (!fence->channel) {
+		spin_unlock(&fctx->lock);
+		kfree(work);
+		func(data);
+		return;
+	}
+
+	INIT_WORK(&work->base, nouveau_fence_work_handler);
+	work->func = func;
+	work->data = data;
+	list_add(&work->head, &fence->work);
+	spin_unlock(&fctx->lock);
+}
+
+static void
 nouveau_fence_update(struct nouveau_channel *chan)
 {
 	struct nouveau_fence_chan *fctx = chan->fence;
@@ -67,8 +130,7 @@
 		if (fctx->read(chan) < fence->sequence)
 			break;
 
-		fence->channel = NULL;
-		list_del(&fence->head);
+		nouveau_fence_signal(fence);
 		nouveau_fence_unref(&fence);
 	}
 	spin_unlock(&fctx->lock);
@@ -81,7 +143,7 @@
 	int ret;
 
 	fence->channel  = chan;
-	fence->timeout  = jiffies + (3 * DRM_HZ);
+	fence->timeout  = jiffies + (15 * DRM_HZ);
 	fence->sequence = ++fctx->sequence;
 
 	ret = fctx->emit(fence);
@@ -265,6 +327,7 @@
 	if (!fence)
 		return -ENOMEM;
 
+	INIT_LIST_HEAD(&fence->work);
 	fence->sysmem = sysmem;
 	kref_init(&fence->kref);
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index c899434..c57bb61 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -5,6 +5,7 @@
 
 struct nouveau_fence {
 	struct list_head head;
+	struct list_head work;
 	struct kref kref;
 
 	bool sysmem;
@@ -22,6 +23,7 @@
 
 int  nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *);
 bool nouveau_fence_done(struct nouveau_fence *);
+void nouveau_fence_work(struct nouveau_fence *, void (*)(void *), void *);
 int  nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
 int  nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index 2b2077d..830cb7b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -50,12 +50,6 @@
 		return;
 	nvbo->gem = NULL;
 
-	/* Lockdep hates you for doing reserve with gem object lock held */
-	if (WARN_ON_ONCE(nvbo->pin_refcnt)) {
-		nvbo->pin_refcnt = 1;
-		nouveau_bo_unpin(nvbo);
-	}
-
 	if (gem->import_attach)
 		drm_prime_gem_destroy(gem, nvbo->bo.sg);
 
@@ -102,6 +96,41 @@
 	return ret;
 }
 
+static void
+nouveau_gem_object_delete(void *data)
+{
+	struct nouveau_vma *vma = data;
+	nouveau_vm_unmap(vma);
+	nouveau_vm_put(vma);
+	kfree(vma);
+}
+
+static void
+nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
+{
+	const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM;
+	struct nouveau_fence *fence = NULL;
+
+	list_del(&vma->head);
+
+	if (mapped) {
+		spin_lock(&nvbo->bo.bdev->fence_lock);
+		if (nvbo->bo.sync_obj)
+			fence = nouveau_fence_ref(nvbo->bo.sync_obj);
+		spin_unlock(&nvbo->bo.bdev->fence_lock);
+	}
+
+	if (fence) {
+		nouveau_fence_work(fence, nouveau_gem_object_delete, vma);
+	} else {
+		if (mapped)
+			nouveau_vm_unmap(vma);
+		nouveau_vm_put(vma);
+		kfree(vma);
+	}
+	nouveau_fence_unref(&fence);
+}
+
 void
 nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
 {
@@ -119,10 +148,8 @@
 
 	vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
 	if (vma) {
-		if (--vma->refcount == 0) {
-			nouveau_bo_vma_del(nvbo, vma);
-			kfree(vma);
-		}
+		if (--vma->refcount == 0)
+			nouveau_gem_object_unmap(nvbo, vma);
 	}
 	ttm_bo_unreserve(&nvbo->bo);
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 7e0ff10a..4f6a572 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -125,7 +125,7 @@
 		t->reg[7] = 0x4000202 | (e->tCL - 1) << 16;
 
 		/* XXX: P.version == 1 only has DDR2 and GDDR3? */
-		if (pfb->ram.type == NV_MEM_TYPE_DDR2) {
+		if (pfb->ram->type == NV_MEM_TYPE_DDR2) {
 			t->reg[5] |= (e->tCL + 3) << 8;
 			t->reg[6] |= (t->tCWL - 2) << 8;
 			t->reg[8] |= (e->tCL - 4);
@@ -428,7 +428,7 @@
 		break;
 	}
 
-	switch (pfb->ram.type * !ret) {
+	switch (pfb->ram->type * !ret) {
 	case NV_MEM_TYPE_GDDR3:
 		ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t);
 		break;
@@ -455,7 +455,7 @@
 		else
 			dll_off = !!(ramcfg[2] & 0x40);
 
-		switch (pfb->ram.type) {
+		switch (pfb->ram->type) {
 		case NV_MEM_TYPE_GDDR3:
 			t->mr[1] &= ~0x00000040;
 			t->mr[1] |=  0x00000040 * dll_off;
@@ -522,7 +522,7 @@
 	t->odt = 0;
 	t->drive_strength = 0;
 
-	switch (pfb->ram.type) {
+	switch (pfb->ram->type) {
 	case NV_MEM_TYPE_DDR3:
 		t->odt |= (t->mr[1] & 0x200) >> 7;
 	case NV_MEM_TYPE_DDR2:
@@ -551,7 +551,7 @@
 	u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] };
 	u32 mr1_dlloff;
 
-	switch (pfb->ram.type) {
+	switch (pfb->ram->type) {
 	case NV_MEM_TYPE_DDR2:
 		tDLLK = 2000;
 		mr1_dlloff = 0x00000001;
@@ -572,7 +572,7 @@
 	}
 
 	/* fetch current MRs */
-	switch (pfb->ram.type) {
+	switch (pfb->ram->type) {
 	case NV_MEM_TYPE_GDDR3:
 	case NV_MEM_TYPE_DDR3:
 		mr[2] = exec->mrg(exec, 2);
@@ -639,7 +639,7 @@
 		exec->mrs (exec, 0, info->mr[0] | 0x00000000);
 		exec->wait(exec, tMRD);
 		exec->wait(exec, tDLLK);
-		if (pfb->ram.type == NV_MEM_TYPE_GDDR3)
+		if (pfb->ram->type == NV_MEM_TYPE_GDDR3)
 			exec->precharge(exec);
 	}
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index 3da985e..19e3757 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -69,7 +69,7 @@
 	struct nouveau_drm *drm = nouveau_bdev(man->bdev);
 	struct nouveau_fb *pfb = nouveau_fb(drm->device);
 	nouveau_mem_node_cleanup(mem->mm_node);
-	pfb->ram.put(pfb, (struct nouveau_mem **)&mem->mm_node);
+	pfb->ram->put(pfb, (struct nouveau_mem **)&mem->mm_node);
 }
 
 static int
@@ -88,7 +88,7 @@
 	if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)
 		size_nc = 1 << nvbo->page_shift;
 
-	ret = pfb->ram.get(pfb, mem->num_pages << PAGE_SHIFT,
+	ret = pfb->ram->get(pfb, mem->num_pages << PAGE_SHIFT,
 			   mem->page_alignment << PAGE_SHIFT, size_nc,
 			   (nvbo->tile_flags >> 8) & 0x3ff, &node);
 	if (ret) {
@@ -111,7 +111,7 @@
 	struct nouveau_mm_node *r;
 	u32 total = 0, free = 0;
 
-	mutex_lock(&mm->mutex);
+	mutex_lock(&nv_subdev(pfb)->mutex);
 	list_for_each_entry(r, &mm->nodes, nl_entry) {
 		printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n",
 		       prefix, r->type, ((u64)r->offset << 12),
@@ -121,7 +121,7 @@
 		if (!r->type)
 			free += r->length;
 	}
-	mutex_unlock(&mm->mutex);
+	mutex_unlock(&nv_subdev(pfb)->mutex);
 
 	printk(KERN_DEBUG "%s  total: 0x%010llx free: 0x%010llx\n",
 	       prefix, (u64)total << 12, (u64)free << 12);
@@ -168,9 +168,6 @@
 	struct nouveau_bo *nvbo = nouveau_bo(bo);
 	struct nouveau_mem *node;
 
-	if (unlikely((mem->num_pages << PAGE_SHIFT) >= 512 * 1024 * 1024))
-		return -ENOMEM;
-
 	node = kzalloc(sizeof(*node), GFP_KERNEL);
 	if (!node)
 		return -ENOMEM;
@@ -386,7 +383,7 @@
 	}
 
 	/* VRAM init */
-	drm->gem.vram_available  = nouveau_fb(drm->device)->ram.size;
+	drm->gem.vram_available  = nouveau_fb(drm->device)->ram->size;
 	drm->gem.vram_available -= nouveau_instmem(drm->device)->reserved;
 
 	ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
@@ -402,8 +399,6 @@
 	/* GART init */
 	if (drm->agp.stat != ENABLED) {
 		drm->gem.gart_available = nouveau_vmmgr(drm->device)->limit;
-		if (drm->gem.gart_available > 512 * 1024 * 1024)
-			drm->gem.gart_available = 512 * 1024 * 1024;
 	} else {
 		drm->gem.gart_available = drm->agp.size;
 	}
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index dd5e01f..8b40a36 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -159,7 +159,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 					.conf0 = NV50_DMA_CONF0_ENABLE |
 					         NV50_DMA_CONF0_PART_256,
 				     }, sizeof(struct nv_dma_class), &object);
@@ -172,7 +172,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 					.conf0 = NV50_DMA_CONF0_ENABLE | 0x70 |
 					         NV50_DMA_CONF0_PART_256,
 				 }, sizeof(struct nv_dma_class), &object);
@@ -185,7 +185,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 					.conf0 = NV50_DMA_CONF0_ENABLE | 0x7a |
 					         NV50_DMA_CONF0_PART_256,
 				 }, sizeof(struct nv_dma_class), &object);
@@ -204,7 +204,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 					.conf0 = NVC0_DMA_CONF0_ENABLE,
 				     }, sizeof(struct nv_dma_class), &object);
 	if (ret)
@@ -216,7 +216,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 					.conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe,
 				 }, sizeof(struct nv_dma_class), &object);
 	if (ret)
@@ -228,7 +228,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 					.conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe,
 				 }, sizeof(struct nv_dma_class), &object);
 	return ret;
@@ -246,7 +246,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 					.conf0 = NVD0_DMA_CONF0_ENABLE |
 						 NVD0_DMA_CONF0_PAGE_LP,
 				     }, sizeof(struct nv_dma_class), &object);
@@ -259,7 +259,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 					.conf0 = NVD0_DMA_CONF0_ENABLE | 0xfe |
 						 NVD0_DMA_CONF0_PAGE_LP,
 				 }, sizeof(struct nv_dma_class), &object);
@@ -316,7 +316,7 @@
 					.flags = NV_DMA_TARGET_VRAM |
 						 NV_DMA_ACCESS_RDWR,
 					.start = 0,
-					.limit = pfb->ram.size - 1,
+					.limit = pfb->ram->size - 1,
 				 }, sizeof(struct nv_dma_class), &object);
 	if (ret)
 		return ret;
@@ -355,6 +355,7 @@
 
 struct nv50_head {
 	struct nouveau_crtc base;
+	struct nouveau_bo *image;
 	struct nv50_curs curs;
 	struct nv50_sync sync;
 	struct nv50_ovly ovly;
@@ -517,9 +518,10 @@
 {
 	struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+	struct nv50_head *head = nv50_head(crtc);
 	struct nv50_sync *sync = nv50_sync(crtc);
-	int head = nv_crtc->index, ret;
 	u32 *push;
+	int ret;
 
 	swap_interval <<= 4;
 	if (swap_interval == 0)
@@ -537,7 +539,7 @@
 			return ret;
 
 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
-		OUT_RING  (chan, NvEvoSema0 + head);
+		OUT_RING  (chan, NvEvoSema0 + nv_crtc->index);
 		OUT_RING  (chan, sync->addr ^ 0x10);
 		BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
 		OUT_RING  (chan, sync->data + 1);
@@ -546,7 +548,7 @@
 		OUT_RING  (chan, sync->data);
 	} else
 	if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
-		u64 addr = nv84_fence_crtc(chan, head) + sync->addr;
+		u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
 		ret = RING_SPACE(chan, 12);
 		if (ret)
 			return ret;
@@ -565,7 +567,7 @@
 		OUT_RING  (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
 	} else
 	if (chan) {
-		u64 addr = nv84_fence_crtc(chan, head) + sync->addr;
+		u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr;
 		ret = RING_SPACE(chan, 10);
 		if (ret)
 			return ret;
@@ -630,6 +632,8 @@
 	evo_mthd(push, 0x0080, 1);
 	evo_data(push, 0x00000000);
 	evo_kick(push, sync);
+
+	nouveau_bo_ref(nv_fb->nvbo, &head->image);
 	return 0;
 }
 
@@ -1038,18 +1042,17 @@
 nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
 {
 	struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+	struct nv50_head *head = nv50_head(crtc);
 	int ret;
 
 	ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM);
-	if (ret)
-		return ret;
-
-	if (old_fb) {
-		nvfb = nouveau_framebuffer(old_fb);
-		nouveau_bo_unpin(nvfb->nvbo);
+	if (ret == 0) {
+		if (head->image)
+			nouveau_bo_unpin(head->image);
+		nouveau_bo_ref(nvfb->nvbo, &head->image);
 	}
 
-	return 0;
+	return ret;
 }
 
 static int
@@ -1198,6 +1201,15 @@
 	}
 }
 
+static void
+nv50_crtc_disable(struct drm_crtc *crtc)
+{
+	struct nv50_head *head = nv50_head(crtc);
+	if (head->image)
+		nouveau_bo_unpin(head->image);
+	nouveau_bo_ref(NULL, &head->image);
+}
+
 static int
 nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
 		     uint32_t handle, uint32_t width, uint32_t height)
@@ -1271,18 +1283,29 @@
 	struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
 	struct nv50_disp *disp = nv50_disp(crtc->dev);
 	struct nv50_head *head = nv50_head(crtc);
+
 	nv50_dmac_destroy(disp->core, &head->ovly.base);
 	nv50_pioc_destroy(disp->core, &head->oimm.base);
 	nv50_dmac_destroy(disp->core, &head->sync.base);
 	nv50_pioc_destroy(disp->core, &head->curs.base);
+
+	/*XXX: this shouldn't be necessary, but the core doesn't call
+	 *     disconnect() during the cleanup paths
+	 */
+	if (head->image)
+		nouveau_bo_unpin(head->image);
+	nouveau_bo_ref(NULL, &head->image);
+
 	nouveau_bo_unmap(nv_crtc->cursor.nvbo);
 	if (nv_crtc->cursor.nvbo)
 		nouveau_bo_unpin(nv_crtc->cursor.nvbo);
 	nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
+
 	nouveau_bo_unmap(nv_crtc->lut.nvbo);
 	if (nv_crtc->lut.nvbo)
 		nouveau_bo_unpin(nv_crtc->lut.nvbo);
 	nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
+
 	drm_crtc_cleanup(crtc);
 	kfree(crtc);
 }
@@ -1296,6 +1319,7 @@
 	.mode_set_base = nv50_crtc_mode_set_base,
 	.mode_set_base_atomic = nv50_crtc_mode_set_base_atomic,
 	.load_lut = nv50_crtc_lut_load,
+	.disable = nv50_crtc_disable,
 };
 
 static const struct drm_crtc_funcs nv50_crtc_func = {
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index 69620e3..4efc33f 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -493,12 +493,12 @@
 	struct hwsq_ucode *hwsq = &info->mclk_hwsq;
 
 	if (mr <= 1) {
-		if (pfb->ram.ranks > 1)
+		if (pfb->ram->ranks > 1)
 			hwsq_wr32(hwsq, 0x1002c8 + ((mr - 0) * 4), data);
 		hwsq_wr32(hwsq, 0x1002c0 + ((mr - 0) * 4), data);
 	} else
 	if (mr <= 3) {
-		if (pfb->ram.ranks > 1)
+		if (pfb->ram->ranks > 1)
 			hwsq_wr32(hwsq, 0x1002e8 + ((mr - 2) * 4), data);
 		hwsq_wr32(hwsq, 0x1002e0 + ((mr - 2) * 4), data);
 	}
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
index 863f010..0d0ed59 100644
--- a/drivers/gpu/drm/nouveau/nva3_pm.c
+++ b/drivers/gpu/drm/nouveau/nva3_pm.c
@@ -389,12 +389,12 @@
 	struct nouveau_device *device = nouveau_dev(exec->dev);
 	struct nouveau_fb *pfb = nouveau_fb(device);
 	if (mr <= 1) {
-		if (pfb->ram.ranks > 1)
+		if (pfb->ram->ranks > 1)
 			nv_wr32(device, 0x1002c8 + ((mr - 0) * 4), data);
 		nv_wr32(device, 0x1002c0 + ((mr - 0) * 4), data);
 	} else
 	if (mr <= 3) {
-		if (pfb->ram.ranks > 1)
+		if (pfb->ram->ranks > 1)
 			nv_wr32(device, 0x1002e8 + ((mr - 2) * 4), data);
 		nv_wr32(device, 0x1002e0 + ((mr - 2) * 4), data);
 	}
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c
index 0d34eb5..3b7041c 100644
--- a/drivers/gpu/drm/nouveau/nvc0_pm.c
+++ b/drivers/gpu/drm/nouveau/nvc0_pm.c
@@ -477,7 +477,7 @@
 {
 	struct nouveau_device *device = nouveau_dev(exec->dev);
 	struct nouveau_fb *pfb = nouveau_fb(device);
-	if (pfb->ram.type != NV_MEM_TYPE_GDDR5) {
+	if (pfb->ram->type != NV_MEM_TYPE_GDDR5) {
 		if (mr <= 1)
 			return nv_rd32(device, 0x10f300 + ((mr - 0) * 4));
 		return nv_rd32(device, 0x10f320 + ((mr - 2) * 4));
@@ -496,15 +496,15 @@
 {
 	struct nouveau_device *device = nouveau_dev(exec->dev);
 	struct nouveau_fb *pfb = nouveau_fb(device);
-	if (pfb->ram.type != NV_MEM_TYPE_GDDR5) {
+	if (pfb->ram->type != NV_MEM_TYPE_GDDR5) {
 		if (mr <= 1) {
 			nv_wr32(device, 0x10f300 + ((mr - 0) * 4), data);
-			if (pfb->ram.ranks > 1)
+			if (pfb->ram->ranks > 1)
 				nv_wr32(device, 0x10f308 + ((mr - 0) * 4), data);
 		} else
 		if (mr <= 3) {
 			nv_wr32(device, 0x10f320 + ((mr - 2) * 4), data);
-			if (pfb->ram.ranks > 1)
+			if (pfb->ram->ranks > 1)
 				nv_wr32(device, 0x10f328 + ((mr - 2) * 4), data);
 		}
 	} else {
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index ef161ea9..11a5263 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -40,7 +40,7 @@
 	 * mgr->id.)  Eventually this will be replaced w/ something
 	 * more common-panel-framework-y
 	 */
-	struct omap_overlay_manager mgr;
+	struct omap_overlay_manager *mgr;
 
 	struct omap_video_timings timings;
 	bool enabled;
@@ -90,7 +90,32 @@
  * job of sequencing the setup of the video pipe in the proper order
  */
 
+/* ovl-mgr-id -> crtc */
+static struct omap_crtc *omap_crtcs[8];
+
 /* we can probably ignore these until we support command-mode panels: */
+static int omap_crtc_connect(struct omap_overlay_manager *mgr,
+		struct omap_dss_device *dst)
+{
+	if (mgr->output)
+		return -EINVAL;
+
+	if ((mgr->supported_outputs & dst->id) == 0)
+		return -EINVAL;
+
+	dst->manager = mgr;
+	mgr->output = dst;
+
+	return 0;
+}
+
+static void omap_crtc_disconnect(struct omap_overlay_manager *mgr,
+		struct omap_dss_device *dst)
+{
+	mgr->output->manager = NULL;
+	mgr->output = NULL;
+}
+
 static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
 {
 }
@@ -107,7 +132,7 @@
 static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
 		const struct omap_video_timings *timings)
 {
-	struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
+	struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
 	DBG("%s", omap_crtc->name);
 	omap_crtc->timings = *timings;
 	omap_crtc->full_update = true;
@@ -116,7 +141,7 @@
 static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
 		const struct dss_lcd_mgr_config *config)
 {
-	struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
+	struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
 	DBG("%s", omap_crtc->name);
 	dispc_mgr_set_lcd_config(omap_crtc->channel, config);
 }
@@ -135,6 +160,8 @@
 }
 
 static const struct dss_mgr_ops mgr_ops = {
+		.connect = omap_crtc_connect,
+		.disconnect = omap_crtc_disconnect,
 		.start_update = omap_crtc_start_update,
 		.enable = omap_crtc_enable,
 		.disable = omap_crtc_disable,
@@ -564,7 +591,7 @@
 	} else {
 		if (encoder) {
 			omap_encoder_set_enabled(encoder, false);
-			omap_encoder_update(encoder, &omap_crtc->mgr,
+			omap_encoder_update(encoder, omap_crtc->mgr,
 					&omap_crtc->timings);
 			omap_encoder_set_enabled(encoder, true);
 			omap_crtc->full_update = false;
@@ -590,6 +617,11 @@
 		[OMAP_DSS_CHANNEL_LCD2] = "lcd2",
 };
 
+void omap_crtc_pre_init(void)
+{
+	dss_install_mgr_ops(&mgr_ops);
+}
+
 /* initialize crtc */
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 		struct drm_plane *plane, enum omap_channel channel, int id)
@@ -630,9 +662,7 @@
 	omap_irq_register(dev, &omap_crtc->error_irq);
 
 	/* temporary: */
-	omap_crtc->mgr.id = channel;
-
-	dss_install_mgr_ops(&mgr_ops);
+	omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
 
 	/* TODO: fix hard-coded setup.. add properties! */
 	info = &omap_crtc->info;
@@ -646,6 +676,8 @@
 
 	omap_plane_install_properties(omap_crtc->plane, &crtc->base);
 
+	omap_crtcs[channel] = omap_crtc;
+
 	return crtc;
 
 fail:
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 826586f..a3004f1 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -65,10 +65,8 @@
 	switch (dssdev->type) {
 	case OMAP_DISPLAY_TYPE_HDMI:
 		return DRM_MODE_CONNECTOR_HDMIA;
-	case OMAP_DISPLAY_TYPE_DPI:
-		if (!strcmp(dssdev->name, "dvi"))
-			return DRM_MODE_CONNECTOR_DVID;
-		/* fallthrough */
+	case OMAP_DISPLAY_TYPE_DVI:
+		return DRM_MODE_CONNECTOR_DVID;
 	default:
 		return DRM_MODE_CONNECTOR_Unknown;
 	}
@@ -97,6 +95,9 @@
 	int num_mgrs = dss_feat_get_num_mgrs();
 	int num_crtcs;
 	int i, id = 0;
+	int r;
+
+	omap_crtc_pre_init();
 
 	drm_mode_config_init(dev);
 
@@ -116,6 +117,7 @@
 		struct drm_connector *connector;
 		struct drm_encoder *encoder;
 		enum omap_channel channel;
+		struct omap_overlay_manager *mgr;
 
 		if (!dssdev->driver) {
 			dev_warn(dev->dev, "%s has no driver.. skipping it\n",
@@ -131,6 +133,13 @@
 			continue;
 		}
 
+		r = dssdev->driver->connect(dssdev);
+		if (r) {
+			dev_err(dev->dev, "could not connect display: %s\n",
+					dssdev->name);
+			continue;
+		}
+
 		encoder = omap_encoder_init(dev, dssdev);
 
 		if (!encoder) {
@@ -172,8 +181,9 @@
 		 * other possible channels to which the encoder can connect are
 		 * not considered.
 		 */
-		channel = dssdev->output->dispc_channel;
 
+		mgr = omapdss_find_mgr_from_display(dssdev);
+		channel = mgr->id;
 		/*
 		 * if this channel hasn't already been taken by a previously
 		 * allocated crtc, we create a new crtc for it
@@ -247,6 +257,9 @@
 		struct drm_encoder *encoder = priv->encoders[i];
 		struct omap_dss_device *dssdev =
 					omap_encoder_get_dssdev(encoder);
+		struct omap_dss_device *output;
+
+		output = omapdss_find_output_from_display(dssdev);
 
 		/* figure out which crtc's we can connect the encoder to: */
 		encoder->possible_crtcs = 0;
@@ -259,9 +272,11 @@
 			supported_outputs =
 				dss_feat_get_supported_outputs(crtc_channel);
 
-			if (supported_outputs & dssdev->output->id)
+			if (supported_outputs & output->id)
 				encoder->possible_crtcs |= (1 << id);
 		}
+
+		omap_dss_put_device(output);
 	}
 
 	DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 215a20d..14f17da 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -157,6 +157,7 @@
 enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
 int omap_crtc_apply(struct drm_crtc *crtc,
 		struct omap_drm_apply *apply);
+void omap_crtc_pre_init(void);
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 		struct drm_plane *plane, enum omap_channel channel, int id);
 
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index f867714..93c2f2c 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -49,6 +49,11 @@
 	kfree(ring);
 }
 
+void qxl_ring_init_hdr(struct qxl_ring *ring)
+{
+	ring->ring->header.notify_on_prod = ring->n_elements;
+}
+
 struct qxl_ring *
 qxl_ring_create(struct qxl_ring_header *header,
 		int element_size,
@@ -69,7 +74,7 @@
 	ring->prod_notify = prod_notify;
 	ring->push_event = push_event;
 	if (set_prod_notify)
-		header->notify_on_prod = ring->n_elements;
+		qxl_ring_init_hdr(ring);
 	spin_lock_init(&ring->lock);
 	return ring;
 }
@@ -87,7 +92,7 @@
 	return ret;
 }
 
-static int qxl_check_idle(struct qxl_ring *ring)
+int qxl_check_idle(struct qxl_ring *ring)
 {
 	int ret;
 	struct qxl_ring_header *header = &(ring->ring->header);
@@ -375,8 +380,8 @@
 	wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
 }
 
-void qxl_io_create_primary(struct qxl_device *qdev, unsigned width,
-			   unsigned height, unsigned offset, struct qxl_bo *bo)
+void qxl_io_create_primary(struct qxl_device *qdev,
+			   unsigned offset, struct qxl_bo *bo)
 {
 	struct qxl_surface_create *create;
 
@@ -384,8 +389,8 @@
 		 qdev->ram_header);
 	create = &qdev->ram_header->create_surface;
 	create->format = bo->surf.format;
-	create->width = width;
-	create->height = height;
+	create->width = bo->surf.width;
+	create->height = bo->surf.height;
 	create->stride = bo->surf.stride;
 	create->mem = qxl_bo_physical_address(qdev, bo, offset);
 
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 686a937..f76f5dd 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -30,53 +30,9 @@
 #include "qxl_object.h"
 #include "drm_crtc_helper.h"
 
-static void qxl_crtc_set_to_mode(struct qxl_device *qdev,
-				 struct drm_connector *connector,
-				 struct qxl_head *head)
+static bool qxl_head_enabled(struct qxl_head *head)
 {
-	struct drm_device *dev = connector->dev;
-	struct drm_display_mode *mode, *t;
-	int width = head->width;
-	int height = head->height;
-
-	if (width < 320 || height < 240) {
-		qxl_io_log(qdev, "%s: bad head: %dx%d", width, height);
-		width = 1024;
-		height = 768;
-	}
-	if (width * height * 4 > 16*1024*1024) {
-		width = 1024;
-		height = 768;
-	}
-	/* TODO: go over regular modes and removed preferred? */
-	list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
-		drm_mode_remove(connector, mode);
-	mode = drm_cvt_mode(dev, width, height, 60, false, false, false);
-	mode->type |= DRM_MODE_TYPE_PREFERRED;
-	mode->status = MODE_OK;
-	drm_mode_probed_add(connector, mode);
-	qxl_io_log(qdev, "%s: %d x %d\n", __func__, width, height);
-}
-
-void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev)
-{
-	struct drm_connector *connector;
-	int i;
-	struct drm_device *dev = qdev->ddev;
-
-	i = 0;
-	qxl_io_log(qdev, "%s: %d, %d\n", __func__,
-		   dev->mode_config.num_connector,
-		   qdev->monitors_config->count);
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		if (i > qdev->monitors_config->count) {
-			/* crtc will be reported as disabled */
-			continue;
-		}
-		qxl_crtc_set_to_mode(qdev, connector,
-				     &qdev->monitors_config->heads[i]);
-		++i;
-	}
+	return head->width && head->height;
 }
 
 void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count)
@@ -106,7 +62,6 @@
 	int num_monitors;
 	uint32_t crc;
 
-	BUG_ON(!qdev->monitors_config);
 	num_monitors = qdev->rom->client_monitors_config.count;
 	crc = crc32(0, (const uint8_t *)&qdev->rom->client_monitors_config,
 		  sizeof(qdev->rom->client_monitors_config));
@@ -117,8 +72,8 @@
 		return 1;
 	}
 	if (num_monitors > qdev->monitors_config->max_allowed) {
-		DRM_INFO("client monitors list will be truncated: %d < %d\n",
-			 qdev->monitors_config->max_allowed, num_monitors);
+		DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
+			      qdev->monitors_config->max_allowed, num_monitors);
 		num_monitors = qdev->monitors_config->max_allowed;
 	} else {
 		num_monitors = qdev->rom->client_monitors_config.count;
@@ -132,18 +87,15 @@
 			&qdev->rom->client_monitors_config.heads[i];
 		struct qxl_head *client_head =
 			&qdev->client_monitors_config->heads[i];
-		struct qxl_head *head = &qdev->monitors_config->heads[i];
-		client_head->x = head->x = c_rect->left;
-		client_head->y = head->y = c_rect->top;
-		client_head->width = head->width =
-						c_rect->right - c_rect->left;
-		client_head->height = head->height =
-						c_rect->bottom - c_rect->top;
-		client_head->surface_id = head->surface_id = 0;
-		client_head->id = head->id = i;
-		client_head->flags = head->flags = 0;
-		QXL_DEBUG(qdev, "read %dx%d+%d+%d\n", head->width, head->height,
-			  head->x, head->y);
+		client_head->x = c_rect->left;
+		client_head->y = c_rect->top;
+		client_head->width = c_rect->right - c_rect->left;
+		client_head->height = c_rect->bottom - c_rect->top;
+		client_head->surface_id = 0;
+		client_head->id = i;
+		client_head->flags = 0;
+		DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head->width, client_head->height,
+			  client_head->x, client_head->y);
 	}
 	return 0;
 }
@@ -155,10 +107,7 @@
 		qxl_io_log(qdev, "failed crc check for client_monitors_config,"
 				 " retrying\n");
 	}
-	qxl_crtc_set_from_monitors_config(qdev);
-	/* fire off a uevent and let userspace tell us what to do */
-	qxl_io_log(qdev, "calling drm_sysfs_hotplug_event\n");
-	drm_sysfs_hotplug_event(qdev->ddev);
+	drm_helper_hpd_irq_event(qdev->ddev);
 }
 
 static int qxl_add_monitors_config_modes(struct drm_connector *connector)
@@ -170,9 +119,9 @@
 	struct drm_display_mode *mode = NULL;
 	struct qxl_head *head;
 
-	if (!qdev->monitors_config)
+	if (!qdev->client_monitors_config)
 		return 0;
-	head = &qdev->monitors_config->heads[h];
+	head = &qdev->client_monitors_config->heads[h];
 
 	mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false,
 			    false);
@@ -499,7 +448,7 @@
 	for (i = 0 ; i < qdev->monitors_config->count ; ++i) {
 		struct qxl_head *head = &qdev->monitors_config->heads[i];
 
-		if (head->y > 8192 || head->y < head->x ||
+		if (head->y > 8192 || head->x > 8192 ||
 		    head->width > 8192 || head->height > 8192) {
 			DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
 				  i, head->width, head->height,
@@ -510,16 +459,19 @@
 	qxl_io_monitors_config(qdev);
 }
 
-static void qxl_monitors_config_set_single(struct qxl_device *qdev,
-					   unsigned x, unsigned y,
-					   unsigned width, unsigned height)
+static void qxl_monitors_config_set(struct qxl_device *qdev,
+				    int index,
+				    unsigned x, unsigned y,
+				    unsigned width, unsigned height,
+				    unsigned surf_id)
 {
-	DRM_DEBUG("%dx%d+%d+%d\n", width, height, x, y);
-	qdev->monitors_config->count = 1;
-	qdev->monitors_config->heads[0].x = x;
-	qdev->monitors_config->heads[0].y = y;
-	qdev->monitors_config->heads[0].width = width;
-	qdev->monitors_config->heads[0].height = height;
+	DRM_DEBUG_KMS("%d:%dx%d+%d+%d\n", index, width, height, x, y);
+	qdev->monitors_config->heads[index].x = x;
+	qdev->monitors_config->heads[index].y = y;
+	qdev->monitors_config->heads[index].width = width;
+	qdev->monitors_config->heads[index].height = height;
+	qdev->monitors_config->heads[index].surface_id = surf_id;
+
 }
 
 static int qxl_crtc_mode_set(struct drm_crtc *crtc,
@@ -533,10 +485,11 @@
 	struct qxl_mode *m = (void *)mode->private;
 	struct qxl_framebuffer *qfb;
 	struct qxl_bo *bo, *old_bo = NULL;
+	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
 	uint32_t width, height, base_offset;
 	bool recreate_primary = false;
 	int ret;
-
+	int surf_id;
 	if (!crtc->fb) {
 		DRM_DEBUG_KMS("No FB bound\n");
 		return 0;
@@ -560,7 +513,8 @@
 		  adjusted_mode->hdisplay,
 		  adjusted_mode->vdisplay);
 
-	recreate_primary = true;
+	if (qcrtc->index == 0)
+		recreate_primary = true;
 
 	width = mode->hdisplay;
 	height = mode->vdisplay;
@@ -581,8 +535,11 @@
 			   "recreate primary: %dx%d (was %dx%d,%d,%d)\n",
 			   width, height, bo->surf.width,
 			   bo->surf.height, bo->surf.stride, bo->surf.format);
-		qxl_io_create_primary(qdev, width, height, base_offset, bo);
+		qxl_io_create_primary(qdev, base_offset, bo);
 		bo->is_primary = true;
+		surf_id = 0;
+	} else {
+		surf_id = bo->surface_id;
 	}
 
 	if (old_bo && old_bo != bo) {
@@ -592,11 +549,9 @@
 		qxl_bo_unreserve(old_bo);
 	}
 
-	if (qdev->monitors_config->count == 0) {
-		qxl_monitors_config_set_single(qdev, x, y,
-					       mode->hdisplay,
-					       mode->vdisplay);
-	}
+	qxl_monitors_config_set(qdev, qcrtc->index, x, y,
+				mode->hdisplay,
+				mode->vdisplay, surf_id);
 	return 0;
 }
 
@@ -612,15 +567,36 @@
 	DRM_DEBUG("\n");
 }
 
+static void qxl_crtc_disable(struct drm_crtc *crtc)
+{
+	struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	struct qxl_device *qdev = dev->dev_private;
+	if (crtc->fb) {
+		struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb);
+		struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
+		int ret;
+		ret = qxl_bo_reserve(bo, false);
+		qxl_bo_unpin(bo);
+		qxl_bo_unreserve(bo);
+		crtc->fb = NULL;
+	}
+
+	qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);
+
+	qxl_send_monitors_config(qdev);
+}
+
 static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
 	.dpms = qxl_crtc_dpms,
+	.disable = qxl_crtc_disable,
 	.mode_fixup = qxl_crtc_mode_fixup,
 	.mode_set = qxl_crtc_mode_set,
 	.prepare = qxl_crtc_prepare,
 	.commit = qxl_crtc_commit,
 };
 
-static int qdev_crtc_init(struct drm_device *dev, int num_crtc)
+static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
 {
 	struct qxl_crtc *qxl_crtc;
 
@@ -629,7 +605,7 @@
 		return -ENOMEM;
 
 	drm_crtc_init(dev, &qxl_crtc->base, &qxl_crtc_funcs);
-
+	qxl_crtc->index = crtc_id;
 	drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256);
 	drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
 	return 0;
@@ -657,18 +633,13 @@
 		struct drm_encoder *encoder)
 {
 	int i;
+	struct qxl_output *output = drm_encoder_to_qxl_output(encoder);
 	struct qxl_head *head;
 	struct drm_display_mode *mode;
 
 	BUG_ON(!encoder);
 	/* TODO: ugly, do better */
-	for (i = 0 ; (encoder->possible_crtcs != (1 << i)) && i < 32; ++i)
-		;
-	if (encoder->possible_crtcs != (1 << i)) {
-		DRM_ERROR("encoder has wrong possible_crtcs: %x\n",
-			  encoder->possible_crtcs);
-		return;
-	}
+	i = output->index;
 	if (!qdev->monitors_config ||
 	    qdev->monitors_config->max_allowed <= i) {
 		DRM_ERROR(
@@ -686,7 +657,6 @@
 		DRM_DEBUG("missing for multiple monitors: no head holes\n");
 	head = &qdev->monitors_config->heads[i];
 	head->id = i;
-	head->surface_id = 0;
 	if (encoder->crtc->enabled) {
 		mode = &encoder->crtc->mode;
 		head->width = mode->hdisplay;
@@ -701,8 +671,8 @@
 		head->x = 0;
 		head->y = 0;
 	}
-	DRM_DEBUG("setting head %d to +%d+%d %dx%d\n",
-		  i, head->x, head->y, head->width, head->height);
+	DRM_DEBUG_KMS("setting head %d to +%d+%d %dx%d out of %d\n",
+		      i, head->x, head->y, head->width, head->height, qdev->monitors_config->count);
 	head->flags = 0;
 	/* TODO - somewhere else to call this for multiple monitors
 	 * (config_commit?) */
@@ -797,8 +767,9 @@
 
 	/* The first monitor is always connected */
 	connected = (output->index == 0) ||
-		    (qdev->monitors_config &&
-		     qdev->monitors_config->count > output->index);
+		    (qdev->client_monitors_config &&
+		     qdev->client_monitors_config->count > output->index &&
+		     qxl_head_enabled(&qdev->client_monitors_config->heads[output->index]));
 
 	DRM_DEBUG("\n");
 	return connected ? connector_status_connected
@@ -862,6 +833,8 @@
 	drm_encoder_init(dev, &qxl_output->enc, &qxl_enc_funcs,
 			 DRM_MODE_ENCODER_VIRTUAL);
 
+	/* we get HPD via client monitors config */
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
 	encoder->possible_crtcs = 1 << num_output;
 	drm_mode_connector_attach_encoder(&qxl_output->base,
 					  &qxl_output->enc);
@@ -901,16 +874,14 @@
 	.fb_create = qxl_user_framebuffer_create,
 };
 
-int qxl_modeset_init(struct qxl_device *qdev)
+int qxl_create_monitors_object(struct qxl_device *qdev)
 {
-	int i;
 	int ret;
 	struct drm_gem_object *gobj;
-	int max_allowed = QXL_NUM_OUTPUTS;
+	int max_allowed = qxl_num_crtc;
 	int monitors_config_size = sizeof(struct qxl_monitors_config) +
-				   max_allowed * sizeof(struct qxl_head);
+		max_allowed * sizeof(struct qxl_head);
 
-	drm_mode_config_init(qdev->ddev);
 	ret = qxl_gem_object_create(qdev, monitors_config_size, 0,
 				    QXL_GEM_DOMAIN_VRAM,
 				    false, false, NULL, &gobj);
@@ -919,13 +890,59 @@
 		return -ENOMEM;
 	}
 	qdev->monitors_config_bo = gem_to_qxl_bo(gobj);
+
+	ret = qxl_bo_reserve(qdev->monitors_config_bo, false);
+	if (ret)
+		return ret;
+
+	ret = qxl_bo_pin(qdev->monitors_config_bo, QXL_GEM_DOMAIN_VRAM, NULL);
+	if (ret) {
+		qxl_bo_unreserve(qdev->monitors_config_bo);
+		return ret;
+	}
+
+	qxl_bo_unreserve(qdev->monitors_config_bo);
+
 	qxl_bo_kmap(qdev->monitors_config_bo, NULL);
+
 	qdev->monitors_config = qdev->monitors_config_bo->kptr;
 	qdev->ram_header->monitors_config =
 		qxl_bo_physical_address(qdev, qdev->monitors_config_bo, 0);
 
 	memset(qdev->monitors_config, 0, monitors_config_size);
 	qdev->monitors_config->max_allowed = max_allowed;
+	return 0;
+}
+
+int qxl_destroy_monitors_object(struct qxl_device *qdev)
+{
+	int ret;
+
+	qdev->monitors_config = NULL;
+	qdev->ram_header->monitors_config = 0;
+
+	qxl_bo_kunmap(qdev->monitors_config_bo);
+	ret = qxl_bo_reserve(qdev->monitors_config_bo, false);
+	if (ret)
+		return ret;
+
+	qxl_bo_unpin(qdev->monitors_config_bo);
+	qxl_bo_unreserve(qdev->monitors_config_bo);
+
+	qxl_bo_unref(&qdev->monitors_config_bo);
+	return 0;
+}
+
+int qxl_modeset_init(struct qxl_device *qdev)
+{
+	int i;
+	int ret;
+
+	drm_mode_config_init(qdev->ddev);
+
+	ret = qxl_create_monitors_object(qdev);
+	if (ret)
+		return ret;
 
 	qdev->ddev->mode_config.funcs = (void *)&qxl_mode_funcs;
 
@@ -936,7 +953,7 @@
 	qdev->ddev->mode_config.max_height = 8192;
 
 	qdev->ddev->mode_config.fb_base = qdev->vram_base;
-	for (i = 0 ; i < QXL_NUM_OUTPUTS; ++i) {
+	for (i = 0 ; i < qxl_num_crtc; ++i) {
 		qdev_crtc_init(qdev->ddev, i);
 		qdev_output_init(qdev->ddev, i);
 	}
@@ -953,6 +970,8 @@
 void qxl_modeset_fini(struct qxl_device *qdev)
 {
 	qxl_fbdev_fini(qdev);
+
+	qxl_destroy_monitors_object(qdev);
 	if (qdev->mode_info.mode_config_initialized) {
 		drm_mode_config_cleanup(qdev->ddev);
 		qdev->mode_info.mode_config_initialized = false;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index aa291d8a..df0b577 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -33,8 +33,9 @@
 
 #include "drmP.h"
 #include "drm/drm.h"
-
+#include "drm_crtc_helper.h"
 #include "qxl_drv.h"
+#include "qxl_object.h"
 
 extern int qxl_max_ioctls;
 static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
@@ -47,10 +48,14 @@
 MODULE_DEVICE_TABLE(pci, pciidlist);
 
 static int qxl_modeset = -1;
+int qxl_num_crtc = 4;
 
 MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
 module_param_named(modeset, qxl_modeset, int, 0400);
 
+MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)");
+module_param_named(num_heads, qxl_num_crtc, int, 0400);
+
 static struct drm_driver qxl_driver;
 static struct pci_driver qxl_pci_driver;
 
@@ -73,13 +78,6 @@
 	drm_put_dev(dev);
 }
 
-static struct pci_driver qxl_pci_driver = {
-	 .name = DRIVER_NAME,
-	 .id_table = pciidlist,
-	 .probe = qxl_pci_probe,
-	 .remove = qxl_pci_remove,
-};
-
 static const struct file_operations qxl_fops = {
 	.owner = THIS_MODULE,
 	.open = drm_open,
@@ -90,6 +88,130 @@
 	.mmap = qxl_mmap,
 };
 
+static int qxl_drm_freeze(struct drm_device *dev)
+{
+	struct pci_dev *pdev = dev->pdev;
+	struct qxl_device *qdev = dev->dev_private;
+	struct drm_crtc *crtc;
+
+	drm_kms_helper_poll_disable(dev);
+
+	console_lock();
+	qxl_fbdev_set_suspend(qdev, 1);
+	console_unlock();
+
+	/* unpin the front buffers */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+		if (crtc->enabled)
+			(*crtc_funcs->disable)(crtc);
+	}
+
+	qxl_destroy_monitors_object(qdev);
+	qxl_surf_evict(qdev);
+	qxl_vram_evict(qdev);
+
+	while (!qxl_check_idle(qdev->command_ring));
+	while (!qxl_check_idle(qdev->release_ring))
+		qxl_queue_garbage_collect(qdev, 1);
+
+	pci_save_state(pdev);
+
+	return 0;
+}
+
+static int qxl_drm_resume(struct drm_device *dev, bool thaw)
+{
+	struct qxl_device *qdev = dev->dev_private;
+
+	qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
+	if (!thaw) {
+		qxl_reinit_memslots(qdev);
+		qxl_ring_init_hdr(qdev->release_ring);
+	}
+
+	qxl_create_monitors_object(qdev);
+	drm_helper_resume_force_mode(dev);
+
+	console_lock();
+	qxl_fbdev_set_suspend(qdev, 0);
+	console_unlock();
+
+	drm_kms_helper_poll_enable(dev);
+	return 0;
+}
+
+static int qxl_pm_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+	int error;
+
+	error = qxl_drm_freeze(drm_dev);
+	if (error)
+		return error;
+
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+	return 0;
+}
+
+static int qxl_pm_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	if (pci_enable_device(pdev)) {
+		return -EIO;
+	}
+
+	return qxl_drm_resume(drm_dev, false);
+}
+
+static int qxl_pm_thaw(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+	return qxl_drm_resume(drm_dev, true);
+}
+
+static int qxl_pm_freeze(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+	return qxl_drm_freeze(drm_dev);
+}
+
+static int qxl_pm_restore(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+	struct qxl_device *qdev = drm_dev->dev_private;
+
+	qxl_io_reset(qdev);
+	return qxl_drm_resume(drm_dev, false);
+}
+
+static const struct dev_pm_ops qxl_pm_ops = {
+	.suspend = qxl_pm_suspend,
+	.resume = qxl_pm_resume,
+	.freeze = qxl_pm_freeze,
+	.thaw = qxl_pm_thaw,
+	.poweroff = qxl_pm_freeze,
+	.restore = qxl_pm_restore,
+};
+static struct pci_driver qxl_pci_driver = {
+	 .name = DRIVER_NAME,
+	 .id_table = pciidlist,
+	 .probe = qxl_pci_probe,
+	 .remove = qxl_pci_remove,
+	 .driver.pm = &qxl_pm_ops,
+};
+
 static struct drm_driver qxl_driver = {
 	.driver_features = DRIVER_GEM | DRIVER_MODESET |
 			   DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 43d06ab..aacb791 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -55,11 +55,10 @@
 #define DRIVER_MINOR 1
 #define DRIVER_PATCHLEVEL 0
 
-#define QXL_NUM_OUTPUTS 1
-
 #define QXL_DEBUGFS_MAX_COMPONENTS		32
 
 extern int qxl_log_level;
+extern int qxl_num_crtc;
 
 enum {
 	QXL_INFO_LEVEL = 1,
@@ -139,6 +138,7 @@
 
 struct qxl_crtc {
 	struct drm_crtc base;
+	int index;
 	int cur_x;
 	int cur_y;
 };
@@ -156,7 +156,7 @@
 
 #define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base)
 #define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base)
-#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, base)
+#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc)
 #define to_qxl_framebuffer(x) container_of(x, struct qxl_framebuffer, base)
 
 struct qxl_mman {
@@ -331,6 +331,10 @@
 int qxl_bo_init(struct qxl_device *qdev);
 void qxl_bo_fini(struct qxl_device *qdev);
 
+void qxl_reinit_memslots(struct qxl_device *qdev);
+int qxl_surf_evict(struct qxl_device *qdev);
+int qxl_vram_evict(struct qxl_device *qdev);
+
 struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header,
 				 int element_size,
 				 int n_elements,
@@ -338,6 +342,8 @@
 				 bool set_prod_notify,
 				 wait_queue_head_t *push_event);
 void qxl_ring_free(struct qxl_ring *ring);
+void qxl_ring_init_hdr(struct qxl_ring *ring);
+int qxl_check_idle(struct qxl_ring *ring);
 
 static inline void *
 qxl_fb_virtual_address(struct qxl_device *qdev, unsigned long physical)
@@ -365,6 +371,7 @@
 int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
 				  struct drm_file *file_priv,
 				  uint32_t *handle);
+void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state);
 
 /* qxl_display.c */
 int
@@ -374,6 +381,8 @@
 		     struct drm_gem_object *obj);
 void qxl_display_read_client_monitors_config(struct qxl_device *qdev);
 void qxl_send_monitors_config(struct qxl_device *qdev);
+int qxl_create_monitors_object(struct qxl_device *qdev);
+int qxl_destroy_monitors_object(struct qxl_device *qdev);
 
 /* used by qxl_debugfs only */
 void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev);
@@ -435,7 +444,7 @@
 /* qxl io operations (qxl_cmd.c) */
 
 void qxl_io_create_primary(struct qxl_device *qdev,
-			   unsigned width, unsigned height, unsigned offset,
+			   unsigned offset,
 			   struct qxl_bo *bo);
 void qxl_io_destroy_primary(struct qxl_device *qdev);
 void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id);
@@ -528,6 +537,7 @@
 
 /* qxl_fb.c */
 int qxl_fb_init(struct qxl_device *qdev);
+bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj);
 
 int qxl_debugfs_add_files(struct qxl_device *qdev,
 			  struct drm_info_list *files,
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index 4b955b0..76f39d8 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -538,7 +538,7 @@
 	qfbdev->helper.funcs = &qxl_fb_helper_funcs;
 
 	ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper,
-				 1 /* num_crtc - QXL supports just 1 */,
+				 qxl_num_crtc /* num_crtc - QXL supports just 1 */,
 				 QXLFB_CONN_LIMIT);
 	if (ret) {
 		kfree(qfbdev);
@@ -560,4 +560,14 @@
 	qdev->mode_info.qfbdev = NULL;
 }
 
+void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)
+{
+	fb_set_suspend(qdev->mode_info.qfbdev->helper.fbdev, state);
+}
 
+bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj)
+{
+	if (qobj == gem_to_qxl_bo(qdev->mode_info.qfbdev->qfb.obj))
+		return true;
+	return false;
+}
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index a4b71b2..27f45e4 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -171,6 +171,11 @@
 		if (user_cmd.command_size > PAGE_SIZE - sizeof(union qxl_release_info))
 			return -EINVAL;
 
+		if (!access_ok(VERIFY_READ,
+			       (void *)(unsigned long)user_cmd.command,
+			       user_cmd.command_size))
+			return -EFAULT;
+
 		ret = qxl_alloc_release_reserved(qdev,
 						 sizeof(union qxl_release_info) +
 						 user_cmd.command_size,
@@ -183,6 +188,12 @@
 		/* TODO copy slow path code from i915 */
 		fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
 		unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)user_cmd.command, user_cmd.command_size);
+
+		{
+			struct qxl_drawable *draw = fb_cmd;
+
+			draw->mm_time = qdev->rom->mm_clock;
+		}
 		qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
 		if (unwritten) {
 			DRM_ERROR("got unwritten %d\n", unwritten);
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index e27ce2a..9e8da9e 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -26,6 +26,7 @@
 #include "qxl_drv.h"
 #include "qxl_object.h"
 
+#include <drm/drm_crtc_helper.h>
 #include <linux/io-mapping.h>
 
 int qxl_log_level;
@@ -72,21 +73,28 @@
 	return true;
 }
 
+static void setup_hw_slot(struct qxl_device *qdev, int slot_index,
+			  struct qxl_memslot *slot)
+{
+	qdev->ram_header->mem_slot.mem_start = slot->start_phys_addr;
+	qdev->ram_header->mem_slot.mem_end = slot->end_phys_addr;
+	qxl_io_memslot_add(qdev, slot_index);
+}
+
 static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset,
 	unsigned long start_phys_addr, unsigned long end_phys_addr)
 {
 	uint64_t high_bits;
 	struct qxl_memslot *slot;
 	uint8_t slot_index;
-	struct qxl_ram_header *ram_header = qdev->ram_header;
 
 	slot_index = qdev->rom->slots_start + slot_index_offset;
 	slot = &qdev->mem_slots[slot_index];
 	slot->start_phys_addr = start_phys_addr;
 	slot->end_phys_addr = end_phys_addr;
-	ram_header->mem_slot.mem_start = slot->start_phys_addr;
-	ram_header->mem_slot.mem_end = slot->end_phys_addr;
-	qxl_io_memslot_add(qdev, slot_index);
+
+	setup_hw_slot(qdev, slot_index, slot);
+
 	slot->generation = qdev->rom->slot_generation;
 	high_bits = slot_index << qdev->slot_gen_bits;
 	high_bits |= slot->generation;
@@ -95,6 +103,12 @@
 	return slot_index;
 }
 
+void qxl_reinit_memslots(struct qxl_device *qdev)
+{
+	setup_hw_slot(qdev, qdev->main_mem_slot, &qdev->mem_slots[qdev->main_mem_slot]);
+	setup_hw_slot(qdev, qdev->surfaces_mem_slot, &qdev->mem_slots[qdev->surfaces_mem_slot]);
+}
+
 static void qxl_gc_work(struct work_struct *work)
 {
 	struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work);
@@ -294,6 +308,8 @@
 		goto out;
 	}
 
+	drm_kms_helper_poll_init(qdev->ddev);
+
 	return 0;
 out:
 	kfree(qdev);
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index d9b12e7..1191fe7 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -363,3 +363,13 @@
 		return ret;
 	return 0;
 }
+
+int qxl_surf_evict(struct qxl_device *qdev)
+{
+	return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
+}
+
+int qxl_vram_evict(struct qxl_device *qdev)
+{
+	return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_VRAM);
+}
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index c7ad4b9..b9d3b43 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1841,6 +1841,9 @@
 	atombios_crtc_set_base(crtc, x, y, old_fb);
 	atombios_overscan_setup(crtc, mode, adjusted_mode);
 	atombios_scaler_setup(crtc);
+	/* update the hw version fpr dpm */
+	radeon_crtc->hw_mode = *adjusted_mode;
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index bab0185..0bfd55e 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -2059,6 +2059,19 @@
 	}
 }
 
+bool btc_dpm_vblank_too_short(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
+	u32 switch_limit = pi->mem_gddr5 ? 450 : 100;
+
+	if (vblank_time < switch_limit)
+		return true;
+	else
+		return false;
+
+}
+
 static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
 					 struct radeon_ps *rps)
 {
@@ -2068,7 +2081,8 @@
 	u32 mclk, sclk;
 	u16 vddc, vddci;
 
-	if (rdev->pm.dpm.new_active_crtc_count > 1)
+	if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
+	    btc_dpm_vblank_too_short(rdev))
 		disable_mclk_switching = true;
 	else
 		disable_mclk_switching = false;
@@ -2326,14 +2340,11 @@
 		return ret;
 	}
 
-#if 0
-	/* XXX */
-	ret = rv770_unrestrict_performance_levels_after_switch(rdev);
+	ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
 	if (ret) {
-		DRM_ERROR("rv770_unrestrict_performance_levels_after_switch failed\n");
+		DRM_ERROR("rv770_dpm_force_performance_level failed\n");
 		return ret;
 	}
-#endif
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index ed1d910..6dacec4 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -22,7 +22,6 @@
  * Authors: Alex Deucher
  */
 #include <linux/firmware.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include "drmP.h"
@@ -742,7 +741,6 @@
  */
 static int cik_init_microcode(struct radeon_device *rdev)
 {
-	struct platform_device *pdev;
 	const char *chip_name;
 	size_t pfp_req_size, me_req_size, ce_req_size,
 		mec_req_size, rlc_req_size, mc_req_size,
@@ -752,13 +750,6 @@
 
 	DRM_DEBUG("\n");
 
-	pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
-	err = IS_ERR(pdev);
-	if (err) {
-		printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
-		return -EINVAL;
-	}
-
 	switch (rdev->family) {
 	case CHIP_BONAIRE:
 		chip_name = "BONAIRE";
@@ -794,7 +785,7 @@
 	DRM_INFO("Loading %s Microcode\n", chip_name);
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
-	err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->pfp_fw->size != pfp_req_size) {
@@ -806,7 +797,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
-	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->me_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->me_fw->size != me_req_size) {
@@ -817,7 +808,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name);
-	err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->ce_fw->size != ce_req_size) {
@@ -828,7 +819,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name);
-	err = request_firmware(&rdev->mec_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->mec_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->mec_fw->size != mec_req_size) {
@@ -839,7 +830,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name);
-	err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->rlc_fw->size != rlc_req_size) {
@@ -850,7 +841,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name);
-	err = request_firmware(&rdev->sdma_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->sdma_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->sdma_fw->size != sdma_req_size) {
@@ -863,7 +854,7 @@
 	/* No MC ucode on APUs */
 	if (!(rdev->flags & RADEON_IS_IGP)) {
 		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
-		err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+		err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev);
 		if (err)
 			goto out;
 		if (rdev->mc_fw->size != mc_req_size) {
@@ -875,8 +866,6 @@
 	}
 
 out:
-	platform_device_unregister(pdev);
-
 	if (err) {
 		if (err != -EINVAL)
 			printk(KERN_ERR
@@ -4453,6 +4442,29 @@
 }
 
 /**
+ * cik_vm_decode_fault - print human readable fault info
+ *
+ * @rdev: radeon_device pointer
+ * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value
+ * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value
+ *
+ * Print human readable fault information (CIK).
+ */
+static void cik_vm_decode_fault(struct radeon_device *rdev,
+				u32 status, u32 addr, u32 mc_client)
+{
+	u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT;
+	u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT;
+	u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT;
+	char *block = (char *)&mc_client;
+
+	printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n",
+	       protections, vmid, addr,
+	       (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read",
+	       block, mc_id);
+}
+
+/**
  * cik_vm_flush - cik vm flush using the CP
  *
  * @rdev: radeon_device pointer
@@ -5507,6 +5519,7 @@
 	u32 ring_index;
 	bool queue_hotplug = false;
 	bool queue_reset = false;
+	u32 addr, status, mc_client;
 
 	if (!rdev->ih.enabled || rdev->shutdown)
 		return IRQ_NONE;
@@ -5742,11 +5755,15 @@
 			break;
 		case 146:
 		case 147:
+			addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
+			status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS);
+			mc_client = RREG32(VM_CONTEXT1_PROTECTION_FAULT_MCCLIENT);
 			dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
 			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
-				RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+				addr);
 			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
-				RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+				status);
+			cik_vm_decode_fault(rdev, status, addr, mc_client);
 			/* reset addr and status */
 			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
 			break;
@@ -6961,7 +6978,7 @@
 
 	/* programm the VCPU memory controller bits 0-27 */
 	addr = rdev->uvd.gpu_addr >> 3;
-	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
+	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3;
 	WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
 	WREG32(UVD_VCPU_CACHE_SIZE0, size);
 
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 63514b9..7e9275e 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -136,6 +136,22 @@
 #define VM_INVALIDATE_RESPONSE				0x147c
 
 #define	VM_CONTEXT1_PROTECTION_FAULT_STATUS		0x14DC
+#define		PROTECTIONS_MASK			(0xf << 0)
+#define		PROTECTIONS_SHIFT			0
+		/* bit 0: range
+		 * bit 1: pde0
+		 * bit 2: valid
+		 * bit 3: read
+		 * bit 4: write
+		 */
+#define		MEMORY_CLIENT_ID_MASK			(0xff << 12)
+#define		MEMORY_CLIENT_ID_SHIFT			12
+#define		MEMORY_CLIENT_RW_MASK			(1 << 24)
+#define		MEMORY_CLIENT_RW_SHIFT			24
+#define		FAULT_VMID_MASK				(0xf << 25)
+#define		FAULT_VMID_SHIFT			25
+
+#define	VM_CONTEXT1_PROTECTION_FAULT_MCCLIENT		0x14E4
 
 #define	VM_CONTEXT1_PROTECTION_FAULT_ADDR		0x14FC
 
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
index 5ada922..9bcdd17 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.c
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -2014,9 +2014,9 @@
 	if (eg_pi->pcie_performance_request)
 		cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
 
-	ret = rv770_unrestrict_performance_levels_after_switch(rdev);
+	ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
 	if (ret) {
-		DRM_ERROR("rv770_unrestrict_performance_levels_after_switch failed\n");
+		DRM_ERROR("rv770_dpm_force_performance_level failed\n");
 		return ret;
 	}
 
@@ -2174,3 +2174,16 @@
 	kfree(rdev->pm.dpm.ps);
 	kfree(rdev->pm.dpm.priv);
 }
+
+bool cypress_dpm_vblank_too_short(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
+	u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
+
+	if (vblank_time < switch_limit)
+		return true;
+	else
+		return false;
+
+}
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 0de5b74..038dcac 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -139,6 +139,8 @@
 void evergreen_program_aspm(struct radeon_device *rdev);
 extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev,
 				     int ring, u32 cp_int_cntl);
+extern void cayman_vm_decode_fault(struct radeon_device *rdev,
+				   u32 status, u32 addr);
 
 static const u32 evergreen_golden_registers[] =
 {
@@ -1504,8 +1506,8 @@
 	struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage;
 
 	if (voltage->type == VOLTAGE_SW) {
-		/* 0xff01 is a flag rather then an actual voltage */
-		if (voltage->voltage == 0xff01)
+		/* 0xff0x are flags rather then an actual voltage */
+		if ((voltage->voltage & 0xff00) == 0xff00)
 			return;
 		if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) {
 			radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
@@ -1525,8 +1527,8 @@
 			voltage = &rdev->pm.power_state[req_ps_idx].
 				clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].voltage;
 
-		/* 0xff01 is a flag rather then an actual voltage */
-		if (voltage->vddci == 0xff01)
+		/* 0xff0x are flags rather then an actual voltage */
+		if ((voltage->vddci & 0xff00) == 0xff00)
 			return;
 		if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) {
 			radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI);
@@ -4043,8 +4045,6 @@
 
 	if (rdev->flags & RADEON_IS_IGP) {
 		mask |= GFX_POWER_GATING_ENABLE | GFX_POWER_GATING_SRC;
-		if (rdev->family == CHIP_ARUBA)
-			mask |= DYN_PER_SIMD_PG_ENABLE | LB_CNT_SPIM_ACTIVE | LOAD_BALANCE_ENABLE;
 	}
 
 	WREG32(RLC_CNTL, mask);
@@ -4588,6 +4588,7 @@
 	bool queue_hotplug = false;
 	bool queue_hdmi = false;
 	bool queue_thermal = false;
+	u32 status, addr;
 
 	if (!rdev->ih.enabled || rdev->shutdown)
 		return IRQ_NONE;
@@ -4874,11 +4875,14 @@
 			break;
 		case 146:
 		case 147:
+			addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
+			status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS);
 			dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
 			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
-				RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+				addr);
 			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
-				RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+				status);
+			cayman_vm_decode_fault(rdev, status, addr);
 			/* reset addr and status */
 			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
 			break;
@@ -5511,6 +5515,9 @@
 	 */
 	bool fusion_platform = false;
 
+	if (radeon_aspm == 0)
+		return;
+
 	if (!(rdev->flags & RADEON_IS_PCIE))
 		return;
 
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index b9c6f76..b0d3fb3 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -177,6 +177,9 @@
 	uint32_t offset;
 	ssize_t err;
 
+	if (!dig || !dig->afmt)
+		return;
+
 	/* Silent, r600_hdmi_enable will raise WARN for us */
 	if (!dig->afmt->enabled)
 		return;
@@ -280,6 +283,9 @@
 	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 
+	if (!dig || !dig->afmt)
+		return;
+
 	/* Silent, r600_hdmi_enable will raise WARN for us */
 	if (enable && dig->afmt->enabled)
 		return;
diff --git a/drivers/gpu/drm/radeon/mkregtable.c b/drivers/gpu/drm/radeon/mkregtable.c
index 5a82b6b..af85299 100644
--- a/drivers/gpu/drm/radeon/mkregtable.c
+++ b/drivers/gpu/drm/radeon/mkregtable.c
@@ -373,19 +373,6 @@
 		pos = pos->next)
 
 /**
- * __list_for_each	-	iterate over a list
- * @pos:	the &struct list_head to use as a loop cursor.
- * @head:	the head for your list.
- *
- * This variant differs from list_for_each() in that it's the
- * simplest possible list iteration code, no prefetching is done.
- * Use this for code that knows the list to be very short (empty
- * or 1 entry) most of the time.
- */
-#define __list_for_each(pos, head) \
-	for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
  * list_for_each_prev	-	iterate over a list backwards
  * @pos:	the &struct list_head to use as a loop cursor.
  * @head:	the head for your list.
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index f30127c..56bd4f3 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -22,7 +22,6 @@
  * Authors: Alex Deucher
  */
 #include <linux/firmware.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <drm/drmP.h>
@@ -684,7 +683,6 @@
 
 int ni_init_microcode(struct radeon_device *rdev)
 {
-	struct platform_device *pdev;
 	const char *chip_name;
 	const char *rlc_chip_name;
 	size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size;
@@ -694,13 +692,6 @@
 
 	DRM_DEBUG("\n");
 
-	pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
-	err = IS_ERR(pdev);
-	if (err) {
-		printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
-		return -EINVAL;
-	}
-
 	switch (rdev->family) {
 	case CHIP_BARTS:
 		chip_name = "BARTS";
@@ -753,7 +744,7 @@
 	DRM_INFO("Loading %s Microcode\n", chip_name);
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
-	err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->pfp_fw->size != pfp_req_size) {
@@ -765,7 +756,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
-	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->me_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->me_fw->size != me_req_size) {
@@ -776,7 +767,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name);
-	err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->rlc_fw->size != rlc_req_size) {
@@ -789,7 +780,7 @@
 	/* no MC ucode on TN */
 	if (!(rdev->flags & RADEON_IS_IGP)) {
 		snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
-		err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+		err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev);
 		if (err)
 			goto out;
 		if (rdev->mc_fw->size != mc_req_size) {
@@ -802,7 +793,7 @@
 
 	if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) {
 		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
-		err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+		err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
 		if (err)
 			goto out;
 		if (rdev->smc_fw->size != smc_req_size) {
@@ -814,8 +805,6 @@
 	}
 
 out:
-	platform_device_unregister(pdev);
-
 	if (err) {
 		if (err != -EINVAL)
 			printk(KERN_ERR
@@ -2461,6 +2450,167 @@
 {
 }
 
+/**
+ * cayman_vm_decode_fault - print human readable fault info
+ *
+ * @rdev: radeon_device pointer
+ * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value
+ * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value
+ *
+ * Print human readable fault information (cayman/TN).
+ */
+void cayman_vm_decode_fault(struct radeon_device *rdev,
+			    u32 status, u32 addr)
+{
+	u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT;
+	u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT;
+	u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT;
+	char *block;
+
+	switch (mc_id) {
+	case 32:
+	case 16:
+	case 96:
+	case 80:
+	case 160:
+	case 144:
+	case 224:
+	case 208:
+		block = "CB";
+		break;
+	case 33:
+	case 17:
+	case 97:
+	case 81:
+	case 161:
+	case 145:
+	case 225:
+	case 209:
+		block = "CB_FMASK";
+		break;
+	case 34:
+	case 18:
+	case 98:
+	case 82:
+	case 162:
+	case 146:
+	case 226:
+	case 210:
+		block = "CB_CMASK";
+		break;
+	case 35:
+	case 19:
+	case 99:
+	case 83:
+	case 163:
+	case 147:
+	case 227:
+	case 211:
+		block = "CB_IMMED";
+		break;
+	case 36:
+	case 20:
+	case 100:
+	case 84:
+	case 164:
+	case 148:
+	case 228:
+	case 212:
+		block = "DB";
+		break;
+	case 37:
+	case 21:
+	case 101:
+	case 85:
+	case 165:
+	case 149:
+	case 229:
+	case 213:
+		block = "DB_HTILE";
+		break;
+	case 38:
+	case 22:
+	case 102:
+	case 86:
+	case 166:
+	case 150:
+	case 230:
+	case 214:
+		block = "SX";
+		break;
+	case 39:
+	case 23:
+	case 103:
+	case 87:
+	case 167:
+	case 151:
+	case 231:
+	case 215:
+		block = "DB_STEN";
+		break;
+	case 40:
+	case 24:
+	case 104:
+	case 88:
+	case 232:
+	case 216:
+	case 168:
+	case 152:
+		block = "TC_TFETCH";
+		break;
+	case 41:
+	case 25:
+	case 105:
+	case 89:
+	case 233:
+	case 217:
+	case 169:
+	case 153:
+		block = "TC_VFETCH";
+		break;
+	case 42:
+	case 26:
+	case 106:
+	case 90:
+	case 234:
+	case 218:
+	case 170:
+	case 154:
+		block = "VC";
+		break;
+	case 112:
+		block = "CP";
+		break;
+	case 113:
+	case 114:
+		block = "SH";
+		break;
+	case 115:
+		block = "VGT";
+		break;
+	case 178:
+		block = "IH";
+		break;
+	case 51:
+		block = "RLC";
+		break;
+	case 55:
+		block = "DMA";
+		break;
+	case 56:
+		block = "HDP";
+		break;
+	default:
+		block = "unknown";
+		break;
+	}
+
+	printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n",
+	       protections, vmid, addr,
+	       (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read",
+	       block, mc_id);
+}
+
 #define R600_ENTRY_VALID   (1 << 0)
 #define R600_PTE_SYSTEM    (1 << 1)
 #define R600_PTE_SNOOPED   (1 << 2)
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 777d17e..559cf24 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -28,6 +28,7 @@
 #include "ni_dpm.h"
 #include "atom.h"
 #include <linux/math64.h>
+#include <linux/seq_file.h>
 
 #define MC_CG_ARB_FREQ_F0           0x0a
 #define MC_CG_ARB_FREQ_F1           0x0b
@@ -764,6 +765,19 @@
 	ni_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage);
 }
 
+bool ni_dpm_vblank_too_short(struct radeon_device *rdev)
+{
+	struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
+	u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
+
+	if (vblank_time < switch_limit)
+		return true;
+	else
+		return false;
+
+}
+
 static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
 					struct radeon_ps *rps)
 {
@@ -774,7 +788,8 @@
 	u16 vddc, vddci;
 	int i;
 
-	if (rdev->pm.dpm.new_active_crtc_count > 1)
+	if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
+	    ni_dpm_vblank_too_short(rdev))
 		disable_mclk_switching = true;
 	else
 		disable_mclk_switching = false;
@@ -1036,16 +1051,38 @@
 		0 : -EINVAL;
 }
 
-#if 0
-static int ni_unrestrict_performance_levels_after_switch(struct radeon_device *rdev)
+int ni_dpm_force_performance_level(struct radeon_device *rdev,
+				   enum radeon_dpm_forced_level level)
 {
-	if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
-		return -EINVAL;
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct ni_ps *ps = ni_get_ps(rps);
+	u32 levels;
 
-	return (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) == PPSMC_Result_OK) ?
-		0 : -EINVAL;
+	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+		if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+			return -EINVAL;
+
+		if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
+			return -EINVAL;
+	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+		if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
+			return -EINVAL;
+
+		levels = ps->performance_level_count - 1;
+		if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+			return -EINVAL;
+	} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
+		if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
+			return -EINVAL;
+
+		if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+			return -EINVAL;
+	}
+
+	rdev->pm.dpm.forced_level = level;
+
+	return 0;
 }
-#endif
 
 static void ni_stop_smc(struct radeon_device *rdev)
 {
@@ -3832,14 +3869,11 @@
 		return ret;
 	}
 
-#if 0
-	/* XXX */
-	ret = ni_unrestrict_performance_levels_after_switch(rdev);
+	ret = ni_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
 	if (ret) {
-		DRM_ERROR("ni_unrestrict_performance_levels_after_switch failed\n");
+		DRM_ERROR("ni_dpm_force_performance_level failed\n");
 		return ret;
 	}
-#endif
 
 	return 0;
 }
@@ -4292,6 +4326,26 @@
 	r600_dpm_print_ps_status(rdev, rps);
 }
 
+void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						    struct seq_file *m)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct ni_ps *ps = ni_get_ps(rps);
+	struct rv7xx_pl *pl;
+	u32 current_index =
+		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+		CURRENT_STATE_INDEX_SHIFT;
+
+	if (current_index >= ps->performance_level_count) {
+		seq_printf(m, "invalid dpm profile %d\n", current_index);
+	} else {
+		pl = &ps->performance_levels[current_index];
+		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+		seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+			   current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+	}
+}
+
 u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
 {
 	struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
diff --git a/drivers/gpu/drm/radeon/ni_dpm.h b/drivers/gpu/drm/radeon/ni_dpm.h
index ac1c7ab..6bbee91 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.h
+++ b/drivers/gpu/drm/radeon/ni_dpm.h
@@ -245,4 +245,6 @@
 					  struct radeon_ps *new_ps,
 					  struct radeon_ps *old_ps);
 
+bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
+
 #endif
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
index 95693c7..22421bc 100644
--- a/drivers/gpu/drm/radeon/nid.h
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -133,6 +133,22 @@
 #define VM_CONTEXT1_CNTL2				0x1434
 #define VM_INVALIDATE_REQUEST				0x1478
 #define VM_INVALIDATE_RESPONSE				0x147c
+#define	VM_CONTEXT1_PROTECTION_FAULT_ADDR		0x14FC
+#define	VM_CONTEXT1_PROTECTION_FAULT_STATUS		0x14DC
+#define		PROTECTIONS_MASK			(0xf << 0)
+#define		PROTECTIONS_SHIFT			0
+		/* bit 0: range
+		 * bit 2: pde0
+		 * bit 3: valid
+		 * bit 4: read
+		 * bit 5: write
+		 */
+#define		MEMORY_CLIENT_ID_MASK			(0xff << 12)
+#define		MEMORY_CLIENT_ID_SHIFT			12
+#define		MEMORY_CLIENT_RW_MASK			(1 << 24)
+#define		MEMORY_CLIENT_RW_SHIFT			24
+#define		FAULT_VMID_MASK				(0x7 << 25)
+#define		FAULT_VMID_SHIFT			25
 #define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR	0x1518
 #define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR	0x151c
 #define	VM_CONTEXT0_PAGE_TABLE_BASE_ADDR		0x153C
@@ -618,6 +634,10 @@
 #       define MRDCKD0_BYPASS                           (1 << 30)
 #       define MRDCKD1_BYPASS                           (1 << 31)
 
+#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x66c
+#       define CURRENT_STATE_INDEX_MASK                   (0xf << 4)
+#       define CURRENT_STATE_INDEX_SHIFT                  4
+
 #define CG_AT                                           0x6d4
 #       define CG_R(x)					((x) << 0)
 #       define CG_R_MASK				(0xffff << 0)
diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h
index 8fb1113..b5564a3 100644
--- a/drivers/gpu/drm/radeon/ppsmc.h
+++ b/drivers/gpu/drm/radeon/ppsmc.h
@@ -71,6 +71,8 @@
 #define PPSMC_MSG_SwitchToSwState           ((uint8_t)0x20)
 #define PPSMC_MSG_SwitchToInitialState      ((uint8_t)0x40)
 #define PPSMC_MSG_NoForcedLevel             ((uint8_t)0x41)
+#define PPSMC_MSG_ForceHigh                 ((uint8_t)0x42)
+#define PPSMC_MSG_ForceMediumOrHigh         ((uint8_t)0x43)
 #define PPSMC_MSG_SwitchToMinimumPower      ((uint8_t)0x51)
 #define PPSMC_MSG_ResumeFromMinimumPower    ((uint8_t)0x52)
 #define PPSMC_MSG_EnableCac                 ((uint8_t)0x53)
@@ -101,6 +103,7 @@
 #define PPSMC_MSG_DPM_Config                ((uint32_t) 0x102)
 #define PPSMC_MSG_DPM_ForceState            ((uint32_t) 0x104)
 #define PPSMC_MSG_PG_SIMD_Config            ((uint32_t) 0x108)
+#define PPSMC_MSG_DPM_N_LevelsDisabled      ((uint32_t) 0x112)
 #define PPSMC_MSG_DCE_RemoveVoltageAdjustment   ((uint32_t) 0x11d)
 #define PPSMC_MSG_DCE_AllowVoltageAdjustment    ((uint32_t) 0x11e)
 #define PPSMC_MSG_UVD_DPM_Config            ((uint32_t) 0x124)
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index d0314ec..75349cd 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -39,7 +39,6 @@
 #include "atom.h"
 
 #include <linux/firmware.h>
-#include <linux/platform_device.h>
 #include <linux/module.h>
 
 #include "r100_reg_safe.h"
@@ -989,18 +988,11 @@
 /* Load the microcode for the CP */
 static int r100_cp_init_microcode(struct radeon_device *rdev)
 {
-	struct platform_device *pdev;
 	const char *fw_name = NULL;
 	int err;
 
 	DRM_DEBUG_KMS("\n");
 
-	pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
-	err = IS_ERR(pdev);
-	if (err) {
-		printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
-		return -EINVAL;
-	}
 	if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) ||
 	    (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) ||
 	    (rdev->family == CHIP_RS200)) {
@@ -1042,8 +1034,7 @@
 		fw_name = FIRMWARE_R520;
 	}
 
-	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
-	platform_device_unregister(pdev);
+	err = request_firmware(&rdev->me_fw, fw_name, rdev->dev);
 	if (err) {
 		printk(KERN_ERR "radeon_cp: Failed to load firmware \"%s\"\n",
 		       fw_name);
@@ -3077,6 +3068,10 @@
 			flags |= RADEON_SURF_TILE_COLOR_BOTH;
 		if (tiling_flags & RADEON_TILING_MACRO)
 			flags |= RADEON_SURF_TILE_COLOR_MACRO;
+		/* setting pitch to 0 disables tiling */
+		if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO))
+				== 0)
+			pitch = 0;
 	} else if (rdev->family <= CHIP_RV280) {
 		if (tiling_flags & (RADEON_TILING_MACRO))
 			flags |= R200_SURF_TILE_COLOR_MACRO;
@@ -3094,13 +3089,6 @@
 	if (tiling_flags & RADEON_TILING_SWAP_32BIT)
 		flags |= RADEON_SURF_AP0_SWP_32BPP | RADEON_SURF_AP1_SWP_32BPP;
 
-	/* when we aren't tiling the pitch seems to needs to be furtherdivided down. - tested on power5 + rn50 server */
-	if (tiling_flags & (RADEON_TILING_SWAP_16BIT | RADEON_TILING_SWAP_32BIT)) {
-		if (!(tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO)))
-			if (ASIC_IS_RN50(rdev))
-				pitch /= 16;
-	}
-
 	/* r100/r200 divide by 16 */
 	if (rdev->family < CHIP_R300)
 		flags |= pitch / 16;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 2d3655f..393880a 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -28,7 +28,6 @@
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <linux/firmware.h>
-#include <linux/platform_device.h>
 #include <linux/module.h>
 #include <drm/drmP.h>
 #include <drm/radeon_drm.h>
@@ -2144,7 +2143,6 @@
 
 int r600_init_microcode(struct radeon_device *rdev)
 {
-	struct platform_device *pdev;
 	const char *chip_name;
 	const char *rlc_chip_name;
 	const char *smc_chip_name = "RV770";
@@ -2154,13 +2152,6 @@
 
 	DRM_DEBUG("\n");
 
-	pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
-	err = IS_ERR(pdev);
-	if (err) {
-		printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
-		return -EINVAL;
-	}
-
 	switch (rdev->family) {
 	case CHIP_R600:
 		chip_name = "R600";
@@ -2272,7 +2263,7 @@
 	DRM_INFO("Loading %s Microcode\n", chip_name);
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
-	err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->pfp_fw->size != pfp_req_size) {
@@ -2284,7 +2275,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
-	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->me_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->me_fw->size != me_req_size) {
@@ -2295,7 +2286,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name);
-	err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->rlc_fw->size != rlc_req_size) {
@@ -2307,7 +2298,7 @@
 
 	if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) {
 		snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name);
-		err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+		err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
 		if (err)
 			goto out;
 		if (rdev->smc_fw->size != smc_req_size) {
@@ -2319,8 +2310,6 @@
 	}
 
 out:
-	platform_device_unregister(pdev);
-
 	if (err) {
 		if (err != -EINVAL)
 			printk(KERN_ERR
@@ -3019,7 +3008,7 @@
 			 struct radeon_fence *fence)
 {
 	struct radeon_ring *ring = &rdev->ring[fence->ring];
-	uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr;
+	uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
 
 	radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
 	radeon_ring_write(ring, fence->seq);
@@ -3145,6 +3134,87 @@
 }
 
 /**
+ * r600_copy_cpdma - copy pages using the CP DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @src_offset: src GPU address
+ * @dst_offset: dst GPU address
+ * @num_gpu_pages: number of GPU pages to xfer
+ * @fence: radeon fence object
+ *
+ * Copy GPU paging using the CP DMA engine (r6xx+).
+ * Used by the radeon ttm implementation to move pages if
+ * registered as the asic copy callback.
+ */
+int r600_copy_cpdma(struct radeon_device *rdev,
+		    uint64_t src_offset, uint64_t dst_offset,
+		    unsigned num_gpu_pages,
+		    struct radeon_fence **fence)
+{
+	struct radeon_semaphore *sem = NULL;
+	int ring_index = rdev->asic->copy.blit_ring_index;
+	struct radeon_ring *ring = &rdev->ring[ring_index];
+	u32 size_in_bytes, cur_size_in_bytes, tmp;
+	int i, num_loops;
+	int r = 0;
+
+	r = radeon_semaphore_create(rdev, &sem);
+	if (r) {
+		DRM_ERROR("radeon: moving bo (%d).\n", r);
+		return r;
+	}
+
+	size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
+	num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
+	r = radeon_ring_lock(rdev, ring, num_loops * 6 + 21);
+	if (r) {
+		DRM_ERROR("radeon: moving bo (%d).\n", r);
+		radeon_semaphore_free(rdev, &sem, NULL);
+		return r;
+	}
+
+	if (radeon_fence_need_sync(*fence, ring->idx)) {
+		radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring,
+					    ring->idx);
+		radeon_fence_note_sync(*fence, ring->idx);
+	} else {
+		radeon_semaphore_free(rdev, &sem, NULL);
+	}
+
+	for (i = 0; i < num_loops; i++) {
+		cur_size_in_bytes = size_in_bytes;
+		if (cur_size_in_bytes > 0x1fffff)
+			cur_size_in_bytes = 0x1fffff;
+		size_in_bytes -= cur_size_in_bytes;
+		tmp = upper_32_bits(src_offset) & 0xff;
+		if (size_in_bytes == 0)
+			tmp |= PACKET3_CP_DMA_CP_SYNC;
+		radeon_ring_write(ring, PACKET3(PACKET3_CP_DMA, 4));
+		radeon_ring_write(ring, src_offset & 0xffffffff);
+		radeon_ring_write(ring, tmp);
+		radeon_ring_write(ring, dst_offset & 0xffffffff);
+		radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xff);
+		radeon_ring_write(ring, cur_size_in_bytes);
+		src_offset += cur_size_in_bytes;
+		dst_offset += cur_size_in_bytes;
+	}
+	radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+	radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+	radeon_ring_write(ring, WAIT_CP_DMA_IDLE_bit);
+
+	r = radeon_fence_emit(rdev, fence, ring->idx);
+	if (r) {
+		radeon_ring_unlock_undo(rdev, ring);
+		return r;
+	}
+
+	radeon_ring_unlock_commit(rdev, ring);
+	radeon_semaphore_free(rdev, &sem, *fence);
+
+	return r;
+}
+
+/**
  * r600_copy_dma - copy pages using the DMA engine
  *
  * @rdev: radeon_device pointer
diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
index 76368c0..b88f54b 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.c
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -150,6 +150,30 @@
 	printk("\n");
 }
 
+u32 r600_dpm_get_vblank_time(struct radeon_device *rdev)
+{
+	struct drm_device *dev = rdev->ddev;
+	struct drm_crtc *crtc;
+	struct radeon_crtc *radeon_crtc;
+	u32 line_time_us, vblank_lines;
+	u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		radeon_crtc = to_radeon_crtc(crtc);
+		if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
+			line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) /
+				radeon_crtc->hw_mode.clock;
+			vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end -
+				radeon_crtc->hw_mode.crtc_vdisplay +
+				(radeon_crtc->v_border * 2);
+			vblank_time_us = vblank_lines * line_time_us;
+			break;
+		}
+	}
+
+	return vblank_time_us;
+}
+
 void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
 			    u32 *p, u32 *u)
 {
diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h
index a95ab21..7c822d9 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.h
+++ b/drivers/gpu/drm/radeon/r600_dpm.h
@@ -129,6 +129,7 @@
 void r600_dpm_print_cap_info(u32 caps);
 void r600_dpm_print_ps_status(struct radeon_device *rdev,
 			      struct radeon_ps *rps);
+u32 r600_dpm_get_vblank_time(struct radeon_device *rdev);
 bool r600_is_uvd_state(u32 class, u32 class2);
 void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
 			    u32 *p, u32 *u);
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index e73b2a7..f48240b 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -266,6 +266,9 @@
 	uint32_t offset;
 	ssize_t err;
 
+	if (!dig || !dig->afmt)
+		return;
+
 	/* Silent, r600_hdmi_enable will raise WARN for us */
 	if (!dig->afmt->enabled)
 		return;
@@ -448,6 +451,9 @@
 	struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 	u32 hdmi = HDMI0_ERROR_ACK;
 
+	if (!dig || !dig->afmt)
+		return;
+
 	/* Silent, r600_hdmi_enable will raise WARN for us */
 	if (enable && dig->afmt->enabled)
 		return;
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index f1b3084..8e3fe81 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -602,6 +602,7 @@
 #define		L2_BUSY						(1 << 0)
 
 #define	WAIT_UNTIL					0x8040
+#define         WAIT_CP_DMA_IDLE_bit                            (1 << 8)
 #define         WAIT_2D_IDLE_bit                                (1 << 14)
 #define         WAIT_3D_IDLE_bit                                (1 << 15)
 #define         WAIT_2D_IDLECLEAN_bit                           (1 << 16)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 7e3fef4..2f08219 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -97,6 +97,7 @@
 extern int radeon_lockup_timeout;
 extern int radeon_fastfb;
 extern int radeon_dpm;
+extern int radeon_aspm;
 
 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -455,6 +456,7 @@
 	uint64_t		gpu_addr;
 	void			*cpu_ptr;
 	uint32_t		domain;
+	uint32_t		align;
 };
 
 struct radeon_sa_bo;
@@ -783,6 +785,11 @@
 /* number of entries in page table */
 #define RADEON_VM_PTE_COUNT (1 << RADEON_VM_BLOCK_SIZE)
 
+/* PTBs (Page Table Blocks) need to be aligned to 32K */
+#define RADEON_VM_PTB_ALIGN_SIZE   32768
+#define RADEON_VM_PTB_ALIGN_MASK (RADEON_VM_PTB_ALIGN_SIZE - 1)
+#define RADEON_VM_PTB_ALIGN(a) (((a) + RADEON_VM_PTB_ALIGN_MASK) & ~RADEON_VM_PTB_ALIGN_MASK)
+
 struct radeon_vm {
 	struct list_head		list;
 	struct list_head		va;
@@ -1100,6 +1107,7 @@
 	POWER_STATE_TYPE_INTERNAL_THERMAL,
 	POWER_STATE_TYPE_INTERNAL_ACPI,
 	POWER_STATE_TYPE_INTERNAL_ULV,
+	POWER_STATE_TYPE_INTERNAL_3DPERF,
 };
 
 enum radeon_pm_profile_type {
@@ -1334,6 +1342,12 @@
 	RADEON_PCIE_GEN_INVALID = 0xffff
 };
 
+enum radeon_dpm_forced_level {
+	RADEON_DPM_FORCED_LEVEL_AUTO = 0,
+	RADEON_DPM_FORCED_LEVEL_LOW = 1,
+	RADEON_DPM_FORCED_LEVEL_HIGH = 2,
+};
+
 struct radeon_dpm {
 	struct radeon_ps        *ps;
 	/* number of valid power states */
@@ -1373,6 +1387,8 @@
 	bool                    uvd_active;
 	/* thermal handling */
 	struct radeon_dpm_thermal thermal;
+	/* forced levels */
+	enum radeon_dpm_forced_level forced_level;
 };
 
 void radeon_dpm_enable_power_state(struct radeon_device *rdev,
@@ -1451,6 +1467,8 @@
 	struct radeon_bo	*vcpu_bo;
 	void			*cpu_addr;
 	uint64_t		gpu_addr;
+	void			*saved_bo;
+	unsigned		fw_size;
 	atomic_t		handles[RADEON_MAX_UVD_HANDLES];
 	struct drm_file		*filp[RADEON_MAX_UVD_HANDLES];
 	struct delayed_work	idle_work;
@@ -1667,6 +1685,9 @@
 		u32 (*get_sclk)(struct radeon_device *rdev, bool low);
 		u32 (*get_mclk)(struct radeon_device *rdev, bool low);
 		void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps);
+		void (*debugfs_print_current_performance_level)(struct radeon_device *rdev, struct seq_file *m);
+		int (*force_performance_level)(struct radeon_device *rdev, enum radeon_dpm_forced_level level);
+		bool (*vblank_too_short)(struct radeon_device *rdev);
 	} dpm;
 	/* pageflipping */
 	struct {
@@ -2042,7 +2063,6 @@
 	const struct firmware *rlc_fw;	/* r6/700 RLC firmware */
 	const struct firmware *mc_fw;	/* NI MC firmware */
 	const struct firmware *ce_fw;	/* SI CE firmware */
-	const struct firmware *uvd_fw;	/* UVD firmware */
 	const struct firmware *mec_fw;	/* CIK MEC firmware */
 	const struct firmware *sdma_fw;	/* CIK SDMA firmware */
 	const struct firmware *smc_fw;	/* SMC firmware */
@@ -2433,6 +2453,9 @@
 #define radeon_dpm_get_sclk(rdev, l) rdev->asic->dpm.get_sclk((rdev), (l))
 #define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l))
 #define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps))
+#define radeon_dpm_debugfs_print_current_performance_level(rdev, m) rdev->asic->dpm.debugfs_print_current_performance_level((rdev), (m))
+#define radeon_dpm_force_performance_level(rdev, l) rdev->asic->dpm.force_performance_level((rdev), (l))
+#define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev))
 
 /* Common functions */
 /* AGP */
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index c3df589..78bec1a 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -1026,8 +1026,8 @@
 		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
 		.dma = &r600_copy_dma,
 		.dma_ring_index = R600_RING_TYPE_DMA_INDEX,
-		.copy = &r600_copy_dma,
-		.copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.copy = &r600_copy_cpdma,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
 	},
 	.surface = {
 		.set_reg = r600_set_surface_reg,
@@ -1119,8 +1119,8 @@
 		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
 		.dma = &r600_copy_dma,
 		.dma_ring_index = R600_RING_TYPE_DMA_INDEX,
-		.copy = &r600_copy_dma,
-		.copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.copy = &r600_copy_cpdma,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
 	},
 	.surface = {
 		.set_reg = r600_set_surface_reg,
@@ -1160,6 +1160,7 @@
 		.get_sclk = &rv6xx_dpm_get_sclk,
 		.get_mclk = &rv6xx_dpm_get_mclk,
 		.print_power_state = &rv6xx_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1228,8 +1229,8 @@
 		.blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
 		.dma = &r600_copy_dma,
 		.dma_ring_index = R600_RING_TYPE_DMA_INDEX,
-		.copy = &r600_copy_dma,
-		.copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+		.copy = &r600_copy_cpdma,
+		.copy_ring_index = RADEON_RING_TYPE_GFX_INDEX,
 	},
 	.surface = {
 		.set_reg = r600_set_surface_reg,
@@ -1269,6 +1270,7 @@
 		.get_sclk = &rs780_dpm_get_sclk,
 		.get_mclk = &rs780_dpm_get_mclk,
 		.print_power_state = &rs780_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1391,6 +1393,9 @@
 		.get_sclk = &rv770_dpm_get_sclk,
 		.get_mclk = &rv770_dpm_get_mclk,
 		.print_power_state = &rv770_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
+		.force_performance_level = &rv770_dpm_force_performance_level,
+		.vblank_too_short = &rv770_dpm_vblank_too_short,
 	},
 	.pflip = {
 		.pre_page_flip = &rs600_pre_page_flip,
@@ -1513,6 +1518,9 @@
 		.get_sclk = &rv770_dpm_get_sclk,
 		.get_mclk = &rv770_dpm_get_mclk,
 		.print_power_state = &rv770_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
+		.force_performance_level = &rv770_dpm_force_performance_level,
+		.vblank_too_short = &cypress_dpm_vblank_too_short,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1635,6 +1643,8 @@
 		.get_sclk = &sumo_dpm_get_sclk,
 		.get_mclk = &sumo_dpm_get_mclk,
 		.print_power_state = &sumo_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level,
+		.force_performance_level = &sumo_dpm_force_performance_level,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1757,6 +1767,9 @@
 		.get_sclk = &btc_dpm_get_sclk,
 		.get_mclk = &btc_dpm_get_mclk,
 		.print_power_state = &rv770_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
+		.force_performance_level = &rv770_dpm_force_performance_level,
+		.vblank_too_short = &btc_dpm_vblank_too_short,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -1931,6 +1944,9 @@
 		.get_sclk = &ni_dpm_get_sclk,
 		.get_mclk = &ni_dpm_get_mclk,
 		.print_power_state = &ni_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level,
+		.force_performance_level = &ni_dpm_force_performance_level,
+		.vblank_too_short = &ni_dpm_vblank_too_short,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -2103,6 +2119,8 @@
 		.get_sclk = &trinity_dpm_get_sclk,
 		.get_mclk = &trinity_dpm_get_mclk,
 		.print_power_state = &trinity_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level,
+		.force_performance_level = &trinity_dpm_force_performance_level,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
@@ -2275,6 +2293,9 @@
 		.get_sclk = &ni_dpm_get_sclk,
 		.get_mclk = &ni_dpm_get_mclk,
 		.print_power_state = &ni_dpm_print_power_state,
+		.debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level,
+		.force_performance_level = &si_dpm_force_performance_level,
+		.vblank_too_short = &ni_dpm_vblank_too_short,
 	},
 	.pflip = {
 		.pre_page_flip = &evergreen_pre_page_flip,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 2497d0a..ca18957 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -340,6 +340,9 @@
 int r600_copy_blit(struct radeon_device *rdev,
 		   uint64_t src_offset, uint64_t dst_offset,
 		   unsigned num_gpu_pages, struct radeon_fence **fence);
+int r600_copy_cpdma(struct radeon_device *rdev,
+		    uint64_t src_offset, uint64_t dst_offset,
+		    unsigned num_gpu_pages, struct radeon_fence **fence);
 int r600_copy_dma(struct radeon_device *rdev,
 		  uint64_t src_offset, uint64_t dst_offset,
 		  unsigned num_gpu_pages, struct radeon_fence **fence);
@@ -416,6 +419,8 @@
 u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low);
 void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
 				 struct radeon_ps *ps);
+void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						       struct seq_file *m);
 /* rs780 dpm */
 int rs780_dpm_init(struct radeon_device *rdev);
 int rs780_dpm_enable(struct radeon_device *rdev);
@@ -428,6 +433,8 @@
 u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
 void rs780_dpm_print_power_state(struct radeon_device *rdev,
 				 struct radeon_ps *ps);
+void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						       struct seq_file *m);
 
 /* uvd */
 int r600_uvd_init(struct radeon_device *rdev);
@@ -474,6 +481,11 @@
 u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low);
 void rv770_dpm_print_power_state(struct radeon_device *rdev,
 				 struct radeon_ps *ps);
+void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						       struct seq_file *m);
+int rv770_dpm_force_performance_level(struct radeon_device *rdev,
+				      enum radeon_dpm_forced_level level);
+bool rv770_dpm_vblank_too_short(struct radeon_device *rdev);
 
 /*
  * evergreen
@@ -538,6 +550,7 @@
 int cypress_dpm_set_power_state(struct radeon_device *rdev);
 void cypress_dpm_display_configuration_changed(struct radeon_device *rdev);
 void cypress_dpm_fini(struct radeon_device *rdev);
+bool cypress_dpm_vblank_too_short(struct radeon_device *rdev);
 int btc_dpm_init(struct radeon_device *rdev);
 void btc_dpm_setup_asic(struct radeon_device *rdev);
 int btc_dpm_enable(struct radeon_device *rdev);
@@ -548,6 +561,7 @@
 void btc_dpm_fini(struct radeon_device *rdev);
 u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low);
 u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
+bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
 int sumo_dpm_init(struct radeon_device *rdev);
 int sumo_dpm_enable(struct radeon_device *rdev);
 void sumo_dpm_disable(struct radeon_device *rdev);
@@ -561,6 +575,10 @@
 u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low);
 void sumo_dpm_print_power_state(struct radeon_device *rdev,
 				struct radeon_ps *ps);
+void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						      struct seq_file *m);
+int sumo_dpm_force_performance_level(struct radeon_device *rdev,
+				     enum radeon_dpm_forced_level level);
 
 /*
  * cayman
@@ -607,6 +625,11 @@
 u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low);
 void ni_dpm_print_power_state(struct radeon_device *rdev,
 			      struct radeon_ps *ps);
+void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						    struct seq_file *m);
+int ni_dpm_force_performance_level(struct radeon_device *rdev,
+				   enum radeon_dpm_forced_level level);
+bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
 int trinity_dpm_init(struct radeon_device *rdev);
 int trinity_dpm_enable(struct radeon_device *rdev);
 void trinity_dpm_disable(struct radeon_device *rdev);
@@ -620,6 +643,10 @@
 u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low);
 void trinity_dpm_print_power_state(struct radeon_device *rdev,
 				   struct radeon_ps *ps);
+void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+							 struct seq_file *m);
+int trinity_dpm_force_performance_level(struct radeon_device *rdev,
+					enum radeon_dpm_forced_level level);
 
 /* DCE6 - SI */
 void dce6_bandwidth_update(struct radeon_device *rdev);
@@ -667,6 +694,10 @@
 void si_dpm_post_set_power_state(struct radeon_device *rdev);
 void si_dpm_fini(struct radeon_device *rdev);
 void si_dpm_display_configuration_changed(struct radeon_device *rdev);
+void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						    struct seq_file *m);
+int si_dpm_force_performance_level(struct radeon_device *rdev,
+				   enum radeon_dpm_forced_level level);
 
 /* DCE8 - CIK */
 void dce8_bandwidth_update(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index a8296e0..e3f3e88 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -2441,6 +2441,10 @@
 	case ATOM_VIRTUAL_VOLTAGE_ID1:
 	case ATOM_VIRTUAL_VOLTAGE_ID2:
 	case ATOM_VIRTUAL_VOLTAGE_ID3:
+	case ATOM_VIRTUAL_VOLTAGE_ID4:
+	case ATOM_VIRTUAL_VOLTAGE_ID5:
+	case ATOM_VIRTUAL_VOLTAGE_ID6:
+	case ATOM_VIRTUAL_VOLTAGE_ID7:
 		if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC,
 					     rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage,
 					     &vddc) == 0)
@@ -3509,7 +3513,6 @@
 	u8 frev, crev, i;
 	u16 data_offset, size;
 	union vram_info *vram_info;
-	u8 *p;
 
 	memset(mem_info, 0, sizeof(struct atom_memory_info));
 
@@ -3525,13 +3528,12 @@
 				if (module_index < vram_info->v1_3.ucNumOfVRAMModule) {
 					ATOM_VRAM_MODULE_V3 *vram_module =
 						(ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo;
-					p = (u8 *)vram_info->v1_3.aVramInfo;
 
 					for (i = 0; i < module_index; i++) {
-						vram_module = (ATOM_VRAM_MODULE_V3 *)p;
 						if (le16_to_cpu(vram_module->usSize) == 0)
 							return -EINVAL;
-						p += le16_to_cpu(vram_module->usSize);
+						vram_module = (ATOM_VRAM_MODULE_V3 *)
+							((u8 *)vram_module + le16_to_cpu(vram_module->usSize));
 					}
 					mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf;
 					mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0;
@@ -3543,13 +3545,12 @@
 				if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
 					ATOM_VRAM_MODULE_V4 *vram_module =
 						(ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
-					p = (u8 *)vram_info->v1_4.aVramInfo;
 
 					for (i = 0; i < module_index; i++) {
-						vram_module = (ATOM_VRAM_MODULE_V4 *)p;
 						if (le16_to_cpu(vram_module->usModuleSize) == 0)
 							return -EINVAL;
-						p += le16_to_cpu(vram_module->usModuleSize);
+						vram_module = (ATOM_VRAM_MODULE_V4 *)
+							((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
 					}
 					mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
 					mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
@@ -3568,13 +3569,12 @@
 				if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
 					ATOM_VRAM_MODULE_V7 *vram_module =
 						(ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo;
-					p = (u8 *)vram_info->v2_1.aVramInfo;
 
 					for (i = 0; i < module_index; i++) {
-						vram_module = (ATOM_VRAM_MODULE_V7 *)p;
 						if (le16_to_cpu(vram_module->usModuleSize) == 0)
 							return -EINVAL;
-						p += le16_to_cpu(vram_module->usModuleSize);
+						vram_module = (ATOM_VRAM_MODULE_V7 *)
+							((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
 					}
 					mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
 					mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
@@ -3624,22 +3624,20 @@
 				if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
 					ATOM_VRAM_MODULE_V4 *vram_module =
 						(ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
-					ATOM_MEMORY_TIMING_FORMAT *format;
-					p = (u8 *)vram_info->v1_4.aVramInfo;
 
 					for (i = 0; i < module_index; i++) {
-						vram_module = (ATOM_VRAM_MODULE_V4 *)p;
 						if (le16_to_cpu(vram_module->usModuleSize) == 0)
 							return -EINVAL;
-						p += le16_to_cpu(vram_module->usModuleSize);
+						vram_module = (ATOM_VRAM_MODULE_V4 *)
+							((u8 *)vram_module + le16_to_cpu(vram_module->usModuleSize));
 					}
 					mclk_range_table->num_entries = (u8)
-						((vram_module->usModuleSize - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) /
+						((le16_to_cpu(vram_module->usModuleSize) - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) /
 						 mem_timing_size);
-					p = (u8 *)vram_module->asMemTiming;
+					p = (u8 *)&vram_module->asMemTiming[0];
 					for (i = 0; i < mclk_range_table->num_entries; i++) {
-						format = (ATOM_MEMORY_TIMING_FORMAT *)p;
-						mclk_range_table->mclk[i] = format->ulClkRange;
+						ATOM_MEMORY_TIMING_FORMAT *format = (ATOM_MEMORY_TIMING_FORMAT *)p;
+						mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange);
 						p += mem_timing_size;
 					}
 				} else
@@ -3701,17 +3699,21 @@
 						(ATOM_MEMORY_SETTING_DATA_BLOCK *)
 						((u8 *)reg_block + (2 * sizeof(u16)) +
 						 le16_to_cpu(reg_block->usRegIndexTblSize));
+					ATOM_INIT_REG_INDEX_FORMAT *format = &reg_block->asRegIndexBuf[0];
 					num_entries = (u8)((le16_to_cpu(reg_block->usRegIndexTblSize)) /
 							   sizeof(ATOM_INIT_REG_INDEX_FORMAT)) - 1;
 					if (num_entries > VBIOS_MC_REGISTER_ARRAY_SIZE)
 						return -EINVAL;
-					while (!(reg_block->asRegIndexBuf[i].ucPreRegDataLength & ACCESS_PLACEHOLDER) &&
-					      (i < num_entries)) {
+					while (i < num_entries) {
+						if (format->ucPreRegDataLength & ACCESS_PLACEHOLDER)
+							break;
 						reg_table->mc_reg_address[i].s1 =
-							(u16)(le16_to_cpu(reg_block->asRegIndexBuf[i].usRegIndex));
+							(u16)(le16_to_cpu(format->usRegIndex));
 						reg_table->mc_reg_address[i].pre_reg_data =
-							(u8)(reg_block->asRegIndexBuf[i].ucPreRegDataLength);
+							(u8)(format->ucPreRegDataLength);
 						i++;
+						format = (ATOM_INIT_REG_INDEX_FORMAT *)
+							((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
 					}
 					reg_table->last = i;
 					while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) &&
@@ -3732,7 +3734,8 @@
 							}
 							num_ranges++;
 						}
-						reg_data += reg_block->usRegDataBlkSize;
+						reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
+							((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));
 					}
 					if (*(u32 *)reg_data != END_OF_REG_DATA_BLOCK)
 						return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index e5419b3..29876b1 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -167,6 +167,7 @@
 int radeon_lockup_timeout = 10000;
 int radeon_fastfb = 0;
 int radeon_dpm = -1;
+int radeon_aspm = -1;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -225,6 +226,9 @@
 MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)");
 module_param_named(dpm, radeon_dpm, int, 0444);
 
+MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(aspm, radeon_aspm, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
 	radeon_PCI_IDS
 };
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index b174674..665ced3 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -230,7 +230,7 @@
 
 	ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
 	if (ret) {
-		DRM_ERROR("failed to initalise framebuffer %d\n", ret);
+		DRM_ERROR("failed to initialize framebuffer %d\n", ret);
 		goto out_unref;
 	}
 
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index ddb8f8e..7ddb0ef 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -782,7 +782,7 @@
 
 		} else {
 			/* put fence directly behind firmware */
-			index = ALIGN(rdev->uvd_fw->size, 8);
+			index = ALIGN(rdev->uvd.fw_size, 8);
 			rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index;
 			rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index;
 		}
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index 43ec4a4..d9d31a3 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -466,7 +466,8 @@
 		size += rdev->vm_manager.max_pfn * 8;
 		size *= 2;
 		r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager,
-					      RADEON_GPU_PAGE_ALIGN(size),
+					      RADEON_VM_PTB_ALIGN(size),
+					      RADEON_VM_PTB_ALIGN_SIZE,
 					      RADEON_GEM_DOMAIN_VRAM);
 		if (r) {
 			dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n",
@@ -620,10 +621,10 @@
 	}
 
 retry:
-	pd_size = RADEON_GPU_PAGE_ALIGN(radeon_vm_directory_size(rdev));
+	pd_size = RADEON_VM_PTB_ALIGN(radeon_vm_directory_size(rdev));
 	r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
 			     &vm->page_directory, pd_size,
-			     RADEON_GPU_PAGE_SIZE, false);
+			     RADEON_VM_PTB_ALIGN_SIZE, false);
 	if (r == -ENOMEM) {
 		r = radeon_vm_evict(rdev, vm);
 		if (r)
@@ -952,8 +953,8 @@
 retry:
 		r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
 				     &vm->page_tables[pt_idx],
-				     RADEON_VM_PTE_COUNT * 8,
-				     RADEON_GPU_PAGE_SIZE, false);
+				     RADEON_VM_PTB_ALIGN(RADEON_VM_PTE_COUNT * 8),
+				     RADEON_VM_PTB_ALIGN_SIZE, false);
 
 		if (r == -ENOMEM) {
 			r = radeon_vm_evict(rdev, vm);
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index bcdefd1..081886b 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -260,10 +260,6 @@
 {
 	int r = 0;
 
-	INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
-	INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
-	INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func);
-
 	spin_lock_init(&rdev->irq.lock);
 	r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
 	if (r) {
@@ -285,6 +281,11 @@
 		rdev->irq.installed = false;
 		return r;
 	}
+
+	INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+	INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
+	INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func);
+
 	DRM_INFO("radeon: irq initialized.\n");
 	return 0;
 }
@@ -304,8 +305,8 @@
 		rdev->irq.installed = false;
 		if (rdev->msi_enabled)
 			pci_disable_msi(rdev->pdev);
+		flush_work(&rdev->hotplug_work);
 	}
-	flush_work(&rdev->hotplug_work);
 }
 
 /**
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index b568cb1..8296632 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -335,6 +335,7 @@
 	u32 line_time;
 	u32 wm_low;
 	u32 wm_high;
+	struct drm_display_mode hw_mode;
 };
 
 struct radeon_encoder_primary_dac {
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 0219d26..2020bf4 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -377,6 +377,7 @@
 					domain = lobj->alt_domain;
 					goto retry;
 				}
+				ttm_eu_backoff_reservation(ticket, head);
 				return r;
 			}
 		}
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index 91519a5..49c82c4 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -174,7 +174,7 @@
 
 extern int radeon_sa_bo_manager_init(struct radeon_device *rdev,
 				     struct radeon_sa_manager *sa_manager,
-				     unsigned size, u32 domain);
+				     unsigned size, u32 align, u32 domain);
 extern void radeon_sa_bo_manager_fini(struct radeon_device *rdev,
 				      struct radeon_sa_manager *sa_manager);
 extern int radeon_sa_bo_manager_start(struct radeon_device *rdev,
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 9737bae..f374c46 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -468,9 +468,57 @@
 	return count;
 }
 
+static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,
+						       struct device_attribute *attr,
+						       char *buf)
+{
+	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+	struct radeon_device *rdev = ddev->dev_private;
+	enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			(level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+			(level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+}
+
+static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
+						       struct device_attribute *attr,
+						       const char *buf,
+						       size_t count)
+{
+	struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+	struct radeon_device *rdev = ddev->dev_private;
+	enum radeon_dpm_forced_level level;
+	int ret = 0;
+
+	mutex_lock(&rdev->pm.mutex);
+	if (strncmp("low", buf, strlen("low")) == 0) {
+		level = RADEON_DPM_FORCED_LEVEL_LOW;
+	} else if (strncmp("high", buf, strlen("high")) == 0) {
+		level = RADEON_DPM_FORCED_LEVEL_HIGH;
+	} else if (strncmp("auto", buf, strlen("auto")) == 0) {
+		level = RADEON_DPM_FORCED_LEVEL_AUTO;
+	} else {
+		mutex_unlock(&rdev->pm.mutex);
+		count = -EINVAL;
+		goto fail;
+	}
+	if (rdev->asic->dpm.force_performance_level) {
+		ret = radeon_dpm_force_performance_level(rdev, level);
+		if (ret)
+			count = -EINVAL;
+	}
+	mutex_unlock(&rdev->pm.mutex);
+fail:
+	return count;
+}
+
 static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
 static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
 static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
+static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
+		   radeon_get_dpm_forced_performance_level,
+		   radeon_set_dpm_forced_performance_level);
 
 static ssize_t radeon_hwmon_show_temp(struct device *dev,
 				      struct device_attribute *attr,
@@ -585,12 +633,25 @@
 	int i;
 	struct radeon_ps *ps;
 	u32 ui_class;
+	bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ?
+		true : false;
 
-restart_search:
+	/* check if the vblank period is too short to adjust the mclk */
+	if (single_display && rdev->asic->dpm.vblank_too_short) {
+		if (radeon_dpm_vblank_too_short(rdev))
+			single_display = false;
+	}
+
+	/* certain older asics have a separare 3D performance state,
+	 * so try that first if the user selected performance
+	 */
+	if (dpm_state == POWER_STATE_TYPE_PERFORMANCE)
+		dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF;
 	/* balanced states don't exist at the moment */
 	if (dpm_state == POWER_STATE_TYPE_BALANCED)
 		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
 
+restart_search:
 	/* Pick the best power state based on current conditions */
 	for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
 		ps = &rdev->pm.dpm.ps[i];
@@ -600,7 +661,7 @@
 		case POWER_STATE_TYPE_BATTERY:
 			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
 				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
-					if (rdev->pm.dpm.new_active_crtc_count < 2)
+					if (single_display)
 						return ps;
 				} else
 					return ps;
@@ -609,7 +670,7 @@
 		case POWER_STATE_TYPE_BALANCED:
 			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) {
 				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
-					if (rdev->pm.dpm.new_active_crtc_count < 2)
+					if (single_display)
 						return ps;
 				} else
 					return ps;
@@ -618,7 +679,7 @@
 		case POWER_STATE_TYPE_PERFORMANCE:
 			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
 				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
-					if (rdev->pm.dpm.new_active_crtc_count < 2)
+					if (single_display)
 						return ps;
 				} else
 					return ps;
@@ -657,6 +718,10 @@
 			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
 				return ps;
 			break;
+		case POWER_STATE_TYPE_INTERNAL_3DPERF:
+			if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
+				return ps;
+			break;
 		default:
 			break;
 		}
@@ -675,6 +740,8 @@
 		dpm_state = POWER_STATE_TYPE_BATTERY;
 		goto restart_search;
 	case POWER_STATE_TYPE_BATTERY:
+	case POWER_STATE_TYPE_BALANCED:
+	case POWER_STATE_TYPE_INTERNAL_3DPERF:
 		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
 		goto restart_search;
 	default:
@@ -852,7 +919,7 @@
 {
 	/* set up the default clocks if the MC ucode is loaded */
 	if ((rdev->family >= CHIP_BARTS) &&
-	    (rdev->family <= CHIP_CAYMAN) &&
+	    (rdev->family <= CHIP_HAINAN) &&
 	    rdev->mc_fw) {
 		if (rdev->pm.default_vddc)
 			radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -896,7 +963,7 @@
 	if (ret) {
 		DRM_ERROR("radeon: dpm resume failed\n");
 		if ((rdev->family >= CHIP_BARTS) &&
-		    (rdev->family <= CHIP_CAYMAN) &&
+		    (rdev->family <= CHIP_HAINAN) &&
 		    rdev->mc_fw) {
 			if (rdev->pm.default_vddc)
 				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -947,7 +1014,7 @@
 		radeon_pm_init_profile(rdev);
 		/* set up the default clocks if the MC ucode is loaded */
 		if ((rdev->family >= CHIP_BARTS) &&
-		    (rdev->family <= CHIP_CAYMAN) &&
+		    (rdev->family <= CHIP_HAINAN) &&
 		    rdev->mc_fw) {
 			if (rdev->pm.default_vddc)
 				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -1003,8 +1070,8 @@
 	int ret;
 
 	/* default to performance state */
-	rdev->pm.dpm.state = POWER_STATE_TYPE_PERFORMANCE;
-	rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
+	rdev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
+	rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
 	rdev->pm.default_sclk = rdev->clock.default_sclk;
 	rdev->pm.default_mclk = rdev->clock.default_mclk;
 	rdev->pm.current_sclk = rdev->clock.default_sclk;
@@ -1032,7 +1099,7 @@
 	if (ret) {
 		rdev->pm.dpm_enabled = false;
 		if ((rdev->family >= CHIP_BARTS) &&
-		    (rdev->family <= CHIP_CAYMAN) &&
+		    (rdev->family <= CHIP_HAINAN) &&
 		    rdev->mc_fw) {
 			if (rdev->pm.default_vddc)
 				radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -1055,6 +1122,9 @@
 		ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
 		if (ret)
 			DRM_ERROR("failed to create device file for dpm state\n");
+		ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
+		if (ret)
+			DRM_ERROR("failed to create device file for dpm state\n");
 		/* XXX: these are noops for dpm but are here for backwards compat */
 		ret = device_create_file(rdev->dev, &dev_attr_power_profile);
 		if (ret)
@@ -1062,6 +1132,11 @@
 		ret = device_create_file(rdev->dev, &dev_attr_power_method);
 		if (ret)
 			DRM_ERROR("failed to create device file for power method\n");
+
+		if (radeon_debugfs_pm_init(rdev)) {
+			DRM_ERROR("Failed to register debugfs file for dpm!\n");
+		}
+
 		DRM_INFO("radeon: dpm initialized\n");
 	}
 
@@ -1154,6 +1229,7 @@
 		mutex_unlock(&rdev->pm.mutex);
 
 		device_remove_file(rdev->dev, &dev_attr_power_dpm_state);
+		device_remove_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
 		/* XXX backwards compat */
 		device_remove_file(rdev->dev, &dev_attr_power_profile);
 		device_remove_file(rdev->dev, &dev_attr_power_method);
@@ -1183,7 +1259,6 @@
 	if (rdev->pm.num_power_states < 2)
 		return;
 
-	INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler);
 	mutex_lock(&rdev->pm.mutex);
 
 	rdev->pm.active_crtcs = 0;
@@ -1389,19 +1464,28 @@
 	struct drm_device *dev = node->minor->dev;
 	struct radeon_device *rdev = dev->dev_private;
 
-	seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk);
-	/* radeon_get_engine_clock is not reliable on APUs so just print the current clock */
-	if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP))
-		seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk);
-	else
-		seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
-	seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk);
-	if (rdev->asic->pm.get_memory_clock)
-		seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
-	if (rdev->pm.current_vddc)
-		seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc);
-	if (rdev->asic->pm.get_pcie_lanes)
-		seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));
+	if (rdev->pm.dpm_enabled) {
+		mutex_lock(&rdev->pm.mutex);
+		if (rdev->asic->dpm.debugfs_print_current_performance_level)
+			radeon_dpm_debugfs_print_current_performance_level(rdev, m);
+		else
+			seq_printf(m, "Debugfs support not implemented for this asic\n");
+		mutex_unlock(&rdev->pm.mutex);
+	} else {
+		seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk);
+		/* radeon_get_engine_clock is not reliable on APUs so just print the current clock */
+		if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP))
+			seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk);
+		else
+			seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
+		seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk);
+		if (rdev->asic->pm.get_memory_clock)
+			seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
+		if (rdev->pm.current_vddc)
+			seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc);
+		if (rdev->asic->pm.get_pcie_lanes)
+			seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 5f1c51a..fb5ea62 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -224,6 +224,7 @@
 	}
 	r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo,
 				      RADEON_IB_POOL_SIZE*64*1024,
+				      RADEON_GPU_PAGE_SIZE,
 				      RADEON_GEM_DOMAIN_GTT);
 	if (r) {
 		return r;
diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c
index 0abe5a9..f0bac68 100644
--- a/drivers/gpu/drm/radeon/radeon_sa.c
+++ b/drivers/gpu/drm/radeon/radeon_sa.c
@@ -49,7 +49,7 @@
 
 int radeon_sa_bo_manager_init(struct radeon_device *rdev,
 			      struct radeon_sa_manager *sa_manager,
-			      unsigned size, u32 domain)
+			      unsigned size, u32 align, u32 domain)
 {
 	int i, r;
 
@@ -57,13 +57,14 @@
 	sa_manager->bo = NULL;
 	sa_manager->size = size;
 	sa_manager->domain = domain;
+	sa_manager->align = align;
 	sa_manager->hole = &sa_manager->olist;
 	INIT_LIST_HEAD(&sa_manager->olist);
 	for (i = 0; i < RADEON_NUM_RINGS; ++i) {
 		INIT_LIST_HEAD(&sa_manager->flist[i]);
 	}
 
-	r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true,
+	r = radeon_bo_create(rdev, size, align, true,
 			     domain, NULL, &sa_manager->bo);
 	if (r) {
 		dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r);
@@ -317,7 +318,7 @@
 	unsigned tries[RADEON_NUM_RINGS];
 	int i, r;
 
-	BUG_ON(align > RADEON_GPU_PAGE_SIZE);
+	BUG_ON(align > sa_manager->align);
 	BUG_ON(size > sa_manager->size);
 
 	*sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL);
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index 41efcec..414fd14 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -56,20 +56,13 @@
 
 int radeon_uvd_init(struct radeon_device *rdev)
 {
-	struct platform_device *pdev;
+	const struct firmware *fw;
 	unsigned long bo_size;
 	const char *fw_name;
 	int i, r;
 
 	INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler);
 
-	pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0);
-	r = IS_ERR(pdev);
-	if (r) {
-		dev_err(rdev->dev, "radeon_uvd: Failed to register firmware\n");
-		return -EINVAL;
-	}
-
 	switch (rdev->family) {
 	case CHIP_RV710:
 	case CHIP_RV730:
@@ -112,17 +105,14 @@
 		return -EINVAL;
 	}
 
-	r = request_firmware(&rdev->uvd_fw, fw_name, &pdev->dev);
+	r = request_firmware(&fw, fw_name, rdev->dev);
 	if (r) {
 		dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
 			fw_name);
-		platform_device_unregister(pdev);
 		return r;
 	}
 
-	platform_device_unregister(pdev);
-
-	bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
+	bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) +
 		  RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
 	r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
 			     RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo);
@@ -131,64 +121,6 @@
 		return r;
 	}
 
-	r = radeon_uvd_resume(rdev);
-	if (r)
-		return r;
-
-	memset(rdev->uvd.cpu_addr, 0, bo_size);
-	memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size);
-
-	r = radeon_uvd_suspend(rdev);
-	if (r)
-		return r;
-
-	for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
-		atomic_set(&rdev->uvd.handles[i], 0);
-		rdev->uvd.filp[i] = NULL;
-	}
-
-	return 0;
-}
-
-void radeon_uvd_fini(struct radeon_device *rdev)
-{
-	radeon_uvd_suspend(rdev);
-	radeon_bo_unref(&rdev->uvd.vcpu_bo);
-}
-
-int radeon_uvd_suspend(struct radeon_device *rdev)
-{
-	int r;
-
-	if (rdev->uvd.vcpu_bo == NULL)
-		return 0;
-
-	r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
-	if (!r) {
-		radeon_bo_kunmap(rdev->uvd.vcpu_bo);
-		radeon_bo_unpin(rdev->uvd.vcpu_bo);
-		rdev->uvd.cpu_addr = NULL;
-		if (!radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_CPU, NULL)) {
-			radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr);
-		}
-		radeon_bo_unreserve(rdev->uvd.vcpu_bo);
-
-		if (rdev->uvd.cpu_addr) {
-			radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
-		} else {
-			rdev->fence_drv[R600_RING_TYPE_UVD_INDEX].cpu_addr = NULL;
-		}
-	}
-	return r;
-}
-
-int radeon_uvd_resume(struct radeon_device *rdev)
-{
-	int r;
-
-	if (rdev->uvd.vcpu_bo == NULL)
-		return -EINVAL;
-
 	r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
 	if (r) {
 		radeon_bo_unref(&rdev->uvd.vcpu_bo);
@@ -196,10 +128,6 @@
 		return r;
 	}
 
-	/* Have been pin in cpu unmap unpin */
-	radeon_bo_kunmap(rdev->uvd.vcpu_bo);
-	radeon_bo_unpin(rdev->uvd.vcpu_bo);
-
 	r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
 			  &rdev->uvd.gpu_addr);
 	if (r) {
@@ -217,6 +145,63 @@
 
 	radeon_bo_unreserve(rdev->uvd.vcpu_bo);
 
+	rdev->uvd.fw_size = fw->size;
+	memset(rdev->uvd.cpu_addr, 0, bo_size);
+	memcpy(rdev->uvd.cpu_addr, fw->data, fw->size);
+
+	release_firmware(fw);
+
+	for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
+		atomic_set(&rdev->uvd.handles[i], 0);
+		rdev->uvd.filp[i] = NULL;
+	}
+
+	return 0;
+}
+
+void radeon_uvd_fini(struct radeon_device *rdev)
+{
+	int r;
+
+	if (rdev->uvd.vcpu_bo == NULL)
+		return;
+
+	r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
+	if (!r) {
+		radeon_bo_kunmap(rdev->uvd.vcpu_bo);
+		radeon_bo_unpin(rdev->uvd.vcpu_bo);
+		radeon_bo_unreserve(rdev->uvd.vcpu_bo);
+	}
+
+	radeon_bo_unref(&rdev->uvd.vcpu_bo);
+}
+
+int radeon_uvd_suspend(struct radeon_device *rdev)
+{
+	unsigned size;
+
+	if (rdev->uvd.vcpu_bo == NULL)
+		return 0;
+
+	size = radeon_bo_size(rdev->uvd.vcpu_bo);
+	rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
+	memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size);
+
+	return 0;
+}
+
+int radeon_uvd_resume(struct radeon_device *rdev)
+{
+	if (rdev->uvd.vcpu_bo == NULL)
+		return -EINVAL;
+
+	if (rdev->uvd.saved_bo != NULL) {
+		unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo);
+		memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size);
+		kfree(rdev->uvd.saved_bo);
+		rdev->uvd.saved_bo = NULL;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
index bef832a..d1a1ce7 100644
--- a/drivers/gpu/drm/radeon/rs780_dpm.c
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -28,6 +28,7 @@
 #include "r600_dpm.h"
 #include "rs780_dpm.h"
 #include "atom.h"
+#include <linux/seq_file.h>
 
 static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
 {
@@ -961,3 +962,27 @@
 
 	return pi->bootup_uma_clk;
 }
+
+void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						       struct seq_file *m)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct igp_ps *ps = rs780_get_ps(rps);
+	u32 current_fb_div = RREG32(FVTHROT_STATUS_REG0) & CURRENT_FEEDBACK_DIV_MASK;
+	u32 func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
+	u32 ref_div = ((func_cntl & SPLL_REF_DIV_MASK) >> SPLL_REF_DIV_SHIFT) + 1;
+	u32 post_div = ((func_cntl & SPLL_SW_HILEN_MASK) >> SPLL_SW_HILEN_SHIFT) + 1 +
+		((func_cntl & SPLL_SW_LOLEN_MASK) >> SPLL_SW_LOLEN_SHIFT) + 1;
+	u32 sclk = (rdev->clock.spll.reference_freq * current_fb_div) /
+		(post_div * ref_div);
+
+	seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+
+	/* guess based on the current sclk */
+	if (sclk < (ps->sclk_low + 500))
+		seq_printf(m, "power level 0    sclk: %u vddc_index: %d\n",
+			   ps->sclk_low, ps->min_voltage);
+	else
+		seq_printf(m, "power level 1    sclk: %u vddc_index: %d\n",
+			   ps->sclk_high, ps->max_voltage);
+}
diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
index b1142ed..cfbe9a4 100644
--- a/drivers/gpu/drm/radeon/rs780d.h
+++ b/drivers/gpu/drm/radeon/rs780d.h
@@ -28,6 +28,7 @@
 #       define SPLL_SLEEP                                (1 << 1)
 #       define SPLL_REF_DIV(x)                           ((x) << 2)
 #       define SPLL_REF_DIV_MASK                         (7 << 2)
+#       define SPLL_REF_DIV_SHIFT                        2
 #       define SPLL_FB_DIV(x)                            ((x) << 5)
 #       define SPLL_FB_DIV_MASK                          (0xff << 2)
 #       define SPLL_FB_DIV_SHIFT                         2
@@ -36,8 +37,10 @@
 #       define SPLL_PULSENUM_MASK                        (3 << 14)
 #       define SPLL_SW_HILEN(x)                          ((x) << 16)
 #       define SPLL_SW_HILEN_MASK                        (0xf << 16)
+#       define SPLL_SW_HILEN_SHIFT                       16
 #       define SPLL_SW_LOLEN(x)                          ((x) << 20)
 #       define SPLL_SW_LOLEN_MASK                        (0xf << 20)
+#       define SPLL_SW_LOLEN_SHIFT                       20
 #       define SPLL_DIVEN                                (1 << 24)
 #       define SPLL_BYPASS_EN                            (1 << 25)
 #       define SPLL_CHG_STATUS                           (1 << 29)
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c
index 0e8b7d9..65e33f3 100644
--- a/drivers/gpu/drm/radeon/rv6xx_dpm.c
+++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c
@@ -28,6 +28,7 @@
 #include "r600_dpm.h"
 #include "rv6xx_dpm.h"
 #include "atom.h"
+#include <linux/seq_file.h>
 
 static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev,
 					u32 unscaled_count, u32 unit);
@@ -1762,12 +1763,14 @@
 {
 	r600_enable_acpi_pm(rdev);
 
-	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
-		rv6xx_enable_l0s(rdev);
-	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
-		rv6xx_enable_l1(rdev);
-	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
-		rv6xx_enable_pll_sleep_in_l1(rdev);
+	if (radeon_aspm != 0) {
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
+			rv6xx_enable_l0s(rdev);
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
+			rv6xx_enable_l1(rdev);
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
+			rv6xx_enable_pll_sleep_in_l1(rdev);
+	}
 }
 
 void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev)
@@ -2027,6 +2030,31 @@
 	r600_dpm_print_ps_status(rdev, rps);
 }
 
+void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						       struct seq_file *m)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+	struct rv6xx_pl *pl;
+	u32 current_index =
+		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+		CURRENT_PROFILE_INDEX_SHIFT;
+
+	if (current_index > 2) {
+		seq_printf(m, "invalid dpm profile %d\n", current_index);
+	} else {
+		if (current_index == 0)
+			pl = &ps->low;
+		else if (current_index == 1)
+			pl = &ps->medium;
+		else /* current_index == 2 */
+			pl = &ps->high;
+		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+		seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u\n",
+			   current_index, pl->sclk, pl->mclk, pl->vddc);
+	}
+}
+
 void rv6xx_dpm_fini(struct radeon_device *rdev)
 {
 	int i;
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 4a62ad2..30ea14e 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -813,7 +813,7 @@
 
 	/* programm the VCPU memory controller bits 0-27 */
 	addr = rdev->uvd.gpu_addr >> 3;
-	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
+	size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3;
 	WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
 	WREG32(UVD_VCPU_CACHE_SIZE0, size);
 
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 7f6fa62..2d34792 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -29,6 +29,7 @@
 #include "rv770_dpm.h"
 #include "cypress_dpm.h"
 #include "atom.h"
+#include <linux/seq_file.h>
 
 #define MC_CG_ARB_FREQ_F0           0x0a
 #define MC_CG_ARB_FREQ_F1           0x0b
@@ -1340,10 +1341,10 @@
 	u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
 
 	tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
-	if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) {
+	if (rdev->pm.dpm.new_active_crtcs & 1) {
 		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
 		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
-	} else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) {
+	} else if (rdev->pm.dpm.new_active_crtcs & 2) {
 		tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
 		tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
 	} else {
@@ -1470,13 +1471,29 @@
 	return 0;
 }
 
-int rv770_unrestrict_performance_levels_after_switch(struct radeon_device *rdev)
+int rv770_dpm_force_performance_level(struct radeon_device *rdev,
+				      enum radeon_dpm_forced_level level)
 {
-	if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_NoForcedLevel)) != PPSMC_Result_OK)
+	PPSMC_Msg msg;
+
+	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+		if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ZeroLevelsDisabled) != PPSMC_Result_OK)
+			return -EINVAL;
+		msg = PPSMC_MSG_ForceHigh;
+	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+		if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
+			return -EINVAL;
+		msg = (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled);
+	} else {
+		if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
+			return -EINVAL;
+		msg = (PPSMC_Msg)(PPSMC_MSG_ZeroLevelsDisabled);
+	}
+
+	if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK)
 		return -EINVAL;
 
-	if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_ZeroLevelsDisabled)) != PPSMC_Result_OK)
-		return -EINVAL;
+	rdev->pm.dpm.forced_level = level;
 
 	return 0;
 }
@@ -2046,9 +2063,10 @@
 	if (pi->dcodt)
 		rv770_program_dcodt_after_state_switch(rdev, new_ps, old_ps);
 	rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
-	ret = rv770_unrestrict_performance_levels_after_switch(rdev);
+
+	ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
 	if (ret) {
-		DRM_ERROR("rv770_unrestrict_performance_levels_after_switch failed\n");
+		DRM_ERROR("rv770_dpm_force_performance_level failed\n");
 		return ret;
 	}
 
@@ -2081,12 +2099,14 @@
 
 	rv770_enable_acpi_pm(rdev);
 
-	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
-		rv770_enable_l0s(rdev);
-	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
-		rv770_enable_l1(rdev);
-	if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
-		rv770_enable_pll_sleep_in_l1(rdev);
+	if (radeon_aspm != 0) {
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
+			rv770_enable_l0s(rdev);
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
+			rv770_enable_l1(rdev);
+		if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
+			rv770_enable_pll_sleep_in_l1(rdev);
+	}
 }
 
 void rv770_dpm_display_configuration_changed(struct radeon_device *rdev)
@@ -2430,6 +2450,36 @@
 	r600_dpm_print_ps_status(rdev, rps);
 }
 
+void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						       struct seq_file *m)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct rv7xx_ps *ps = rv770_get_ps(rps);
+	struct rv7xx_pl *pl;
+	u32 current_index =
+		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+		CURRENT_PROFILE_INDEX_SHIFT;
+
+	if (current_index > 2) {
+		seq_printf(m, "invalid dpm profile %d\n", current_index);
+	} else {
+		if (current_index == 0)
+			pl = &ps->low;
+		else if (current_index == 1)
+			pl = &ps->medium;
+		else /* current_index == 2 */
+			pl = &ps->high;
+		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+		if (rdev->family >= CHIP_CEDAR) {
+			seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u\n",
+				   current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+		} else {
+			seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u\n",
+				   current_index, pl->sclk, pl->mclk, pl->vddc);
+		}
+	}
+}
+
 void rv770_dpm_fini(struct radeon_device *rdev)
 {
 	int i;
@@ -2460,3 +2510,14 @@
 	else
 		return requested_state->high.mclk;
 }
+
+bool rv770_dpm_vblank_too_short(struct radeon_device *rdev)
+{
+	u32 vblank_time = r600_dpm_get_vblank_time(rdev);
+
+	if (vblank_time < 300)
+		return true;
+	else
+		return false;
+
+}
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
index f1e1fcf..96b1b2a 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.h
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -262,7 +262,8 @@
 void r7xx_stop_smc(struct radeon_device *rdev);
 void rv770_reset_smio_status(struct radeon_device *rdev);
 int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev);
-int rv770_unrestrict_performance_levels_after_switch(struct radeon_device *rdev);
+int rv770_dpm_force_performance_level(struct radeon_device *rdev,
+				      enum radeon_dpm_forced_level level);
 int rv770_halt_smc(struct radeon_device *rdev);
 int rv770_resume_smc(struct radeon_device *rdev);
 int rv770_set_sw_state(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index 784eeaf..6bef2b7 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -207,6 +207,10 @@
 #       define MUX_TCLK_TO_XCLK                           (1 << 8)
 #       define XTALIN_DIVIDE                              (1 << 9)
 
+#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x66c
+#       define CURRENT_PROFILE_INDEX_MASK                 (0xf << 4)
+#       define CURRENT_PROFILE_INDEX_SHIFT                4
+
 #define S0_VID_LOWER_SMIO_CNTL                            0x678
 #define S1_VID_LOWER_SMIO_CNTL                            0x67c
 #define S2_VID_LOWER_SMIO_CNTL                            0x680
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 2349067..d325280 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -22,7 +22,6 @@
  * Authors: Alex Deucher
  */
 #include <linux/firmware.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <drm/drmP.h>
@@ -1541,7 +1540,6 @@
 
 static int si_init_microcode(struct radeon_device *rdev)
 {
-	struct platform_device *pdev;
 	const char *chip_name;
 	const char *rlc_chip_name;
 	size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size;
@@ -1551,13 +1549,6 @@
 
 	DRM_DEBUG("\n");
 
-	pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
-	err = IS_ERR(pdev);
-	if (err) {
-		printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
-		return -EINVAL;
-	}
-
 	switch (rdev->family) {
 	case CHIP_TAHITI:
 		chip_name = "TAHITI";
@@ -1615,7 +1606,7 @@
 	DRM_INFO("Loading %s Microcode\n", chip_name);
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
-	err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->pfp_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->pfp_fw->size != pfp_req_size) {
@@ -1627,7 +1618,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
-	err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->me_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->me_fw->size != me_req_size) {
@@ -1638,7 +1629,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name);
-	err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->ce_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->ce_fw->size != ce_req_size) {
@@ -1649,7 +1640,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", rlc_chip_name);
-	err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->rlc_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->rlc_fw->size != rlc_req_size) {
@@ -1660,7 +1651,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
-	err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->mc_fw->size != mc_req_size) {
@@ -1671,7 +1662,7 @@
 	}
 
 	snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
-	err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+	err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
 	if (err)
 		goto out;
 	if (rdev->smc_fw->size != smc_req_size) {
@@ -1682,8 +1673,6 @@
 	}
 
 out:
-	platform_device_unregister(pdev);
-
 	if (err) {
 		if (err != -EINVAL)
 			printk(KERN_ERR
@@ -4401,6 +4390,270 @@
 }
 
 /**
+ * si_vm_decode_fault - print human readable fault info
+ *
+ * @rdev: radeon_device pointer
+ * @status: VM_CONTEXT1_PROTECTION_FAULT_STATUS register value
+ * @addr: VM_CONTEXT1_PROTECTION_FAULT_ADDR register value
+ *
+ * Print human readable fault information (SI).
+ */
+static void si_vm_decode_fault(struct radeon_device *rdev,
+			       u32 status, u32 addr)
+{
+	u32 mc_id = (status & MEMORY_CLIENT_ID_MASK) >> MEMORY_CLIENT_ID_SHIFT;
+	u32 vmid = (status & FAULT_VMID_MASK) >> FAULT_VMID_SHIFT;
+	u32 protections = (status & PROTECTIONS_MASK) >> PROTECTIONS_SHIFT;
+	char *block;
+
+	if (rdev->family == CHIP_TAHITI) {
+		switch (mc_id) {
+		case 160:
+		case 144:
+		case 96:
+		case 80:
+		case 224:
+		case 208:
+		case 32:
+		case 16:
+			block = "CB";
+			break;
+		case 161:
+		case 145:
+		case 97:
+		case 81:
+		case 225:
+		case 209:
+		case 33:
+		case 17:
+			block = "CB_FMASK";
+			break;
+		case 162:
+		case 146:
+		case 98:
+		case 82:
+		case 226:
+		case 210:
+		case 34:
+		case 18:
+			block = "CB_CMASK";
+			break;
+		case 163:
+		case 147:
+		case 99:
+		case 83:
+		case 227:
+		case 211:
+		case 35:
+		case 19:
+			block = "CB_IMMED";
+			break;
+		case 164:
+		case 148:
+		case 100:
+		case 84:
+		case 228:
+		case 212:
+		case 36:
+		case 20:
+			block = "DB";
+			break;
+		case 165:
+		case 149:
+		case 101:
+		case 85:
+		case 229:
+		case 213:
+		case 37:
+		case 21:
+			block = "DB_HTILE";
+			break;
+		case 167:
+		case 151:
+		case 103:
+		case 87:
+		case 231:
+		case 215:
+		case 39:
+		case 23:
+			block = "DB_STEN";
+			break;
+		case 72:
+		case 68:
+		case 64:
+		case 8:
+		case 4:
+		case 0:
+		case 136:
+		case 132:
+		case 128:
+		case 200:
+		case 196:
+		case 192:
+			block = "TC";
+			break;
+		case 112:
+		case 48:
+			block = "CP";
+			break;
+		case 49:
+		case 177:
+		case 50:
+		case 178:
+			block = "SH";
+			break;
+		case 53:
+		case 190:
+			block = "VGT";
+			break;
+		case 117:
+			block = "IH";
+			break;
+		case 51:
+		case 115:
+			block = "RLC";
+			break;
+		case 119:
+		case 183:
+			block = "DMA0";
+			break;
+		case 61:
+			block = "DMA1";
+			break;
+		case 248:
+		case 120:
+			block = "HDP";
+			break;
+		default:
+			block = "unknown";
+			break;
+		}
+	} else {
+		switch (mc_id) {
+		case 32:
+		case 16:
+		case 96:
+		case 80:
+		case 160:
+		case 144:
+		case 224:
+		case 208:
+			block = "CB";
+			break;
+		case 33:
+		case 17:
+		case 97:
+		case 81:
+		case 161:
+		case 145:
+		case 225:
+		case 209:
+			block = "CB_FMASK";
+			break;
+		case 34:
+		case 18:
+		case 98:
+		case 82:
+		case 162:
+		case 146:
+		case 226:
+		case 210:
+			block = "CB_CMASK";
+			break;
+		case 35:
+		case 19:
+		case 99:
+		case 83:
+		case 163:
+		case 147:
+		case 227:
+		case 211:
+			block = "CB_IMMED";
+			break;
+		case 36:
+		case 20:
+		case 100:
+		case 84:
+		case 164:
+		case 148:
+		case 228:
+		case 212:
+			block = "DB";
+			break;
+		case 37:
+		case 21:
+		case 101:
+		case 85:
+		case 165:
+		case 149:
+		case 229:
+		case 213:
+			block = "DB_HTILE";
+			break;
+		case 39:
+		case 23:
+		case 103:
+		case 87:
+		case 167:
+		case 151:
+		case 231:
+		case 215:
+			block = "DB_STEN";
+			break;
+		case 72:
+		case 68:
+		case 8:
+		case 4:
+		case 136:
+		case 132:
+		case 200:
+		case 196:
+			block = "TC";
+			break;
+		case 112:
+		case 48:
+			block = "CP";
+			break;
+		case 49:
+		case 177:
+		case 50:
+		case 178:
+			block = "SH";
+			break;
+		case 53:
+			block = "VGT";
+			break;
+		case 117:
+			block = "IH";
+			break;
+		case 51:
+		case 115:
+			block = "RLC";
+			break;
+		case 119:
+		case 183:
+			block = "DMA0";
+			break;
+		case 61:
+			block = "DMA1";
+			break;
+		case 248:
+		case 120:
+			block = "HDP";
+			break;
+		default:
+			block = "unknown";
+			break;
+		}
+	}
+
+	printk("VM fault (0x%02x, vmid %d) at page %u, %s from %s (%d)\n",
+	       protections, vmid, addr,
+	       (status & MEMORY_CLIENT_RW_MASK) ? "write" : "read",
+	       block, mc_id);
+}
+
+/**
  * si_vm_set_page - update the page tables using the CP
  *
  * @rdev: radeon_device pointer
@@ -5766,6 +6019,7 @@
 	u32 ring_index;
 	bool queue_hotplug = false;
 	bool queue_thermal = false;
+	u32 status, addr;
 
 	if (!rdev->ih.enabled || rdev->shutdown)
 		return IRQ_NONE;
@@ -6001,11 +6255,14 @@
 			break;
 		case 146:
 		case 147:
+			addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR);
+			status = RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS);
 			dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
 			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_ADDR   0x%08X\n",
-				RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+				addr);
 			dev_err(rdev->dev, "  VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
-				RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+				status);
+			si_vm_decode_fault(rdev, status, addr);
 			/* reset addr and status */
 			WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
 			break;
@@ -6796,6 +7053,9 @@
 	bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false;
 	bool disable_clkreq = false;
 
+	if (radeon_aspm == 0)
+		return;
+
 	if (!(rdev->flags & RADEON_IS_PCIE))
 		return;
 
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 6918f07..73aaa2e 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -28,6 +28,7 @@
 #include "si_dpm.h"
 #include "atom.h"
 #include <linux/math64.h>
+#include <linux/seq_file.h>
 
 #define MC_CG_ARB_FREQ_F0           0x0a
 #define MC_CG_ARB_FREQ_F1           0x0b
@@ -2905,7 +2906,8 @@
 	u16 vddc, vddci;
 	int i;
 
-	if (rdev->pm.dpm.new_active_crtc_count > 1)
+	if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
+	    ni_dpm_vblank_too_short(rdev))
 		disable_mclk_switching = true;
 	else
 		disable_mclk_switching = false;
@@ -3230,16 +3232,38 @@
 		0 : -EINVAL;
 }
 
-#if 0
-static int si_unrestrict_performance_levels_after_switch(struct radeon_device *rdev)
+int si_dpm_force_performance_level(struct radeon_device *rdev,
+				   enum radeon_dpm_forced_level level)
 {
-	if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
-		return -EINVAL;
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct ni_ps *ps = ni_get_ps(rps);
+	u32 levels;
 
-	return (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) == PPSMC_Result_OK) ?
-		0 : -EINVAL;
+	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+		if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+			return -EINVAL;
+
+		if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
+			return -EINVAL;
+	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+		if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
+			return -EINVAL;
+
+		levels = ps->performance_level_count - 1;
+		if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+			return -EINVAL;
+	} else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
+		if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
+			return -EINVAL;
+
+		if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+			return -EINVAL;
+	}
+
+	rdev->pm.dpm.forced_level = level;
+
+	return 0;
 }
-#endif
 
 static int si_set_boot_state(struct radeon_device *rdev)
 {
@@ -5991,11 +6015,13 @@
 
 #if 0
 	/* XXX */
-	ret = si_unrestrict_performance_levels_after_switch(rdev);
+	ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
 	if (ret) {
-		DRM_ERROR("si_unrestrict_performance_levels_after_switch failed\n");
+		DRM_ERROR("si_dpm_force_performance_level failed\n");
 		return ret;
 	}
+#else
+	rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
 #endif
 
 	return 0;
@@ -6385,3 +6411,22 @@
 	r600_free_extended_power_table(rdev);
 }
 
+void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						    struct seq_file *m)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct ni_ps *ps = ni_get_ps(rps);
+	struct rv7xx_pl *pl;
+	u32 current_index =
+		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+		CURRENT_STATE_INDEX_SHIFT;
+
+	if (current_index >= ps->performance_level_count) {
+		seq_printf(m, "invalid dpm profile %d\n", current_index);
+	} else {
+		pl = &ps->performance_levels[current_index];
+		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+		seq_printf(m, "power level %d    sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n",
+			   current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
+	}
+}
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
index 299d657..2c8da27 100644
--- a/drivers/gpu/drm/radeon/sid.h
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -220,6 +220,10 @@
 #       define GFX_CLK_OFF_ACPI_D3                        (1 << 13)
 #       define DYN_LIGHT_SLEEP_EN                         (1 << 14)
 
+#define TARGET_AND_CURRENT_PROFILE_INDEX                  0x798
+#       define CURRENT_STATE_INDEX_MASK                   (0xf << 4)
+#       define CURRENT_STATE_INDEX_SHIFT                  4
+
 #define CG_FTV                                            0x7bc
 
 #define CG_FFCT_0                                         0x7c0
@@ -363,6 +367,20 @@
 
 #define	VM_CONTEXT1_PROTECTION_FAULT_ADDR		0x14FC
 #define	VM_CONTEXT1_PROTECTION_FAULT_STATUS		0x14DC
+#define		PROTECTIONS_MASK			(0xf << 0)
+#define		PROTECTIONS_SHIFT			0
+		/* bit 0: range
+		 * bit 1: pde0
+		 * bit 2: valid
+		 * bit 3: read
+		 * bit 4: write
+		 */
+#define		MEMORY_CLIENT_ID_MASK			(0xff << 12)
+#define		MEMORY_CLIENT_ID_SHIFT			12
+#define		MEMORY_CLIENT_RW_MASK			(1 << 24)
+#define		MEMORY_CLIENT_RW_SHIFT			24
+#define		FAULT_VMID_MASK				(0xf << 25)
+#define		FAULT_VMID_SHIFT			25
 
 #define VM_INVALIDATE_REQUEST				0x1478
 #define VM_INVALIDATE_RESPONSE				0x147c
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index dbad293..c0a8503 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -27,6 +27,7 @@
 #include "r600_dpm.h"
 #include "cypress_dpm.h"
 #include "sumo_dpm.h"
+#include <linux/seq_file.h>
 
 #define SUMO_MAX_DEEPSLEEP_DIVIDER_ID 5
 #define SUMO_MINIMUM_ENGINE_CLOCK 800
@@ -810,6 +811,25 @@
 		sumo_power_level_enable(rdev, i, false);
 }
 
+static void sumo_setup_uvd_clocks(struct radeon_device *rdev,
+				  struct radeon_ps *new_rps,
+				  struct radeon_ps *old_rps)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+	if (pi->enable_gfx_power_gating) {
+		sumo_gfx_powergating_enable(rdev, false);
+	}
+
+	radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
+
+	if (pi->enable_gfx_power_gating) {
+		if (!pi->disable_gfx_power_gating_in_uvd ||
+		    !r600_is_uvd_state(new_rps->class, new_rps->class2))
+			sumo_gfx_powergating_enable(rdev, true);
+	}
+}
+
 static void sumo_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
 						    struct radeon_ps *new_rps,
 						    struct radeon_ps *old_rps)
@@ -825,7 +845,7 @@
 	    current_ps->levels[current_ps->num_levels - 1].sclk)
 		return;
 
-	radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
+	sumo_setup_uvd_clocks(rdev, new_rps, old_rps);
 }
 
 static void sumo_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
@@ -843,7 +863,7 @@
 	    current_ps->levels[current_ps->num_levels - 1].sclk)
 		return;
 
-	radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
+	sumo_setup_uvd_clocks(rdev, new_rps, old_rps);
 }
 
 void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
@@ -1133,22 +1153,6 @@
 	sumo_take_smu_control(rdev, false);
 }
 
-static void sumo_uvd_init(struct radeon_device *rdev)
-{
-	u32 tmp;
-
-	tmp = RREG32(CG_VCLK_CNTL);
-	tmp &= ~VCLK_DIR_CNTL_EN;
-	WREG32(CG_VCLK_CNTL, tmp);
-
-	tmp = RREG32(CG_DCLK_CNTL);
-	tmp &= ~DCLK_DIR_CNTL_EN;
-	WREG32(CG_DCLK_CNTL, tmp);
-
-	/* 100 Mhz */
-	radeon_set_uvd_clocks(rdev, 10000, 10000);
-}
-
 static int sumo_set_thermal_temperature_range(struct radeon_device *rdev,
 					      int min_temp, int max_temp)
 {
@@ -1315,6 +1319,8 @@
 	if (pi->enable_dpm)
 		sumo_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
+	rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
+
 	return 0;
 }
 
@@ -1348,7 +1354,6 @@
 	sumo_program_acpi_power_level(rdev);
 	sumo_enable_acpi_pm(rdev);
 	sumo_take_smu_control(rdev, true);
-	sumo_uvd_init(rdev);
 }
 
 void sumo_dpm_display_configuration_changed(struct radeon_device *rdev)
@@ -1727,7 +1732,13 @@
 	pi->enable_sclk_ds = true;
 	pi->enable_dynamic_m3_arbiter = false;
 	pi->enable_dynamic_patch_ps = true;
-	pi->enable_gfx_power_gating = true;
+	/* Some PALM chips don't seem to properly ungate gfx when UVD is in use;
+	 * for now just disable gfx PG.
+	 */
+	if (rdev->family == CHIP_PALM)
+		pi->enable_gfx_power_gating = false;
+	else
+		pi->enable_gfx_power_gating = true;
 	pi->enable_gfx_clock_gating = true;
 	pi->enable_mg_clock_gating = true;
 	pi->enable_auto_thermal_throttling = true;
@@ -1769,6 +1780,34 @@
 	r600_dpm_print_ps_status(rdev, rps);
 }
 
+void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+						      struct seq_file *m)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct sumo_ps *ps = sumo_get_ps(rps);
+	struct sumo_pl *pl;
+	u32 current_index =
+		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
+		CURR_INDEX_SHIFT;
+
+	if (current_index == BOOST_DPM_LEVEL) {
+		pl = &pi->boost_pl;
+		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
+			   current_index, pl->sclk,
+			   sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
+	} else if (current_index >= ps->num_levels) {
+		seq_printf(m, "invalid dpm profile %d\n", current_index);
+	} else {
+		pl = &ps->levels[current_index];
+		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
+			   current_index, pl->sclk,
+			   sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
+	}
+}
+
 void sumo_dpm_fini(struct radeon_device *rdev)
 {
 	int i;
@@ -1799,3 +1838,51 @@
 
 	return pi->sys_info.bootup_uma_clk;
 }
+
+int sumo_dpm_force_performance_level(struct radeon_device *rdev,
+				     enum radeon_dpm_forced_level level)
+{
+	struct sumo_power_info *pi = sumo_get_pi(rdev);
+	struct radeon_ps *rps = &pi->current_rps;
+	struct sumo_ps *ps = sumo_get_ps(rps);
+	int i;
+
+	if (ps->num_levels <= 1)
+		return 0;
+
+	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+		if (pi->enable_boost)
+			sumo_enable_boost(rdev, rps, false);
+		sumo_power_level_enable(rdev, ps->num_levels - 1, true);
+		sumo_set_forced_level(rdev, ps->num_levels - 1);
+		sumo_set_forced_mode_enabled(rdev);
+		for (i = 0; i < ps->num_levels - 1; i++) {
+			sumo_power_level_enable(rdev, i, false);
+		}
+		sumo_set_forced_mode(rdev, false);
+		sumo_set_forced_mode_enabled(rdev);
+		sumo_set_forced_mode(rdev, false);
+	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+		if (pi->enable_boost)
+			sumo_enable_boost(rdev, rps, false);
+		sumo_power_level_enable(rdev, 0, true);
+		sumo_set_forced_level(rdev, 0);
+		sumo_set_forced_mode_enabled(rdev);
+		for (i = 1; i < ps->num_levels; i++) {
+			sumo_power_level_enable(rdev, i, false);
+		}
+		sumo_set_forced_mode(rdev, false);
+		sumo_set_forced_mode_enabled(rdev);
+		sumo_set_forced_mode(rdev, false);
+	} else {
+		for (i = 0; i < ps->num_levels; i++) {
+			sumo_power_level_enable(rdev, i, true);
+		}
+		if (pi->enable_boost)
+			sumo_enable_boost(rdev, rps, true);
+	}
+
+	rdev->pm.dpm.forced_level = level;
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index fce825e..a1eb5f5 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -26,6 +26,7 @@
 #include "trinityd.h"
 #include "r600_dpm.h"
 #include "trinity_dpm.h"
+#include <linux/seq_file.h>
 
 #define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5
 #define TRINITY_MINIMUM_ENGINE_CLOCK 800
@@ -920,6 +921,10 @@
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
 
+	if (pi->enable_gfx_power_gating) {
+		trinity_gfx_powergating_enable(rdev, false);
+	}
+
 	if (pi->uvd_dpm) {
 		if (trinity_uvd_clocks_zero(new_rps) &&
 		    !trinity_uvd_clocks_zero(old_rps)) {
@@ -945,6 +950,10 @@
 
 		radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
 	}
+
+	if (pi->enable_gfx_power_gating) {
+		trinity_gfx_powergating_enable(rdev, true);
+	}
 }
 
 static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
@@ -1149,6 +1158,37 @@
 	}
 }
 
+int trinity_dpm_force_performance_level(struct radeon_device *rdev,
+					enum radeon_dpm_forced_level level)
+{
+	struct trinity_power_info *pi = trinity_get_pi(rdev);
+	struct radeon_ps *rps = &pi->current_rps;
+	struct trinity_ps *ps = trinity_get_ps(rps);
+	int i, ret;
+
+	if (ps->num_levels <= 1)
+		return 0;
+
+	if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+		/* not supported by the hw */
+		return -EINVAL;
+	} else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+		ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1);
+		if (ret)
+			return ret;
+	} else {
+		for (i = 0; i < ps->num_levels; i++) {
+			ret = trinity_dpm_n_levels_disabled(rdev, 0);
+			if (ret)
+				return ret;
+		}
+	}
+
+	rdev->pm.dpm.forced_level = level;
+
+	return 0;
+}
+
 int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
 {
 	struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1181,6 +1221,7 @@
 		trinity_force_level_0(rdev);
 		trinity_unforce_levels(rdev);
 		trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+		rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
 	}
 	trinity_release_mutex(rdev);
 
@@ -1855,6 +1896,27 @@
 	r600_dpm_print_ps_status(rdev, rps);
 }
 
+void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+							 struct seq_file *m)
+{
+	struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+	struct trinity_ps *ps = trinity_get_ps(rps);
+	struct trinity_pl *pl;
+	u32 current_index =
+		(RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
+		CURRENT_STATE_SHIFT;
+
+	if (current_index >= ps->num_levels) {
+		seq_printf(m, "invalid dpm profile %d\n", current_index);
+	} else {
+		pl = &ps->levels[current_index];
+		seq_printf(m, "uvd    vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+		seq_printf(m, "power level %d    sclk: %u vddc: %u\n",
+			   current_index, pl->sclk,
+			   trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
+	}
+}
+
 void trinity_dpm_fini(struct radeon_device *rdev)
 {
 	int i;
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.h b/drivers/gpu/drm/radeon/trinity_dpm.h
index c621b84..e82df07 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.h
+++ b/drivers/gpu/drm/radeon/trinity_dpm.h
@@ -121,6 +121,7 @@
 int trinity_dpm_config(struct radeon_device *rdev, bool enable);
 int trinity_uvd_dpm_config(struct radeon_device *rdev);
 int trinity_dpm_force_state(struct radeon_device *rdev, u32 n);
+int trinity_dpm_n_levels_disabled(struct radeon_device *rdev, u32 n);
 int trinity_dpm_no_forced_level(struct radeon_device *rdev);
 int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev,
 					  bool enable);
diff --git a/drivers/gpu/drm/radeon/trinity_smc.c b/drivers/gpu/drm/radeon/trinity_smc.c
index 85f86a2..a42d89f 100644
--- a/drivers/gpu/drm/radeon/trinity_smc.c
+++ b/drivers/gpu/drm/radeon/trinity_smc.c
@@ -73,6 +73,13 @@
 	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_ForceState);
 }
 
+int trinity_dpm_n_levels_disabled(struct radeon_device *rdev, u32 n)
+{
+	WREG32_SMC(SMU_SCRATCH0, n);
+
+	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_N_LevelsDisabled);
+}
+
 int trinity_uvd_dpm_config(struct radeon_device *rdev)
 {
 	return trinity_notify_message_to_smu(rdev, PPSMC_MSG_UVD_DPM_Config);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 003b34e..dc0fe09 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -249,9 +249,14 @@
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
-	.gem_prime_import	= drm_gem_cma_dmabuf_import,
-	.gem_prime_export	= drm_gem_cma_dmabuf_export,
-	.dumb_create		= drm_gem_cma_dumb_create,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_export	= drm_gem_prime_export,
+	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
+	.dumb_create		= rcar_du_dumb_create,
 	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
 	.dumb_destroy		= drm_gem_cma_dumb_destroy,
 	.fops			= &rcar_du_fops,
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 9c63f39..d30c2e2 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -138,11 +138,25 @@
  * Frame buffer
  */
 
+int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
+			struct drm_mode_create_dumb *args)
+{
+	unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+	unsigned int align;
+
+	/* The pitch must be aligned to a 16 pixels boundary. */
+	align = 16 * args->bpp / 8;
+	args->pitch = roundup(max(args->pitch, min_pitch), align);
+
+	return drm_gem_cma_dumb_create(file, dev, args);
+}
+
 static struct drm_framebuffer *
 rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
 		  struct drm_mode_fb_cmd2 *mode_cmd)
 {
 	const struct rcar_du_format_info *format;
+	unsigned int align;
 
 	format = rcar_du_format_info(mode_cmd->pixel_format);
 	if (format == NULL) {
@@ -151,7 +165,10 @@
 		return ERR_PTR(-EINVAL);
 	}
 
-	if (mode_cmd->pitches[0] & 15 || mode_cmd->pitches[0] >= 8192) {
+	align = 16 * format->bpp / 8;
+
+	if (mode_cmd->pitches[0] & (align - 1) ||
+	    mode_cmd->pitches[0] >= 8192) {
 		dev_dbg(dev->dev, "invalid pitch value %u\n",
 			mode_cmd->pitches[0]);
 		return ERR_PTR(-EINVAL);
@@ -191,8 +208,11 @@
 	if (ret < 0)
 		return ret;
 
-	for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i)
-		rcar_du_crtc_create(rcdu, i);
+	for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) {
+		ret = rcar_du_crtc_create(rcdu, i);
+		if (ret < 0)
+			return ret;
+	}
 
 	rcdu->used_crtcs = 0;
 	rcdu->num_crtcs = i;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/rcar-du/rcar_du_kms.h
index e4d8db0..dba4722 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.h
@@ -56,4 +56,7 @@
 
 int rcar_du_modeset_init(struct rcar_du_device *rcdu);
 
+int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
+			struct drm_mode_create_dumb *args);
+
 #endif /* __RCAR_DU_KMS_H__ */
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
index edc1018..5f83f9a 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
@@ -276,8 +276,13 @@
 	.gem_vm_ops		= &drm_gem_cma_vm_ops,
 	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
 	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
-	.gem_prime_import	= drm_gem_cma_dmabuf_import,
-	.gem_prime_export	= drm_gem_cma_dmabuf_export,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_export	= drm_gem_prime_export,
+	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
 	.dumb_create		= drm_gem_cma_dumb_create,
 	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
 	.dumb_destroy		= drm_gem_cma_dumb_destroy,
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 6e6975c..cb9dd67 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1455,9 +1455,7 @@
 		goto out_no_sys;
 
 	bdev->addr_space_rb = RB_ROOT;
-	ret = drm_mm_init(&bdev->addr_space_mm, file_page_offset, 0x10000000);
-	if (unlikely(ret != 0))
-		goto out_no_addr_mm;
+	drm_mm_init(&bdev->addr_space_mm, file_page_offset, 0x10000000);
 
 	INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue);
 	INIT_LIST_HEAD(&bdev->ddestroy);
@@ -1471,8 +1469,6 @@
 	mutex_unlock(&glob->device_list_mutex);
 
 	return 0;
-out_no_addr_mm:
-	ttm_bo_clean_mm(bdev, 0);
 out_no_sys:
 	return ret;
 }
diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c
index 9212494..e4367f9 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c
@@ -103,18 +103,12 @@
 			   unsigned long p_size)
 {
 	struct ttm_range_manager *rman;
-	int ret;
 
 	rman = kzalloc(sizeof(*rman), GFP_KERNEL);
 	if (!rman)
 		return -ENOMEM;
 
-	ret = drm_mm_init(&rman->mm, 0, p_size);
-	if (ret) {
-		kfree(rman);
-		return ret;
-	}
-
+	drm_mm_init(&rman->mm, 0, p_size);
 	spin_lock_init(&rman->lock);
 	man->priv = rman;
 	return 0;