drm/nouveau: port all engines to new engine module format

This is a HUGE commit, but it's not nearly as bad as it looks - any problems
can be isolated to a particular chipset and engine combination.  It was
simply too difficult to port each one at a time, the compat layers are
*already* ridiculous.

Most of the changes here are simply to the glue, the process for each of the
engine modules was to start with a standard skeleton and copy+paste the old
code into the appropriate places, fixing up variable names etc as needed.

v2: Marcin Slusarz <marcin.slusarz@gmail.com>
- fix find/replace bug in license header

v3: Ben Skeggs <bskeggs@redhat.com>
- bump indirect pushbuf size to 8KiB, 4KiB barely enough for userspace and
  left no space for kernel's requirements during GEM pushbuf submission.
- fix duplicate assignments noticed by clang

v4: Marcin Slusarz <marcin.slusarz@gmail.com>
- add sparse annotations to nv04_fifo_pause/nv04_fifo_start
- use ioread32_native/iowrite32_native for fifo control registers

v5: Ben Skeggs <bskeggs@redhat.com>
- rebase on v3.6-rc4, modified to keep copy engine fix intact
- nv10/fence: unmap fence bo before destroying
- fixed fermi regression when using nvidia gr fuc
- fixed typo in supported dma_mask checking

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
index b0795ec..e194701 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
@@ -2,7 +2,7 @@
 #define __NOUVEAU_GRCTX_H__
 
 struct nouveau_grctx {
-	struct drm_device *dev;
+	struct nouveau_device *device;
 
 	enum {
 		NOUVEAU_GRCTX_PROG,
@@ -10,18 +10,18 @@
 	} mode;
 	void *data;
 
-	uint32_t ctxprog_max;
-	uint32_t ctxprog_len;
-	uint32_t ctxprog_reg;
-	int      ctxprog_label[32];
-	uint32_t ctxvals_pos;
-	uint32_t ctxvals_base;
+	u32 ctxprog_max;
+	u32 ctxprog_len;
+	u32 ctxprog_reg;
+	int ctxprog_label[32];
+	u32 ctxvals_pos;
+	u32 ctxvals_base;
 };
 
 static inline void
-cp_out(struct nouveau_grctx *ctx, uint32_t inst)
+cp_out(struct nouveau_grctx *ctx, u32 inst)
 {
-	uint32_t *ctxprog = ctx->data;
+	u32 *ctxprog = ctx->data;
 
 	if (ctx->mode != NOUVEAU_GRCTX_PROG)
 		return;
@@ -31,13 +31,13 @@
 }
 
 static inline void
-cp_lsr(struct nouveau_grctx *ctx, uint32_t val)
+cp_lsr(struct nouveau_grctx *ctx, u32 val)
 {
 	cp_out(ctx, CP_LOAD_SR | val);
 }
 
 static inline void
-cp_ctx(struct nouveau_grctx *ctx, uint32_t reg, uint32_t length)
+cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length)
 {
 	ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
 
@@ -55,7 +55,7 @@
 static inline void
 cp_name(struct nouveau_grctx *ctx, int name)
 {
-	uint32_t *ctxprog = ctx->data;
+	u32 *ctxprog = ctx->data;
 	int i;
 
 	if (ctx->mode != NOUVEAU_GRCTX_PROG)
@@ -115,7 +115,7 @@
 }
 
 static inline void
-gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
+gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val)
 {
 	if (ctx->mode != NOUVEAU_GRCTX_VALS)
 		return;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
index b17506d..e45035e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
@@ -22,6 +22,8 @@
  * Authors: Ben Skeggs
  */
 
+#include <core/gpuobj.h>
+
 /* NVIDIA context programs handle a number of other conditions which are
  * not implemented in our versions.  It's not clear why NVIDIA context
  * programs have this code, nor whether it's strictly necessary for
@@ -109,8 +111,7 @@
 #define CP_LOAD_MAGIC_NV44TCL    0x00800029 /* per-vs state (0x4497) */
 #define CP_LOAD_MAGIC_NV40TCL    0x00800041 /* per-vs state (0x4097) */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include "nv40.h"
 #include "ctx.h"
 
 /* TODO:
@@ -118,11 +119,10 @@
  */
 
 static int
-nv40_graph_vs_count(struct drm_device *dev)
+nv40_graph_vs_count(struct nouveau_device *device)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -160,7 +160,7 @@
 static void
 nv40_graph_construct_general(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
 	cp_ctx(ctx, 0x4000a4, 1);
@@ -187,7 +187,7 @@
 	cp_ctx(ctx, 0x400724, 1);
 	gr_def(ctx, 0x400724, 0x02008821);
 	cp_ctx(ctx, 0x400770, 3);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x400814, 4);
 		cp_ctx(ctx, 0x400828, 5);
 		cp_ctx(ctx, 0x400840, 5);
@@ -208,7 +208,7 @@
 		gr_def(ctx, 0x4009dc, 0x80000000);
 	} else {
 		cp_ctx(ctx, 0x400840, 20);
-		if (nv44_graph_class(ctx->dev)) {
+		if (nv44_graph_class(ctx->device)) {
 			for (i = 0; i < 8; i++)
 				gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
 		}
@@ -217,21 +217,21 @@
 		gr_def(ctx, 0x400888, 0x00000040);
 		cp_ctx(ctx, 0x400894, 11);
 		gr_def(ctx, 0x400894, 0x00000040);
-		if (!nv44_graph_class(ctx->dev)) {
+		if (!nv44_graph_class(ctx->device)) {
 			for (i = 0; i < 8; i++)
 				gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
 		}
 		cp_ctx(ctx, 0x4008e0, 2);
 		cp_ctx(ctx, 0x4008f8, 2);
-		if (dev_priv->chipset == 0x4c ||
-		    (dev_priv->chipset & 0xf0) == 0x60)
+		if (device->chipset == 0x4c ||
+		    (device->chipset & 0xf0) == 0x60)
 			cp_ctx(ctx, 0x4009f8, 1);
 	}
 	cp_ctx(ctx, 0x400a00, 73);
 	gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
 	cp_ctx(ctx, 0x401000, 4);
 	cp_ctx(ctx, 0x405004, 1);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -240,7 +240,7 @@
 		break;
 	default:
 		cp_ctx(ctx, 0x403440, 1);
-		switch (dev_priv->chipset) {
+		switch (device->chipset) {
 		case 0x40:
 			gr_def(ctx, 0x403440, 0x00000010);
 			break;
@@ -266,19 +266,19 @@
 static void
 nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x401880, 51);
 		gr_def(ctx, 0x401940, 0x00000100);
 	} else
-	if (dev_priv->chipset == 0x46 || dev_priv->chipset == 0x47 ||
-	    dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) {
+	if (device->chipset == 0x46 || device->chipset == 0x47 ||
+	    device->chipset == 0x49 || device->chipset == 0x4b) {
 		cp_ctx(ctx, 0x401880, 32);
 		for (i = 0; i < 16; i++)
 			gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
-		if (dev_priv->chipset == 0x46)
+		if (device->chipset == 0x46)
 			cp_ctx(ctx, 0x401900, 16);
 		cp_ctx(ctx, 0x401940, 3);
 	}
@@ -289,7 +289,7 @@
 	gr_def(ctx, 0x401978, 0xffff0000);
 	gr_def(ctx, 0x40197c, 0x00000001);
 	gr_def(ctx, 0x401990, 0x46400000);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x4019a0, 2);
 		cp_ctx(ctx, 0x4019ac, 5);
 	} else {
@@ -297,7 +297,7 @@
 		cp_ctx(ctx, 0x4019b4, 3);
 	}
 	gr_def(ctx, 0x4019bc, 0xffff0000);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x46:
 	case 0x47:
 	case 0x49:
@@ -316,7 +316,7 @@
 	for (i = 0; i < 16; i++)
 		gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
 	gr_def(ctx, 0x401a8c, 0x4b7fffff);
-	if (dev_priv->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		cp_ctx(ctx, 0x401ab8, 3);
 	} else {
 		cp_ctx(ctx, 0x401ab8, 1);
@@ -327,10 +327,10 @@
 	gr_def(ctx, 0x401ad4, 0x70605040);
 	gr_def(ctx, 0x401ad8, 0xb8a89888);
 	gr_def(ctx, 0x401adc, 0xf8e8d8c8);
-	cp_ctx(ctx, 0x401b10, dev_priv->chipset == 0x40 ? 2 : 1);
+	cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
 	gr_def(ctx, 0x401b10, 0x40100000);
-	cp_ctx(ctx, 0x401b18, dev_priv->chipset == 0x40 ? 6 : 5);
-	gr_def(ctx, 0x401b28, dev_priv->chipset == 0x40 ?
+	cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
+	gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
 			      0x00000004 : 0x00000000);
 	cp_ctx(ctx, 0x401b30, 25);
 	gr_def(ctx, 0x401b34, 0x0000ffff);
@@ -341,8 +341,8 @@
 	gr_def(ctx, 0x401b84, 0xffffffff);
 	gr_def(ctx, 0x401b88, 0x00ff7000);
 	gr_def(ctx, 0x401b8c, 0x0000ffff);
-	if (dev_priv->chipset != 0x44 && dev_priv->chipset != 0x4a &&
-	    dev_priv->chipset != 0x4e)
+	if (device->chipset != 0x44 && device->chipset != 0x4a &&
+	    device->chipset != 0x4e)
 		cp_ctx(ctx, 0x401b94, 1);
 	cp_ctx(ctx, 0x401b98, 8);
 	gr_def(ctx, 0x401b9c, 0x00ff0000);
@@ -371,12 +371,12 @@
 static void
 nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 
 	cp_ctx(ctx, 0x402000, 1);
-	cp_ctx(ctx, 0x402404, dev_priv->chipset == 0x40 ? 1 : 2);
-	switch (dev_priv->chipset) {
+	cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
+	switch (device->chipset) {
 	case 0x40:
 		gr_def(ctx, 0x402404, 0x00000001);
 		break;
@@ -393,9 +393,9 @@
 	default:
 		gr_def(ctx, 0x402404, 0x00000021);
 	}
-	if (dev_priv->chipset != 0x40)
+	if (device->chipset != 0x40)
 		gr_def(ctx, 0x402408, 0x030c30c3);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x44:
 	case 0x46:
 	case 0x4a:
@@ -408,10 +408,10 @@
 	default:
 		break;
 	}
-	cp_ctx(ctx, 0x402480, dev_priv->chipset == 0x40 ? 8 : 9);
+	cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
 	gr_def(ctx, 0x402488, 0x3e020200);
 	gr_def(ctx, 0x40248c, 0x00ffffff);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x40:
 		gr_def(ctx, 0x402490, 0x60103f00);
 		break;
@@ -428,16 +428,16 @@
 		gr_def(ctx, 0x402490, 0x0c103f00);
 		break;
 	}
-	gr_def(ctx, 0x40249c, dev_priv->chipset <= 0x43 ?
+	gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
 			      0x00020000 : 0x00040000);
 	cp_ctx(ctx, 0x402500, 31);
 	gr_def(ctx, 0x402530, 0x00008100);
-	if (dev_priv->chipset == 0x40)
+	if (device->chipset == 0x40)
 		cp_ctx(ctx, 0x40257c, 6);
 	cp_ctx(ctx, 0x402594, 16);
 	cp_ctx(ctx, 0x402800, 17);
 	gr_def(ctx, 0x402800, 0x00000001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -445,7 +445,7 @@
 		gr_def(ctx, 0x402864, 0x00001001);
 		cp_ctx(ctx, 0x402870, 3);
 		gr_def(ctx, 0x402878, 0x00000003);
-		if (dev_priv->chipset != 0x47) { /* belong at end!! */
+		if (device->chipset != 0x47) { /* belong at end!! */
 			cp_ctx(ctx, 0x402900, 1);
 			cp_ctx(ctx, 0x402940, 1);
 			cp_ctx(ctx, 0x402980, 1);
@@ -470,9 +470,9 @@
 	}
 
 	cp_ctx(ctx, 0x402c00, 4);
-	gr_def(ctx, 0x402c00, dev_priv->chipset == 0x40 ?
+	gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
 			      0x80800001 : 0x00888001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x47:
 	case 0x49:
 	case 0x4b:
@@ -485,30 +485,30 @@
 		break;
 	default:
 		cp_ctx(ctx, 0x402c10, 4);
-		if (dev_priv->chipset == 0x40)
+		if (device->chipset == 0x40)
 			cp_ctx(ctx, 0x402c20, 36);
 		else
-		if (dev_priv->chipset <= 0x42)
+		if (device->chipset <= 0x42)
 			cp_ctx(ctx, 0x402c20, 24);
 		else
-		if (dev_priv->chipset <= 0x4a)
+		if (device->chipset <= 0x4a)
 			cp_ctx(ctx, 0x402c20, 16);
 		else
 			cp_ctx(ctx, 0x402c20, 8);
-		cp_ctx(ctx, 0x402cb0, dev_priv->chipset == 0x40 ? 12 : 13);
+		cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
 		gr_def(ctx, 0x402cd4, 0x00000005);
-		if (dev_priv->chipset != 0x40)
+		if (device->chipset != 0x40)
 			gr_def(ctx, 0x402ce0, 0x0000ffff);
 		break;
 	}
 
-	cp_ctx(ctx, 0x403400, dev_priv->chipset == 0x40 ? 4 : 3);
-	cp_ctx(ctx, 0x403410, dev_priv->chipset == 0x40 ? 4 : 3);
-	cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->dev));
-	for (i = 0; i < nv40_graph_vs_count(ctx->dev); i++)
+	cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
+	cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
+	cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->device));
+	for (i = 0; i < nv40_graph_vs_count(ctx->device); i++)
 		gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
 
-	if (dev_priv->chipset != 0x40) {
+	if (device->chipset != 0x40) {
 		cp_ctx(ctx, 0x403600, 1);
 		gr_def(ctx, 0x403600, 0x00000001);
 	}
@@ -516,7 +516,7 @@
 
 	cp_ctx(ctx, 0x403c18, 1);
 	gr_def(ctx, 0x403c18, 0x00000001);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x46:
 	case 0x47:
 	case 0x49:
@@ -527,7 +527,7 @@
 		gr_def(ctx, 0x405c24, 0x000e3000);
 		break;
 	}
-	if (dev_priv->chipset != 0x4e)
+	if (device->chipset != 0x4e)
 		cp_ctx(ctx, 0x405800, 11);
 	cp_ctx(ctx, 0x407000, 1);
 }
@@ -535,7 +535,7 @@
 static void
 nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
 {
-	int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684;
+	int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684;
 
 	cp_out (ctx, 0x300000);
 	cp_lsr (ctx, len - 4);
@@ -550,32 +550,31 @@
 static void
 nv40_graph_construct_shader(struct nouveau_grctx *ctx)
 {
-	struct drm_device *dev = ctx->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	struct nouveau_gpuobj *obj = ctx->data;
 	int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
 	int offset, i;
 
-	vs_nr    = nv40_graph_vs_count(ctx->dev);
+	vs_nr    = nv40_graph_vs_count(ctx->device);
 	vs_nr_b0 = 363;
-	vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64;
-	if (dev_priv->chipset == 0x40) {
+	vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
+	if (device->chipset == 0x40) {
 		b0_offset = 0x2200/4; /* 33a0 */
 		b1_offset = 0x55a0/4; /* 1500 */
 		vs_len = 0x6aa0/4;
 	} else
-	if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) {
+	if (device->chipset == 0x41 || device->chipset == 0x42) {
 		b0_offset = 0x2200/4; /* 2200 */
 		b1_offset = 0x4400/4; /* 0b00 */
 		vs_len = 0x4f00/4;
 	} else {
 		b0_offset = 0x1d40/4; /* 2200 */
 		b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
-		vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4;
+		vs_len = nv44_graph_class(device) ? 0x4980/4 : 0x4a40/4;
 	}
 
 	cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
-	cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041);
+	cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041);
 
 	offset = ctx->ctxvals_pos;
 	ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
@@ -661,21 +660,21 @@
 }
 
 void
-nv40_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
+nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
 {
 	nv40_grctx_generate(&(struct nouveau_grctx) {
-			     .dev = dev,
+			     .device = device,
 			     .mode = NOUVEAU_GRCTX_VALS,
 			     .data = mem,
 			   });
 }
 
 void
-nv40_grctx_init(struct drm_device *dev, u32 *size)
+nv40_grctx_init(struct nouveau_device *device, u32 *size)
 {
 	u32 ctxprog[256], i;
 	struct nouveau_grctx ctx = {
-		.dev = dev,
+		.device = device,
 		.mode = NOUVEAU_GRCTX_PROG,
 		.data = ctxprog,
 		.ctxprog_max = ARRAY_SIZE(ctxprog)
@@ -683,8 +682,8 @@
 
 	nv40_grctx_generate(&ctx);
 
-	nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+	nv_wr32(device, 0x400324, 0);
 	for (i = 0; i < ctx.ctxprog_len; i++)
-		nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, ctxprog[i]);
+		nv_wr32(device, 0x400328, ctxprog[i]);
 	*size = ctx.ctxvals_pos * 4;
 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
index e17c17b..552fdbd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
@@ -20,6 +20,8 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#include <core/gpuobj.h>
+
 #define CP_FLAG_CLEAR                 0
 #define CP_FLAG_SET                   1
 #define CP_FLAG_SWAP_DIRECTION        ((0 * 32) + 0)
@@ -105,8 +107,7 @@
 #define CP_SEEK_1      0x00c000ff
 #define CP_SEEK_2      0x00c800ff
 
-#include "drmP.h"
-#include "nouveau_drv.h"
+#include "nv50.h"
 #include "ctx.h"
 
 #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
@@ -175,32 +176,6 @@
 static int
 nv50_grctx_generate(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-
-	switch (dev_priv->chipset) {
-	case 0x50:
-	case 0x84:
-	case 0x86:
-	case 0x92:
-	case 0x94:
-	case 0x96:
-	case 0x98:
-	case 0xa0:
-	case 0xa3:
-	case 0xa5:
-	case 0xa8:
-	case 0xaa:
-	case 0xac:
-	case 0xaf:
-		break;
-	default:
-		NV_ERROR(ctx->dev, "I don't know how to make a ctxprog for "
-				   "your NV%x card.\n", dev_priv->chipset);
-		NV_ERROR(ctx->dev, "Disabling acceleration. Please contact "
-				   "the devs.\n");
-		return -ENOSYS;
-	}
-
 	cp_set (ctx, STATE, RUNNING);
 	cp_set (ctx, XFER_SWITCH, ENABLE);
 	/* decide whether we're loading/unloading the context */
@@ -278,30 +253,36 @@
 }
 
 void
-nv50_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
+nv50_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
 {
 	nv50_grctx_generate(&(struct nouveau_grctx) {
-			     .dev = dev,
+			     .device = device,
 			     .mode = NOUVEAU_GRCTX_VALS,
 			     .data = mem,
 			   });
 }
 
 int
-nv50_grctx_init(struct drm_device *dev, u32 *data, u32 max, u32 *len, u32 *cnt)
+nv50_grctx_init(struct nouveau_device *device, u32 *size)
 {
+	u32 *ctxprog = kmalloc(512 * 4, GFP_KERNEL), i;
 	struct nouveau_grctx ctx = {
-		.dev = dev,
+		.device = device,
 		.mode = NOUVEAU_GRCTX_PROG,
-		.data = data,
-		.ctxprog_max = max
+		.data = ctxprog,
+		.ctxprog_max = 512,
 	};
-	int ret;
 
-	ret = nv50_grctx_generate(&ctx);
-	*cnt = ctx.ctxvals_pos * 4;
-	*len = ctx.ctxprog_len;
-	return ret;
+	if (!ctxprog)
+		return -ENOMEM;
+	nv50_grctx_generate(&ctx);
+
+	nv_wr32(device, 0x400324, 0);
+	for (i = 0; i < ctx.ctxprog_len; i++)
+		nv_wr32(device, 0x400328, ctxprog[i]);
+	*size = ctx.ctxvals_pos * 4;
+	kfree(ctxprog);
+	return 0;
 }
 
 /*
@@ -315,36 +296,36 @@
 static void
 nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i, j;
 	int offset, base;
-	uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+	u32 units = nv_rd32 (ctx->device, 0x1540);
 
 	/* 0800: DISPATCH */
 	cp_ctx(ctx, 0x400808, 7);
 	gr_def(ctx, 0x400814, 0x00000030);
 	cp_ctx(ctx, 0x400834, 0x32);
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		gr_def(ctx, 0x400834, 0xff400040);
 		gr_def(ctx, 0x400838, 0xfff00080);
 		gr_def(ctx, 0x40083c, 0xfff70090);
 		gr_def(ctx, 0x400840, 0xffe806a8);
 	}
 	gr_def(ctx, 0x400844, 0x00000002);
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		gr_def(ctx, 0x400894, 0x00001000);
 	gr_def(ctx, 0x4008e8, 0x00000003);
 	gr_def(ctx, 0x4008ec, 0x00001000);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		cp_ctx(ctx, 0x400908, 0xb);
-	else if (dev_priv->chipset < 0xa0)
+	else if (device->chipset < 0xa0)
 		cp_ctx(ctx, 0x400908, 0xc);
 	else
 		cp_ctx(ctx, 0x400908, 0xe);
 
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		cp_ctx(ctx, 0x400b00, 0x1);
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		cp_ctx(ctx, 0x400b10, 0x1);
 		gr_def(ctx, 0x400b10, 0x0001629d);
 		cp_ctx(ctx, 0x400b20, 0x1);
@@ -358,10 +339,10 @@
 	gr_def(ctx, 0x400c08, 0x0000fe0c);
 
 	/* 1000 */
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		cp_ctx(ctx, 0x401008, 0x4);
 		gr_def(ctx, 0x401014, 0x00001000);
-	} else if (!IS_NVA3F(dev_priv->chipset)) {
+	} else if (!IS_NVA3F(device->chipset)) {
 		cp_ctx(ctx, 0x401008, 0x5);
 		gr_def(ctx, 0x401018, 0x00001000);
 	} else {
@@ -372,7 +353,7 @@
 	/* 1400 */
 	cp_ctx(ctx, 0x401400, 0x8);
 	cp_ctx(ctx, 0x401424, 0x3);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		gr_def(ctx, 0x40142c, 0x0001fd87);
 	else
 		gr_def(ctx, 0x40142c, 0x00000187);
@@ -382,10 +363,10 @@
 	/* 1800: STREAMOUT */
 	cp_ctx(ctx, 0x401814, 0x1);
 	gr_def(ctx, 0x401814, 0x000000ff);
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		cp_ctx(ctx, 0x40181c, 0xe);
 		gr_def(ctx, 0x401850, 0x00000004);
-	} else if (dev_priv->chipset < 0xa0) {
+	} else if (device->chipset < 0xa0) {
 		cp_ctx(ctx, 0x40181c, 0xf);
 		gr_def(ctx, 0x401854, 0x00000004);
 	} else {
@@ -395,7 +376,7 @@
 
 	/* 1C00 */
 	cp_ctx(ctx, 0x401c00, 0x1);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 		gr_def(ctx, 0x401c00, 0x0001005f);
 		break;
@@ -424,7 +405,7 @@
 
 	/* 2400 */
 	cp_ctx(ctx, 0x402400, 0x1);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		cp_ctx(ctx, 0x402408, 0x1);
 	else
 		cp_ctx(ctx, 0x402408, 0x2);
@@ -432,21 +413,21 @@
 
 	/* 2800: CSCHED */
 	cp_ctx(ctx, 0x402800, 0x1);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		gr_def(ctx, 0x402800, 0x00000006);
 
 	/* 2C00: ZCULL */
 	cp_ctx(ctx, 0x402c08, 0x6);
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		gr_def(ctx, 0x402c14, 0x01000000);
 	gr_def(ctx, 0x402c18, 0x000000ff);
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		cp_ctx(ctx, 0x402ca0, 0x1);
 	else
 		cp_ctx(ctx, 0x402ca0, 0x2);
-	if (dev_priv->chipset < 0xa0)
+	if (device->chipset < 0xa0)
 		gr_def(ctx, 0x402ca0, 0x00000400);
-	else if (!IS_NVA3F(dev_priv->chipset))
+	else if (!IS_NVA3F(device->chipset))
 		gr_def(ctx, 0x402ca0, 0x00000800);
 	else
 		gr_def(ctx, 0x402ca0, 0x00000400);
@@ -457,14 +438,14 @@
 	gr_def(ctx, 0x403004, 0x00000001);
 
 	/* 3400 */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		cp_ctx(ctx, 0x403404, 0x1);
 		gr_def(ctx, 0x403404, 0x00000001);
 	}
 
 	/* 5000: CCACHE */
 	cp_ctx(ctx, 0x405000, 0x1);
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 		gr_def(ctx, 0x405000, 0x00300080);
 		break;
@@ -493,22 +474,22 @@
 	cp_ctx(ctx, 0x40502c, 0x1);
 
 	/* 6000? */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		cp_ctx(ctx, 0x4063e0, 0x1);
 
 	/* 6800: M2MF */
-	if (dev_priv->chipset < 0x90) {
+	if (device->chipset < 0x90) {
 		cp_ctx(ctx, 0x406814, 0x2b);
 		gr_def(ctx, 0x406818, 0x00000f80);
 		gr_def(ctx, 0x406860, 0x007f0080);
 		gr_def(ctx, 0x40689c, 0x007f0080);
 	} else {
 		cp_ctx(ctx, 0x406814, 0x4);
-		if (dev_priv->chipset == 0x98)
+		if (device->chipset == 0x98)
 			gr_def(ctx, 0x406818, 0x00000f80);
 		else
 			gr_def(ctx, 0x406818, 0x00001f80);
-		if (IS_NVA3F(dev_priv->chipset))
+		if (IS_NVA3F(device->chipset))
 			gr_def(ctx, 0x40681c, 0x00000030);
 		cp_ctx(ctx, 0x406830, 0x3);
 	}
@@ -517,43 +498,43 @@
 	for (i = 0; i < 8; i++) {
 		if (units & (1<<(i+16))) {
 			cp_ctx(ctx, 0x407000 + (i<<8), 3);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820);
-			else if (dev_priv->chipset != 0xa5)
+			else if (device->chipset != 0xa5)
 				gr_def(ctx, 0x407000 + (i<<8), 0x3b74f821);
 			else
 				gr_def(ctx, 0x407000 + (i<<8), 0x7b74f821);
 			gr_def(ctx, 0x407004 + (i<<8), 0x89058001);
 
-			if (dev_priv->chipset == 0x50) {
+			if (device->chipset == 0x50) {
 				cp_ctx(ctx, 0x407010 + (i<<8), 1);
-			} else if (dev_priv->chipset < 0xa0) {
+			} else if (device->chipset < 0xa0) {
 				cp_ctx(ctx, 0x407010 + (i<<8), 2);
 				gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
 				gr_def(ctx, 0x407014 + (i<<8), 0x0000001f);
 			} else {
 				cp_ctx(ctx, 0x407010 + (i<<8), 3);
 				gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
-				if (dev_priv->chipset != 0xa5)
+				if (device->chipset != 0xa5)
 					gr_def(ctx, 0x407014 + (i<<8), 0x000000ff);
 				else
 					gr_def(ctx, 0x407014 + (i<<8), 0x000001ff);
 			}
 
 			cp_ctx(ctx, 0x407080 + (i<<8), 4);
-			if (dev_priv->chipset != 0xa5)
+			if (device->chipset != 0xa5)
 				gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa);
 			else
 				gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, 0x407084 + (i<<8), 0x000000c0);
 			else
 				gr_def(ctx, 0x407084 + (i<<8), 0x400000c0);
 			gr_def(ctx, 0x407088 + (i<<8), 0xb7892080);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				cp_ctx(ctx, 0x407094 + (i<<8), 1);
-			else if (!IS_NVA3F(dev_priv->chipset))
+			else if (!IS_NVA3F(device->chipset))
 				cp_ctx(ctx, 0x407094 + (i<<8), 3);
 			else {
 				cp_ctx(ctx, 0x407094 + (i<<8), 4);
@@ -563,30 +544,30 @@
 	}
 
 	cp_ctx(ctx, 0x407c00, 0x3);
-	if (dev_priv->chipset < 0x90)
+	if (device->chipset < 0x90)
 		gr_def(ctx, 0x407c00, 0x00010040);
-	else if (dev_priv->chipset < 0xa0)
+	else if (device->chipset < 0xa0)
 		gr_def(ctx, 0x407c00, 0x00390040);
 	else
 		gr_def(ctx, 0x407c00, 0x003d0040);
 	gr_def(ctx, 0x407c08, 0x00000022);
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		cp_ctx(ctx, 0x407c10, 0x3);
 		cp_ctx(ctx, 0x407c20, 0x1);
 		cp_ctx(ctx, 0x407c2c, 0x1);
 	}
 
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		cp_ctx(ctx, 0x407d00, 0x9);
 	} else {
 		cp_ctx(ctx, 0x407d00, 0x15);
 	}
-	if (dev_priv->chipset == 0x98)
+	if (device->chipset == 0x98)
 		gr_def(ctx, 0x407d08, 0x00380040);
 	else {
-		if (dev_priv->chipset < 0x90)
+		if (device->chipset < 0x90)
 			gr_def(ctx, 0x407d08, 0x00010040);
-		else if (dev_priv->chipset < 0xa0)
+		else if (device->chipset < 0xa0)
 			gr_def(ctx, 0x407d08, 0x00390040);
 		else
 			gr_def(ctx, 0x407d08, 0x003d0040);
@@ -596,11 +577,11 @@
 	/* 8000+: per-TP state */
 	for (i = 0; i < 10; i++) {
 		if (units & (1<<i)) {
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				base = 0x408000 + (i<<12);
 			else
 				base = 0x408000 + (i<<11);
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				offset = base + 0xc00;
 			else
 				offset = base + 0x80;
@@ -609,9 +590,9 @@
 			cp_ctx(ctx, offset + 0x08, 1);
 
 			/* per-MP state */
-			for (j = 0; j < (dev_priv->chipset < 0xa0 ? 2 : 4); j++) {
+			for (j = 0; j < (device->chipset < 0xa0 ? 2 : 4); j++) {
 				if (!(units & (1 << (j+24)))) continue;
-				if (dev_priv->chipset < 0xa0)
+				if (device->chipset < 0xa0)
 					offset = base + 0x200 + (j<<7);
 				else
 					offset = base + 0x100 + (j<<7);
@@ -620,7 +601,7 @@
 				gr_def(ctx, offset + 0x04, 0x00160000);
 				gr_def(ctx, offset + 0x08, 0x01800000);
 				gr_def(ctx, offset + 0x18, 0x0003ffff);
-				switch (dev_priv->chipset) {
+				switch (device->chipset) {
 				case 0x50:
 					gr_def(ctx, offset + 0x1c, 0x00080000);
 					break;
@@ -651,53 +632,53 @@
 					break;
 				}
 				gr_def(ctx, offset + 0x40, 0x00010401);
-				if (dev_priv->chipset == 0x50)
+				if (device->chipset == 0x50)
 					gr_def(ctx, offset + 0x48, 0x00000040);
 				else
 					gr_def(ctx, offset + 0x48, 0x00000078);
 				gr_def(ctx, offset + 0x50, 0x000000bf);
 				gr_def(ctx, offset + 0x58, 0x00001210);
-				if (dev_priv->chipset == 0x50)
+				if (device->chipset == 0x50)
 					gr_def(ctx, offset + 0x5c, 0x00000080);
 				else
 					gr_def(ctx, offset + 0x5c, 0x08000080);
-				if (dev_priv->chipset >= 0xa0)
+				if (device->chipset >= 0xa0)
 					gr_def(ctx, offset + 0x68, 0x0000003e);
 			}
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				cp_ctx(ctx, base + 0x300, 0x4);
 			else
 				cp_ctx(ctx, base + 0x300, 0x5);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, base + 0x304, 0x00007070);
-			else if (dev_priv->chipset < 0xa0)
+			else if (device->chipset < 0xa0)
 				gr_def(ctx, base + 0x304, 0x00027070);
-			else if (!IS_NVA3F(dev_priv->chipset))
+			else if (!IS_NVA3F(device->chipset))
 				gr_def(ctx, base + 0x304, 0x01127070);
 			else
 				gr_def(ctx, base + 0x304, 0x05127070);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				cp_ctx(ctx, base + 0x318, 1);
 			else
 				cp_ctx(ctx, base + 0x320, 1);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, base + 0x318, 0x0003ffff);
-			else if (dev_priv->chipset < 0xa0)
+			else if (device->chipset < 0xa0)
 				gr_def(ctx, base + 0x318, 0x03ffffff);
 			else
 				gr_def(ctx, base + 0x320, 0x07ffffff);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				cp_ctx(ctx, base + 0x324, 5);
 			else
 				cp_ctx(ctx, base + 0x328, 4);
 
-			if (dev_priv->chipset < 0xa0) {
+			if (device->chipset < 0xa0) {
 				cp_ctx(ctx, base + 0x340, 9);
 				offset = base + 0x340;
-			} else if (!IS_NVA3F(dev_priv->chipset)) {
+			} else if (!IS_NVA3F(device->chipset)) {
 				cp_ctx(ctx, base + 0x33c, 0xb);
 				offset = base + 0x344;
 			} else {
@@ -706,12 +687,12 @@
 			}
 			gr_def(ctx, offset + 0x0, 0x00120407);
 			gr_def(ctx, offset + 0x4, 0x05091507);
-			if (dev_priv->chipset == 0x84)
+			if (device->chipset == 0x84)
 				gr_def(ctx, offset + 0x8, 0x05100202);
 			else
 				gr_def(ctx, offset + 0x8, 0x05010202);
 			gr_def(ctx, offset + 0xc, 0x00030201);
-			if (dev_priv->chipset == 0xa3)
+			if (device->chipset == 0xa3)
 				cp_ctx(ctx, base + 0x36c, 1);
 
 			cp_ctx(ctx, base + 0x400, 2);
@@ -720,7 +701,7 @@
 			gr_def(ctx, base + 0x40c, 0x0d0c0b0a);
 			gr_def(ctx, base + 0x410, 0x00141210);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				offset = base + 0x800;
 			else
 				offset = base + 0x500;
@@ -728,55 +709,55 @@
 			gr_def(ctx, offset + 0x0, 0x000001f0);
 			gr_def(ctx, offset + 0x4, 0x00000001);
 			gr_def(ctx, offset + 0x8, 0x00000003);
-			if (dev_priv->chipset == 0x50 || IS_NVAAF(dev_priv->chipset))
+			if (device->chipset == 0x50 || IS_NVAAF(device->chipset))
 				gr_def(ctx, offset + 0xc, 0x00008000);
 			gr_def(ctx, offset + 0x14, 0x00039e00);
 			cp_ctx(ctx, offset + 0x1c, 2);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, offset + 0x1c, 0x00000040);
 			else
 				gr_def(ctx, offset + 0x1c, 0x00000100);
 			gr_def(ctx, offset + 0x20, 0x00003800);
 
-			if (dev_priv->chipset >= 0xa0) {
+			if (device->chipset >= 0xa0) {
 				cp_ctx(ctx, base + 0x54c, 2);
-				if (!IS_NVA3F(dev_priv->chipset))
+				if (!IS_NVA3F(device->chipset))
 					gr_def(ctx, base + 0x54c, 0x003fe006);
 				else
 					gr_def(ctx, base + 0x54c, 0x003fe007);
 				gr_def(ctx, base + 0x550, 0x003fe000);
 			}
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				offset = base + 0xa00;
 			else
 				offset = base + 0x680;
 			cp_ctx(ctx, offset, 1);
 			gr_def(ctx, offset, 0x00404040);
 
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				offset = base + 0xe00;
 			else
 				offset = base + 0x700;
 			cp_ctx(ctx, offset, 2);
-			if (dev_priv->chipset < 0xa0)
+			if (device->chipset < 0xa0)
 				gr_def(ctx, offset, 0x0077f005);
-			else if (dev_priv->chipset == 0xa5)
+			else if (device->chipset == 0xa5)
 				gr_def(ctx, offset, 0x6cf7f007);
-			else if (dev_priv->chipset == 0xa8)
+			else if (device->chipset == 0xa8)
 				gr_def(ctx, offset, 0x6cfff007);
-			else if (dev_priv->chipset == 0xac)
+			else if (device->chipset == 0xac)
 				gr_def(ctx, offset, 0x0cfff007);
 			else
 				gr_def(ctx, offset, 0x0cf7f007);
-			if (dev_priv->chipset == 0x50)
+			if (device->chipset == 0x50)
 				gr_def(ctx, offset + 0x4, 0x00007fff);
-			else if (dev_priv->chipset < 0xa0)
+			else if (device->chipset < 0xa0)
 				gr_def(ctx, offset + 0x4, 0x003f7fff);
 			else
 				gr_def(ctx, offset + 0x4, 0x02bf7fff);
 			cp_ctx(ctx, offset + 0x2c, 1);
-			if (dev_priv->chipset == 0x50) {
+			if (device->chipset == 0x50) {
 				cp_ctx(ctx, offset + 0x50, 9);
 				gr_def(ctx, offset + 0x54, 0x000003ff);
 				gr_def(ctx, offset + 0x58, 0x00000003);
@@ -785,7 +766,7 @@
 				gr_def(ctx, offset + 0x64, 0x0000001f);
 				gr_def(ctx, offset + 0x68, 0x0000000f);
 				gr_def(ctx, offset + 0x6c, 0x0000000f);
-			} else if (dev_priv->chipset < 0xa0) {
+			} else if (device->chipset < 0xa0) {
 				cp_ctx(ctx, offset + 0x50, 1);
 				cp_ctx(ctx, offset + 0x70, 1);
 			} else {
@@ -797,7 +778,7 @@
 }
 
 static void
-dd_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
+dd_emit(struct nouveau_grctx *ctx, int num, u32 val) {
 	int i;
 	if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
 		for (i = 0; i < num; i++)
@@ -808,7 +789,7 @@
 static void
 nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int base, num;
 	base = ctx->ctxvals_pos;
 
@@ -822,7 +803,7 @@
 	dd_emit(ctx, 1, 1);	/* 00000001 SRC_LINEAR #1 */
 	dd_emit(ctx, 1, 0);	/* 000000ff SRC_ADDRESS_HIGH */
 	dd_emit(ctx, 1, 0);	/* 00000001 SRC_SRGB */
-	if (dev_priv->chipset >= 0x94)
+	if (device->chipset >= 0x94)
 		dd_emit(ctx, 1, 0);	/* 00000003 eng2d UNK0258 */
 	dd_emit(ctx, 1, 1);	/* 00000fff SRC_DEPTH */
 	dd_emit(ctx, 1, 0x100);	/* 0000ffff SRC_HEIGHT */
@@ -851,7 +832,7 @@
 	dd_emit(ctx, 1, 1);		/* 0000007f BLOCKDIM_Z */
 	dd_emit(ctx, 1, 4);		/* 000000ff CP_REG_ALLOC_TEMP */
 	dd_emit(ctx, 1, 1);		/* 00000001 BLOCKDIM_DIRTY */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		dd_emit(ctx, 1, 0);	/* 00000003 UNK03E8 */
 	dd_emit(ctx, 1, 1);		/* 0000007f BLOCK_ALLOC_HALFWARPS */
 	dd_emit(ctx, 1, 1);		/* 00000007 LOCAL_WARPS_NO_CLAMP */
@@ -863,7 +844,7 @@
 	dd_emit(ctx, 1, 1);		/* 000007ff BLOCK_ALLOC_THREADS */
 
 	/* compat 2d state */
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		dd_emit(ctx, 4, 0);		/* 0000ffff clip X, Y, W, H */
 
 		dd_emit(ctx, 1, 1);		/* ffffffff chroma COLOR_FORMAT */
@@ -923,7 +904,7 @@
 	dd_emit(ctx, 1, 0x100);		/* ffffffff m2mf TILING_PITCH_IN */
 
 	/* more compat 2d state */
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		dd_emit(ctx, 1, 1);		/* ffffffff line COLOR_FORMAT */
 		dd_emit(ctx, 1, 0);		/* ffffffff line OPERATION */
 
@@ -957,18 +938,18 @@
 	dd_emit(ctx, 1, 0);		/* 000000ff UNK12B0_2 */
 	dd_emit(ctx, 1, 0);		/* 0000000f FP_TEXTURES_LOG2 */
 	dd_emit(ctx, 1, 0);		/* 0000000f FP_SAMPLERS_LOG2 */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		dd_emit(ctx, 1, 0);	/* ffffffff */
 		dd_emit(ctx, 1, 0);	/* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
 	} else {
 		dd_emit(ctx, 1, 0);	/* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
 	}
 	dd_emit(ctx, 1, 0xc);		/* 000000ff SEMANTIC_COLOR.BFC0_ID */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 1, 0);	/* 00000001 SEMANTIC_COLOR.CLMP_EN */
 	dd_emit(ctx, 1, 8);		/* 000000ff SEMANTIC_COLOR.COLR_NR */
 	dd_emit(ctx, 1, 0x14);		/* 000000ff SEMANTIC_COLOR.FFC0_ID */
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		dd_emit(ctx, 1, 0);	/* 000000ff SEMANTIC_LAYER */
 		dd_emit(ctx, 1, 0);	/* 00000001 */
 	} else {
@@ -994,7 +975,7 @@
 	dd_emit(ctx, 8, 0);		/* ffffffff RT_ADDRESS_LOW */
 	dd_emit(ctx, 1, 0xcf);		/* 000000ff RT_FORMAT */
 	dd_emit(ctx, 7, 0);		/* 000000ff RT_FORMAT */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 3, 0);	/* 1, 1, 1 */
 	else
 		dd_emit(ctx, 2, 0);	/* 1, 1 */
@@ -1002,15 +983,15 @@
 	dd_emit(ctx, 1, 0x80);		/* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
 	dd_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
 	dd_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		dd_emit(ctx, 1, 3);	/* 00000003 */
 		dd_emit(ctx, 1, 0);	/* 00000001 UNK1418. Alone. */
 	}
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 1, 3);	/* 00000003 UNK15AC */
 	dd_emit(ctx, 1, 1);		/* ffffffff RASTERIZE_ENABLE */
 	dd_emit(ctx, 1, 0);		/* 00000001 FP_CONTROL.EXPORTS_Z */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 1, 0);	/* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
 	dd_emit(ctx, 1, 0x12);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT */
 	dd_emit(ctx, 1, 0x10);		/* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
@@ -1022,16 +1003,16 @@
 	dd_emit(ctx, 1, 4);		/* 000000ff FP_RESULT_COUNT */
 	dd_emit(ctx, 1, 2);		/* ffffffff REG_MODE */
 	dd_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		dd_emit(ctx, 1, 0);	/* ffffffff */
 	dd_emit(ctx, 1, 0);		/* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
 	dd_emit(ctx, 1, 0);		/* ffffffff STRMOUT_ENABLE */
 	dd_emit(ctx, 1, 0x3fffff);	/* 003fffff TIC_LIMIT */
 	dd_emit(ctx, 1, 0x1fff);	/* 000fffff TSC_LIMIT */
 	dd_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE*/
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		dd_emit(ctx, 8, 0);	/* 00000001 */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.COMP */
 		dd_emit(ctx, 1, 1);	/* 00000007 VTX_ATTR_DEFINE.SIZE */
 		dd_emit(ctx, 1, 2);	/* 00000007 VTX_ATTR_DEFINE.TYPE */
@@ -1042,20 +1023,20 @@
 	dd_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	dd_emit(ctx, 1, 0);		/* 0000000f VP_TEXTURES_LOG2 */
 	dd_emit(ctx, 1, 0);		/* 0000000f VP_SAMPLERS_LOG2 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		dd_emit(ctx, 1, 0);	/* 00000001 */
 	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_BACK */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		dd_emit(ctx, 1, 0);	/* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
 	dd_emit(ctx, 1, 0);		/* 0000ffff CB_ADDR_INDEX */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		dd_emit(ctx, 1, 0);	/* 00000003 */
 	dd_emit(ctx, 1, 0);		/* 00000001 CULL_FACE_ENABLE */
 	dd_emit(ctx, 1, 1);		/* 00000003 CULL_FACE */
 	dd_emit(ctx, 1, 0);		/* 00000001 FRONT_FACE */
 	dd_emit(ctx, 1, 2);		/* 00000003 POLYGON_MODE_FRONT */
 	dd_emit(ctx, 1, 0x1000);	/* 00007fff UNK141C */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		dd_emit(ctx, 1, 0xe00);		/* 7fff */
 		dd_emit(ctx, 1, 0x1000);	/* 7fff */
 		dd_emit(ctx, 1, 0x1e00);	/* 7fff */
@@ -1070,10 +1051,10 @@
 	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
 	dd_emit(ctx, 1, 0);		/* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
 	dd_emit(ctx, 1, 0x200);		/* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		dd_emit(ctx, 1, 0x200);
 	dd_emit(ctx, 1, 0);		/* 00000001 */
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		dd_emit(ctx, 1, 1);	/* 00000001 */
 		dd_emit(ctx, 1, 0x70);	/* 000000ff */
 		dd_emit(ctx, 1, 0x80);	/* 000000ff */
@@ -1120,7 +1101,7 @@
 
 	num = ctx->ctxvals_pos - base;
 	ctx->ctxvals_pos = base;
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		cp_ctx(ctx, 0x404800, num);
 	else
 		cp_ctx(ctx, 0x405400, num);
@@ -1169,7 +1150,7 @@
  */
 
 static void
-xf_emit(struct nouveau_grctx *ctx, int num, uint32_t val) {
+xf_emit(struct nouveau_grctx *ctx, int num, u32 val) {
 	int i;
 	if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
 		for (i = 0; i < num; i++)
@@ -1201,16 +1182,16 @@
 static void
 nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 	int offset;
 	int size = 0;
-	uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+	u32 units = nv_rd32 (ctx->device, 0x1540);
 
 	offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
 	ctx->ctxvals_base = offset;
 
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		/* Strand 0 */
 		ctx->ctxvals_pos = offset;
 		nv50_graph_construct_gene_dispatch(ctx);
@@ -1280,7 +1261,7 @@
 
 		/* Strand 2 */
 		ctx->ctxvals_pos = offset + 2;
-		if (dev_priv->chipset == 0xa0)
+		if (device->chipset == 0xa0)
 			nv50_graph_construct_gene_unk14xx(ctx);
 		nv50_graph_construct_gene_unk24xx(ctx);
 		if ((ctx->ctxvals_pos-offset)/8 > size)
@@ -1327,7 +1308,7 @@
 
 		/* Strand 7 */
 		ctx->ctxvals_pos = offset + 7;
-		if (dev_priv->chipset == 0xa0) {
+		if (device->chipset == 0xa0) {
 			if (units & (1 << 4))
 				nv50_graph_construct_xfer_tp(ctx);
 			if (units & (1 << 5))
@@ -1365,24 +1346,24 @@
 nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx)
 {
 	/* start of strand 0 */
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* SEEK */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 5, 0);
-	else if (!IS_NVA3F(dev_priv->chipset))
+	else if (!IS_NVA3F(device->chipset))
 		xf_emit(ctx, 6, 0);
 	else
 		xf_emit(ctx, 4, 0);
 	/* SEEK */
 	/* the PGRAPH's internal FIFO */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 8*3, 0);
 	else
 		xf_emit(ctx, 0x100*3, 0);
 	/* and another bonus slot?!? */
 	xf_emit(ctx, 3, 0);
 	/* and YET ANOTHER bonus slot? */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 3, 0);
 	/* SEEK */
 	/* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
@@ -1394,7 +1375,7 @@
 	/* SEEK */
 	xf_emit(ctx, 9, 0);
 	/* SEEK */
-	if (dev_priv->chipset < 0x90)
+	if (device->chipset < 0x90)
 		xf_emit(ctx, 4, 0);
 	/* SEEK */
 	xf_emit(ctx, 2, 0);
@@ -1407,9 +1388,9 @@
 	xf_emit(ctx, 6*2, 0);
 	xf_emit(ctx, 2, 0);
 	/* SEEK */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 0x1c, 0);
-	else if (dev_priv->chipset < 0xa0)
+	else if (device->chipset < 0xa0)
 		xf_emit(ctx, 0x1e, 0);
 	else
 		xf_emit(ctx, 0x22, 0);
@@ -1421,9 +1402,9 @@
 nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
 {
 	/* Strand 0, right after dispatch */
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int smallm2mf = 0;
-	if (dev_priv->chipset < 0x92 || dev_priv->chipset == 0x98)
+	if (device->chipset < 0x92 || device->chipset == 0x98)
 		smallm2mf = 1;
 	/* SEEK */
 	xf_emit (ctx, 1, 0);		/* DMA_NOTIFY instance >> 4 */
@@ -1472,10 +1453,10 @@
 static void
 nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 2, 0);		/* RO */
 	xf_emit(ctx, 0x800, 0);		/* ffffffff */
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 	case 0x92:
 	case 0xa0:
@@ -1540,7 +1521,7 @@
 static void
 nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 	/* end of area 2 on pre-NVA0, area 1 on NVAx */
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
@@ -1550,14 +1531,14 @@
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_REG_ALLOC_RESULT */
 	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
 	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0x3ff);
 	else
 		xf_emit(ctx, 1, 0x7ff);	/* 000007ff */
 	xf_emit(ctx, 1, 0);		/* 111/113 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	for (i = 0; i < 8; i++) {
-		switch (dev_priv->chipset) {
+		switch (device->chipset) {
 		case 0x50:
 		case 0x86:
 		case 0x98:
@@ -1600,7 +1581,7 @@
 static void
 nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* end of area 2 on pre-NVA0, area 1 on NVAx */
 	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
 	xf_emit(ctx, 1, 0);		/* 00000003 VIEWPORT_CLIP_MODE */
@@ -1614,9 +1595,9 @@
 	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
 	xf_emit(ctx, 1, 0x1fe21);	/* 0001ffff tesla UNK0FAC */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0x0fac6881);
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 1);
 		xf_emit(ctx, 3, 0);
 	}
@@ -1625,9 +1606,9 @@
 static void
 nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 5, 0);		/* ffffffff */
 		xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
 		xf_emit(ctx, 1, 0);		/* 00000001 */
@@ -1643,14 +1624,14 @@
 	xf_emit(ctx, 1, 0);			/* 00000001 GP_ENABLE */
 	xf_emit(ctx, 1, 0x10);			/* 7f/ff VIEW_VOLUME_CLIP_CTRL */
 	xf_emit(ctx, 1, 0);			/* 000000ff VP_CLIP_DISTANCE_ENABLE */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);		/* 3ff */
 	xf_emit(ctx, 1, 0);			/* 000000ff tesla UNK1940 */
 	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK0D7C */
 	xf_emit(ctx, 1, 0x804);			/* 00000fff SEMANTIC_CLIP */
 	xf_emit(ctx, 1, 1);			/* 00000001 VIEWPORT_TRANSFORM_EN */
 	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0x7f);		/* 000000ff tesla UNK0FFC */
 	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A30 */
 	xf_emit(ctx, 1, 1);			/* 00000001 SHADE_MODEL */
@@ -1669,7 +1650,7 @@
 	xf_emit(ctx, 4, 0);			/* ffffffff NOPERSPECTIVE_BITMAP */
 	xf_emit(ctx, 1, 0);			/* 00000001 tesla UNK1900 */
 	xf_emit(ctx, 1, 0);			/* 0000000f */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0x3ff);		/* 000003ff tesla UNK0D68 */
 	else
 		xf_emit(ctx, 1, 0x7ff);		/* 000007ff tesla UNK0D68 */
@@ -1704,11 +1685,11 @@
 	xf_emit(ctx, 1, 0);			/* 00000001 LINE_STIPPLE_ENABLE */
 	xf_emit(ctx, 1, 0);			/* 00000001 LINE_SMOOTH_ENABLE */
 	xf_emit(ctx, 1, 0);			/* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0);		/* 00000001 */
 	xf_emit(ctx, 1, 0x1a);			/* 0000001f POLYGON_MODE */
 	xf_emit(ctx, 1, 0x10);			/* 000000ff VIEW_VOLUME_CLIP_CTRL */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 1, 0);		/* ffffffff */
 		xf_emit(ctx, 1, 0);		/* 00000001 */
 		xf_emit(ctx, 1, 0);		/* 000003ff */
@@ -1736,7 +1717,7 @@
 static void
 nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
 	/* SEEK */
 	xf_emit(ctx, 1, 0x3f);		/* 0000003f UNK1590 */
@@ -1774,7 +1755,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1108 */
 	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
@@ -1789,7 +1770,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 VIEWPORT_CLIP_RECTS_EN */
 	xf_emit(ctx, 1, 3);		/* 00000003 FP_CTRL_UNK196C */
 	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1968 */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);	/* 0fffffff tesla UNK1104 */
 	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK151C */
 }
@@ -1817,7 +1798,7 @@
 static void
 nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
 	/* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
 	/* SEEK */
@@ -1829,7 +1810,7 @@
 	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 4, 0);	/* RO */
 		xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
 		xf_emit(ctx, 1, 0);	/* 1ff */
@@ -1860,7 +1841,7 @@
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
 	/* SEEK */
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
@@ -1869,7 +1850,7 @@
 	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
 	xf_emit(ctx, 1, 1);		/* 00000001 */
 	/* SEEK */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 2, 4);	/* 000000ff */
 	xf_emit(ctx, 1, 0x80c14);	/* 01ffffff SEMANTIC_COLOR */
 	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
@@ -1893,20 +1874,20 @@
 	xf_emit(ctx, 0x10, 0);		/* 00ffffff POINT_COORD_REPLACE_MAP */
 	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
 	xf_emit(ctx, 1, 0x8100c12);	/* 1fffffff FP_INTERPOLANT_CTRL */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);	/* 000003ff */
 }
 
 static void
 nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int acnt = 0x10, rep, i;
 	/* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		acnt = 0x20;
 	/* SEEK */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK13A4 */
 		xf_emit(ctx, 1, 1);	/* 00000fff tesla UNK1318 */
 	}
@@ -1923,9 +1904,9 @@
 	xf_emit(ctx, 1, 0);		/* 0000ffff turing USER_PARAM_COUNT */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0xb, 0);	/* RO */
-	else if (dev_priv->chipset >= 0xa0)
+	else if (device->chipset >= 0xa0)
 		xf_emit(ctx, 0x9, 0);	/* RO */
 	else
 		xf_emit(ctx, 0x8, 0);	/* RO */
@@ -1944,11 +1925,11 @@
 	xf_emit(ctx, 1, 4);		/* 000001ff UNK1A28 */
 	xf_emit(ctx, 1, 8);		/* 000001ff UNK0DF0 */
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0x3ff);	/* 3ff tesla UNK0D68 */
 	else
 		xf_emit(ctx, 1, 0x7ff);	/* 7ff tesla UNK0D68 */
-	if (dev_priv->chipset == 0xa8)
+	if (device->chipset == 0xa8)
 		xf_emit(ctx, 1, 0x1e00);	/* 7fff */
 	/* SEEK */
 	xf_emit(ctx, 0xc, 0);		/* RO or close */
@@ -1956,13 +1937,13 @@
 	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
 	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
 	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
-	if (dev_priv->chipset > 0x50 && dev_priv->chipset < 0xa0)
+	if (device->chipset > 0x50 && device->chipset < 0xa0)
 		xf_emit(ctx, 2, 0);	/* ffffffff */
 	else
 		xf_emit(ctx, 1, 0);	/* ffffffff */
 	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0FD8 */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 0x10, 0);	/* 0? */
 		xf_emit(ctx, 2, 0);	/* weird... */
 		xf_emit(ctx, 2, 0);	/* RO */
@@ -1975,7 +1956,7 @@
 	xf_emit(ctx, 1, 0);		/* ffffffff VB_ELEMENT_BASE */
 	xf_emit(ctx, 1, 0);		/* ffffffff UNK1438 */
 	xf_emit(ctx, acnt, 0);		/* 1 tesla UNK1000 */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1118? */
 	/* SEEK */
 	xf_emit(ctx, acnt, 0);		/* ffffffff VERTEX_ARRAY_UNK90C */
@@ -2013,23 +1994,23 @@
 	xf_emit(ctx, acnt, 0);		/* 000000ff VERTEX_LIMIT_HIGH */
 	xf_emit(ctx, 3, 0);		/* f/1f */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, acnt, 0);		/* f */
 		xf_emit(ctx, 3, 0);		/* f/1f */
 	}
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 2, 0);	/* RO */
 	else
 		xf_emit(ctx, 5, 0);	/* RO */
 	/* SEEK */
 	xf_emit(ctx, 1, 0);		/* ffff DMA_VTXBUF */
 	/* SEEK */
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		xf_emit(ctx, 0x41, 0);	/* RO */
 		/* SEEK */
 		xf_emit(ctx, 0x11, 0);	/* RO */
-	} else if (!IS_NVA3F(dev_priv->chipset))
+	} else if (!IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x50, 0);	/* RO */
 	else
 		xf_emit(ctx, 0x58, 0);	/* RO */
@@ -2041,7 +2022,7 @@
 	xf_emit(ctx, acnt*4, 0);	/* ffffffff VTX_ATTR */
 	xf_emit(ctx, 4, 0);		/* f/1f, 0, 0, 0 */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x1d, 0);	/* RO */
 	else
 		xf_emit(ctx, 0x16, 0);	/* RO */
@@ -2049,21 +2030,21 @@
 	xf_emit(ctx, 1, 0xf);		/* ffffffff VP_ATTR_EN */
 	xf_emit(ctx, (acnt/8)-1, 0);	/* ffffffff VP_ATTR_EN */
 	/* SEEK */
-	if (dev_priv->chipset < 0xa0)
+	if (device->chipset < 0xa0)
 		xf_emit(ctx, 8, 0);	/* RO */
-	else if (IS_NVA3F(dev_priv->chipset))
+	else if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0xc, 0);	/* RO */
 	else
 		xf_emit(ctx, 7, 0);	/* RO */
 	/* SEEK */
 	xf_emit(ctx, 0xa, 0);		/* RO */
-	if (dev_priv->chipset == 0xa0)
+	if (device->chipset == 0xa0)
 		rep = 0xc;
 	else
 		rep = 4;
 	for (i = 0; i < rep; i++) {
 		/* SEEK */
-		if (IS_NVA3F(dev_priv->chipset))
+		if (IS_NVA3F(device->chipset))
 			xf_emit(ctx, 0x20, 0);	/* ffffffff */
 		xf_emit(ctx, 0x200, 0);	/* ffffffff */
 		xf_emit(ctx, 4, 0);	/* 7f/ff, 0, 0, 0 */
@@ -2077,7 +2058,7 @@
 	xf_emit(ctx, 1, 0);		/* 0000000f VP_GP_BUILTIN_ATTR_EN */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	/* SEEK */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 7, 0);	/* weird... */
 	else
 		xf_emit(ctx, 5, 0);	/* weird... */
@@ -2086,13 +2067,13 @@
 static void
 nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
 	/* SEEK */
 	xf_emit(ctx, 2, 0);		/* 0001ffff CLIP_X, CLIP_Y */
 	xf_emit(ctx, 2, 0);		/* 0000ffff CLIP_W, CLIP_H */
 	xf_emit(ctx, 1, 0);		/* 00000001 CLIP_ENABLE */
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		/* this is useless on everything but the original NV50,
 		 * guess they forgot to nuke it. Or just didn't bother. */
 		xf_emit(ctx, 2, 0);	/* 0000ffff IFC_CLIP_X, Y */
@@ -2148,7 +2129,7 @@
 static void
 nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
 	/* SEEK */
 	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
@@ -2173,7 +2154,7 @@
 	xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
 	/* SEEK */
 	xf_emit(ctx, 0x40, 0);		/* ffffffff USER_PARAM */
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 	case 0x92:
 		xf_emit(ctx, 8, 0);	/* 7, 0, 0, 0, ... */
@@ -2247,7 +2228,7 @@
 static void
 nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 2, 0);		/* 00007fff WINDOW_OFFSET_XY */
 	xf_emit(ctx, 1, 0x3f800000);	/* ffffffff LINE_WIDTH */
 	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
@@ -2277,9 +2258,9 @@
 	xf_emit(ctx, 1, 4);		/* 00000007 FP_CONTROL */
 	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 3);	/* 00000003 UNK16B4 */
-	else if (dev_priv->chipset >= 0xa0)
+	else if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 1);	/* 00000001 UNK16B4 */
 	xf_emit(ctx, 1, 0);		/* 00000003 MULTISAMPLE_CTRL */
 	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK0F90 */
@@ -2293,11 +2274,11 @@
 	xf_emit(ctx, 1, 0);		/* ffffffff POINT_SIZE */
 	xf_emit(ctx, 1, 0);		/* 00000001 */
 	xf_emit(ctx, 1, 0);		/* 00000007 tesla UNK0FB4 */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 1, 0);	/* 3ff */
 		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK1110 */
 	}
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1928 */
 	xf_emit(ctx, 0x10, 0);		/* ffffffff DEPTH_RANGE_NEAR */
 	xf_emit(ctx, 0x10, 0x3f800000);	/* ffffffff DEPTH_RANGE_FAR */
@@ -2316,11 +2297,11 @@
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000001 VERTEX_TWO_SIDE_ENABLE */
 	xf_emit(ctx, 4, 0xffff);	/* 0000ffff MSAA_MASK */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
-	if (dev_priv->chipset < 0xa0)
+	if (device->chipset < 0xa0)
 		xf_emit(ctx, 0x1c, 0);	/* RO */
-	else if (IS_NVA3F(dev_priv->chipset))
+	else if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x9, 0);
 	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
 	xf_emit(ctx, 1, 0);		/* 00000001 LINE_SMOOTH_ENABLE */
@@ -2328,13 +2309,13 @@
 	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
 	xf_emit(ctx, 1, 0x1a);		/* 0000001f POLYGON_MODE */
 	xf_emit(ctx, 1, 0);		/* 00000003 WINDOW_ORIGIN */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK1100 */
 		xf_emit(ctx, 1, 0);	/* 3ff */
 	}
 	/* XXX: the following block could belong either to unk1cxx, or
 	 * to STRMOUT. Rather hard to tell. */
-	if (dev_priv->chipset < 0xa0)
+	if (device->chipset < 0xa0)
 		xf_emit(ctx, 0x25, 0);
 	else
 		xf_emit(ctx, 0x3b, 0);
@@ -2343,18 +2324,18 @@
 static void
 nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 1, 0x102);		/* 0000ffff STRMOUT_BUFFER_CTRL */
 	xf_emit(ctx, 1, 0);		/* ffffffff STRMOUT_PRIMITIVE_COUNT */
 	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
 		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
 	}
 	xf_emit(ctx, 1, 4);		/* 000000ff GP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 4);		/* 0000007f VP_RESULT_MAP_SIZE */
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0x3ff);	/* 000003ff tesla UNK0D68 */
 	else
 		xf_emit(ctx, 1, 0x7ff);	/* 000007ff tesla UNK0D68 */
@@ -2365,7 +2346,7 @@
 	xf_emit(ctx, 4, 0);		/* 000000ff STRMOUT_ADDRESS_HIGH */
 	xf_emit(ctx, 4, 0);		/* ffffffff STRMOUT_ADDRESS_LOW */
 	xf_emit(ctx, 4, 4);		/* 000000ff STRMOUT_NUM_ATTRIBS */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 4, 0);	/* ffffffff UNK1A8C */
 		xf_emit(ctx, 4, 0);	/* ffffffff UNK1780 */
 	}
@@ -2385,12 +2366,12 @@
 static void
 nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0D64 */
 	xf_emit(ctx, 1, 0x4e3bfdf);	/* ffffffff UNK0DF4 */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
 	xf_emit(ctx, 1, 0);		/* 000003ff */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 }
@@ -2398,7 +2379,7 @@
 static void
 nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	/* SEEK */
 	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_QUERY */
 	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
@@ -2416,7 +2397,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 eng2d UNK260 */
 	xf_emit(ctx, 1, 0);		/* ff/3ff */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0x11);	/* 000000ff tesla UNK1968 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 }
@@ -2424,11 +2405,11 @@
 static void
 nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int magic2;
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		magic2 = 0x00003e60;
-	} else if (!IS_NVA3F(dev_priv->chipset)) {
+	} else if (!IS_NVA3F(device->chipset)) {
 		magic2 = 0x001ffe67;
 	} else {
 		magic2 = 0x00087e67;
@@ -2446,14 +2427,14 @@
 	xf_emit(ctx, 1, 0);		/* 00000007 DEPTH_TEST_FUNC */
 	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_WRITE_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, 0);		/* 00000007 STENCIL_FRONT_FUNC_FUNC */
 	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_FUNC_MASK */
 	xf_emit(ctx, 1, 0);		/* 000000ff STENCIL_FRONT_MASK */
 	xf_emit(ctx, 3, 0);		/* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
 	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_FRONT_ENABLE */
-	if (dev_priv->chipset >= 0xa0 && !IS_NVAAF(dev_priv->chipset))
+	if (device->chipset >= 0xa0 && !IS_NVAAF(device->chipset))
 		xf_emit(ctx, 1, 0x15);	/* 000000ff */
 	xf_emit(ctx, 1, 0);		/* 00000001 STENCIL_BACK_ENABLE */
 	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK15B4 */
@@ -2462,14 +2443,14 @@
 	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x92 || dev_priv->chipset == 0x98 || dev_priv->chipset >= 0xa0) {
+	if (device->chipset == 0x86 || device->chipset == 0x92 || device->chipset == 0x98 || device->chipset >= 0xa0) {
 		xf_emit(ctx, 3, 0);	/* ff, ffffffff, ffffffff */
 		xf_emit(ctx, 1, 4);	/* 7 */
 		xf_emit(ctx, 1, 0x400);	/* fffffff */
 		xf_emit(ctx, 1, 0x300);	/* ffff */
 		xf_emit(ctx, 1, 0x1001);	/* 1fff */
-		if (dev_priv->chipset != 0xa0) {
-			if (IS_NVA3F(dev_priv->chipset))
+		if (device->chipset != 0xa0) {
+			if (IS_NVA3F(device->chipset))
 				xf_emit(ctx, 1, 0);	/* 0000000f UNK15C8 */
 			else
 				xf_emit(ctx, 1, 0x15);	/* ff */
@@ -2547,7 +2528,7 @@
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff CLEAR_DEPTH */
 	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK19CC */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 2, 0);
 		xf_emit(ctx, 1, 0x1001);
 		xf_emit(ctx, 0xb, 0);
@@ -2564,7 +2545,7 @@
 	xf_emit(ctx, 7, 0);		/* 0000000f COLOR_MASK */
 	xf_emit(ctx, 1, 0x11);		/* 3f/7f */
 	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	if (dev_priv->chipset != 0x50) {
+	if (device->chipset != 0x50) {
 		xf_emit(ctx, 1, 0);	/* 0000000f LOGIC_OP */
 		xf_emit(ctx, 1, 0);	/* 000000ff */
 	}
@@ -2581,7 +2562,7 @@
 	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 	xf_emit(ctx, 1, 0x0fac6881);	/* 0fffffff RT_CONTROL */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 0);	/* 00000001 tesla UNK12E4 */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
@@ -2600,7 +2581,7 @@
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 		xf_emit(ctx, 1, 0);	/* 00000001 */
 		xf_emit(ctx, 1, 0);	/* 000003ff */
-	} else if (dev_priv->chipset >= 0xa0) {
+	} else if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 2, 0);	/* 00000001 */
 		xf_emit(ctx, 1, 0);	/* 00000007 */
 		xf_emit(ctx, 1, 0);	/* 00000003 */
@@ -2614,7 +2595,7 @@
 	xf_emit(ctx, 4, 0);		/* ffffffff CLEAR_COLOR */
 	xf_emit(ctx, 4, 0);		/* ffffffff BLEND_COLOR A R G B */
 	xf_emit(ctx, 1, 0);		/* 00000fff eng2d UNK2B0 */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 2, 0);	/* 00000001 */
 	xf_emit(ctx, 1, 0);		/* 000003ff */
 	xf_emit(ctx, 8, 0);		/* 00000001 BLEND_ENABLE */
@@ -2628,9 +2609,9 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 UNK19C0 */
 	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 0000000f LOGIC_OP */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4? NVA3+ only? */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 8, 1);	/* 00000001 IBLEND_UNK00 */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
 		xf_emit(ctx, 8, 2);	/* 0000001f IBLEND_FUNC_SRC_RGB */
@@ -2659,9 +2640,9 @@
 static void
 nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int magic3;
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0x50:
 		magic3 = 0x1000;
 		break;
@@ -2681,16 +2662,16 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	xf_emit(ctx, 1, 0);		/* 111/113[NVA0+] */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x1f, 0);	/* ffffffff */
-	else if (dev_priv->chipset >= 0xa0)
+	else if (device->chipset >= 0xa0)
 		xf_emit(ctx, 0x0f, 0);	/* ffffffff */
 	else
 		xf_emit(ctx, 0x10, 0);	/* fffffff VP_RESULT_MAP_1 up */
 	xf_emit(ctx, 2, 0);		/* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
 	xf_emit(ctx, 1, 4);		/* 7f/ff VP_REG_ALLOC_RESULT */
 	xf_emit(ctx, 1, 4);		/* 7f/ff VP_RESULT_MAP_SIZE */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0x03020100);	/* ffffffff */
 	else
 		xf_emit(ctx, 1, 0x00608080);	/* fffffff VP_RESULT_MAP_0 */
@@ -2733,11 +2714,11 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
 	xf_emit(ctx, 1, 0);		/* 111/113 */
-	if (dev_priv->chipset == 0x94 || dev_priv->chipset == 0x96)
+	if (device->chipset == 0x94 || device->chipset == 0x96)
 		xf_emit(ctx, 0x1020, 0);	/* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
-	else if (dev_priv->chipset < 0xa0)
+	else if (device->chipset < 0xa0)
 		xf_emit(ctx, 0xa20, 0);	/* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
-	else if (!IS_NVA3F(dev_priv->chipset))
+	else if (!IS_NVA3F(device->chipset))
 		xf_emit(ctx, 0x210, 0);	/* ffffffff */
 	else
 		xf_emit(ctx, 0x410, 0);	/* ffffffff */
@@ -2751,12 +2732,12 @@
 static void
 nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int magic1, magic2;
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		magic1 = 0x3ff;
 		magic2 = 0x00003e60;
-	} else if (!IS_NVA3F(dev_priv->chipset)) {
+	} else if (!IS_NVA3F(device->chipset)) {
 		magic1 = 0x7ff;
 		magic2 = 0x001ffe67;
 	} else {
@@ -2766,7 +2747,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
 	xf_emit(ctx, 1, 0);		/* ffffffff ALPHA_TEST_REF */
 	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000000f UNK16A0 */
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
 	xf_emit(ctx, 1, 0);		/* 00000001 tesla UNK1534 */
@@ -2800,11 +2781,11 @@
 	xf_emit(ctx, 1, 1);		/* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000007 ALPHA_TEST_FUNC */
 	xf_emit(ctx, 1, 0);		/* 00000001 ALPHA_TEST_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 3);	/* 00000003 tesla UNK16B4 */
 		xf_emit(ctx, 1, 0);	/* 00000003 */
 		xf_emit(ctx, 1, 0);	/* 00000003 tesla UNK1298 */
-	} else if (dev_priv->chipset >= 0xa0) {
+	} else if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 1, 1);	/* 00000001 tesla UNK16B4 */
 		xf_emit(ctx, 1, 0);	/* 00000003 */
 	} else {
@@ -2818,7 +2799,7 @@
 	xf_emit(ctx, 1, 1);		/* 0000001f BLEND_FUNC_DST_RGB */
 	xf_emit(ctx, 1, 1);		/* 00000007 BLEND_EQUATION_RGB */
 	xf_emit(ctx, 1, 2);		/* 0000001f BLEND_FUNC_SRC_RGB */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 0);	/* 00000001 UNK12E4 */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_RGB */
 		xf_emit(ctx, 8, 1);	/* 00000007 IBLEND_EQUATION_ALPHA */
@@ -2846,7 +2827,7 @@
 	xf_emit(ctx, 1, 0xcf);		/* 000000ff SIFC_FORMAT */
 	xf_emit(ctx, 1, 0xcf);		/* 000000ff DRAW_COLOR_FORMAT */
 	xf_emit(ctx, 1, 0xcf);		/* 000000ff SRC_FORMAT */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 	xf_emit(ctx, 1, 0);		/* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
@@ -2870,9 +2851,9 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_TEST_ENABLE */
 	xf_emit(ctx, 1, 0x11);		/* 3f/7f DST_FORMAT */
 	xf_emit(ctx, 1, 1);		/* 00000001 DST_LINEAR */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0);	/* ff */
 	else
 		xf_emit(ctx, 3, 0);	/* 1, 7, 3ff */
@@ -2907,7 +2888,7 @@
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 8, 0);		/* 0000ffff DMA_COLOR */
 	xf_emit(ctx, 1, 0);		/* 0000ffff DMA_GLOBAL */
@@ -2945,7 +2926,7 @@
 	xf_emit(ctx, 1, 0);		/* 0001ffff GP_BUILTIN_RESULT_EN */
 	xf_emit(ctx, 1, 0);		/* 00000003 UNK0F90 */
 	xf_emit(ctx, 1, 0);		/* 00000007 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
@@ -2974,7 +2955,7 @@
 	xf_emit(ctx, 1, 0x1001);	/* 00001fff ZETA_ARRAY_MODE */
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 0);	/* 00000001 */
 	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
 	xf_emit(ctx, 1, 0x11);		/* 3f/7f RT_FORMAT */
@@ -2988,14 +2969,14 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 FRAMEBUFFER_SRGB */
 	xf_emit(ctx, 1, 0);		/* 7 */
 	xf_emit(ctx, 1, 0);		/* 00000001 LOGIC_OP_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	}
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
 	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
 	xf_emit(ctx, 1, 0);		/* ffff0ff3 */
-	if (dev_priv->chipset >= 0xa0)
+	if (device->chipset >= 0xa0)
 		xf_emit(ctx, 1, 0x0fac6881);	/* fffffff */
 	xf_emit(ctx, 1, magic2);	/* 001fffff tesla UNK0F78 */
 	xf_emit(ctx, 1, 0);		/* 00000001 DEPTH_BOUNDS_EN */
@@ -3012,12 +2993,12 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 SAMPLECNT_ENABLE */
 	xf_emit(ctx, 1, 0);		/* 0000000f ZETA_FORMAT */
 	xf_emit(ctx, 1, 1);		/* 00000001 ZETA_ENABLE */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 		xf_emit(ctx, 1, 0);	/* 0000000f tesla UNK15C8 */
 	}
 	xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A3C */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 3, 0);		/* 7/f, 1, ffff0ff3 */
 		xf_emit(ctx, 1, 0xfac6881);	/* fffffff */
 		xf_emit(ctx, 4, 0);		/* 1, 1, 1, 3ff */
@@ -3027,7 +3008,7 @@
 		xf_emit(ctx, 2, 0);		/* 7, f */
 		xf_emit(ctx, 1, 1);		/* 1 */
 		xf_emit(ctx, 1, 0);		/* 7/f */
-		if (IS_NVA3F(dev_priv->chipset))
+		if (IS_NVA3F(device->chipset))
 			xf_emit(ctx, 0x9, 0);	/* 1 */
 		else
 			xf_emit(ctx, 0x8, 0);	/* 1 */
@@ -3041,7 +3022,7 @@
 		xf_emit(ctx, 1, 0x11);		/* 7f */
 		xf_emit(ctx, 1, 1);		/* 1 */
 		xf_emit(ctx, 5, 0);		/* 1, 7, 3ff, 3, 7 */
-		if (IS_NVA3F(dev_priv->chipset)) {
+		if (IS_NVA3F(device->chipset)) {
 			xf_emit(ctx, 1, 0);	/* 00000001 UNK1140 */
 			xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 		}
@@ -3051,15 +3032,15 @@
 static void
 nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 2, 0);		/* 1 LINKED_TSC. yes, 2. */
-	if (dev_priv->chipset != 0x50)
+	if (device->chipset != 0x50)
 		xf_emit(ctx, 1, 0);	/* 3 */
 	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DU_DX_INT */
 	xf_emit(ctx, 1, 0);		/* fffff BLIT_DU_DX_FRACT */
 	xf_emit(ctx, 1, 1);		/* 1ffff BLIT_DV_DY_INT */
 	xf_emit(ctx, 1, 0);		/* fffff BLIT_DV_DY_FRACT */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 1, 0);	/* 3 BLIT_CONTROL */
 	else
 		xf_emit(ctx, 2, 0);	/* 3ff, 1 */
@@ -3071,13 +3052,13 @@
 	xf_emit(ctx, 1, 0x10100);	/* ffffffff SRC_TIC_5 */
 	xf_emit(ctx, 1, 0x02800000);	/* ffffffff SRC_TIC_6 */
 	xf_emit(ctx, 1, 0);		/* ffffffff SRC_TIC_7 */
-	if (dev_priv->chipset == 0x50) {
+	if (device->chipset == 0x50) {
 		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK358 */
 		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
 		xf_emit(ctx, 1, 0);	/* 00000003 turing UNK37C tesla UNK1690 */
 		xf_emit(ctx, 1, 0);	/* 00000003 BLIT_CONTROL */
 		xf_emit(ctx, 1, 0);	/* 00000001 turing UNK32C tesla UNK0F94 */
-	} else if (!IS_NVAAF(dev_priv->chipset)) {
+	} else if (!IS_NVAAF(device->chipset)) {
 		xf_emit(ctx, 1, 0);	/* ffffffff tesla UNK1A34? */
 		xf_emit(ctx, 1, 0);	/* 00000003 */
 		xf_emit(ctx, 1, 0);	/* 000003ff */
@@ -3097,7 +3078,7 @@
 static void
 nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	xf_emit(ctx, 1, 0);		/* 00000001 UNK1534 */
 	xf_emit(ctx, 1, 0);		/* 7/f MULTISAMPLE_SAMPLES_LOG2 */
 	xf_emit(ctx, 2, 0);		/* 7, ffff0ff3 */
@@ -3109,7 +3090,7 @@
 	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
 	xf_emit(ctx, 1, 0x00ffff00);	/* 00ffffff LINE_STIPPLE_PATTERN */
 	xf_emit(ctx, 1, 1);		/* 00000001 tesla UNK0F98 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);	/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, 0);		/* 00000003 tesla UNK1668 */
 	xf_emit(ctx, 1, 0);		/* 00000001 LINE_STIPPLE_ENABLE */
@@ -3136,8 +3117,8 @@
 static void
 nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
-	if (dev_priv->chipset < 0xa0) {
+	struct nouveau_device *device = ctx->device;
+	if (device->chipset < 0xa0) {
 		nv50_graph_construct_xfer_unk84xx(ctx);
 		nv50_graph_construct_xfer_tprop(ctx);
 		nv50_graph_construct_xfer_tex(ctx);
@@ -3153,9 +3134,9 @@
 static void
 nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i, mpcnt = 2;
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 		case 0x98:
 		case 0xaa:
 			mpcnt = 1;
@@ -3182,34 +3163,34 @@
 		xf_emit(ctx, 1, 0x80);		/* ffffffff tesla UNK1404 */
 		xf_emit(ctx, 1, 0x80007004);	/* ffffffff tesla UNK12B0 */
 		xf_emit(ctx, 1, 0x04000400);	/* ffffffff */
-		if (dev_priv->chipset >= 0xa0)
+		if (device->chipset >= 0xa0)
 			xf_emit(ctx, 1, 0xc0);	/* 00007fff tesla UNK152C */
 		xf_emit(ctx, 1, 0x1000);	/* 0000ffff tesla UNK0D60 */
 		xf_emit(ctx, 1, 0);		/* ff/3ff */
 		xf_emit(ctx, 1, 0);		/* ffffffff tesla UNK1A30 */
-		if (dev_priv->chipset == 0x86 || dev_priv->chipset == 0x98 || dev_priv->chipset == 0xa8 || IS_NVAAF(dev_priv->chipset)) {
+		if (device->chipset == 0x86 || device->chipset == 0x98 || device->chipset == 0xa8 || IS_NVAAF(device->chipset)) {
 			xf_emit(ctx, 1, 0xe00);		/* 7fff */
 			xf_emit(ctx, 1, 0x1e00);	/* 7fff */
 		}
 		xf_emit(ctx, 1, 1);		/* 000000ff VP_REG_ALLOC_TEMP */
 		xf_emit(ctx, 1, 0);		/* 00000001 LINKED_TSC */
 		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
-		if (dev_priv->chipset == 0x50)
+		if (device->chipset == 0x50)
 			xf_emit(ctx, 2, 0x1000);	/* 7fff tesla UNK141C */
 		xf_emit(ctx, 1, 1);		/* 000000ff GP_REG_ALLOC_TEMP */
 		xf_emit(ctx, 1, 0);		/* 00000001 GP_ENABLE */
 		xf_emit(ctx, 1, 4);		/* 000000ff FP_REG_ALLOC_TEMP */
 		xf_emit(ctx, 1, 2);		/* 00000003 REG_MODE */
-		if (IS_NVAAF(dev_priv->chipset))
+		if (IS_NVAAF(device->chipset))
 			xf_emit(ctx, 0xb, 0);	/* RO */
-		else if (dev_priv->chipset >= 0xa0)
+		else if (device->chipset >= 0xa0)
 			xf_emit(ctx, 0xc, 0);	/* RO */
 		else
 			xf_emit(ctx, 0xa, 0);	/* RO */
 	}
 	xf_emit(ctx, 1, 0x08100c12);		/* 1fffffff FP_INTERPOLANT_CTRL */
 	xf_emit(ctx, 1, 0);			/* ff/3ff */
-	if (dev_priv->chipset >= 0xa0) {
+	if (device->chipset >= 0xa0) {
 		xf_emit(ctx, 1, 0x1fe21);	/* 0003ffff tesla UNK0FAC */
 	}
 	xf_emit(ctx, 3, 0);			/* 7fff, 0, 0 */
@@ -3223,7 +3204,7 @@
 	xf_emit(ctx, 1, 0);			/* ffffffff SHARED_SIZE */
 	xf_emit(ctx, 1, 0x1fe21);		/* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
 	xf_emit(ctx, 1, 0);			/* ffffffff tesla UNK1A34 */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 1);		/* 0000001f tesla UNK169C */
 	xf_emit(ctx, 1, 0);			/* ff/3ff */
 	xf_emit(ctx, 1, 0);			/* 1 LINKED_TSC */
@@ -3238,7 +3219,7 @@
 	xf_emit(ctx, 1, 0);			/* 00000007 */
 	xf_emit(ctx, 1, 0xfac6881);		/* 0fffffff RT_CONTROL */
 	xf_emit(ctx, 1, 0);			/* 00000003 MULTISAMPLE_CTRL */
-	if (IS_NVA3F(dev_priv->chipset))
+	if (IS_NVA3F(device->chipset))
 		xf_emit(ctx, 1, 3);		/* 00000003 tesla UNK16B4 */
 	xf_emit(ctx, 1, 0);			/* 00000001 ALPHA_TEST_ENABLE */
 	xf_emit(ctx, 1, 0);			/* 00000007 ALPHA_TEST_FUNC */
@@ -3253,7 +3234,7 @@
 	xf_emit(ctx, 1, 1);			/* 0000001f BLEND_FUNC_DST_ALPHA */
 	xf_emit(ctx, 1, 1);			/* 00000007 BLEND_EQUATION_ALPHA */
 	xf_emit(ctx, 1, 1);			/* 00000001 UNK133C */
-	if (IS_NVA3F(dev_priv->chipset)) {
+	if (IS_NVA3F(device->chipset)) {
 		xf_emit(ctx, 1, 0);		/* 00000001 UNK12E4 */
 		xf_emit(ctx, 8, 2);		/* 0000001f IBLEND_FUNC_SRC_RGB */
 		xf_emit(ctx, 8, 1);		/* 0000001f IBLEND_FUNC_DST_RGB */
@@ -3268,11 +3249,11 @@
 	xf_emit(ctx, 1, 0);			/* 00000003 tesla UNK0F90 */
 	xf_emit(ctx, 1, 4);			/* 000000ff FP_RESULT_COUNT */
 	/* XXX: demagic this part some day */
-	if (dev_priv->chipset == 0x50)
+	if (device->chipset == 0x50)
 		xf_emit(ctx, 0x3a0, 0);
-	else if (dev_priv->chipset < 0x94)
+	else if (device->chipset < 0x94)
 		xf_emit(ctx, 0x3a2, 0);
-	else if (dev_priv->chipset == 0x98 || dev_priv->chipset == 0xaa)
+	else if (device->chipset == 0x98 || device->chipset == 0xaa)
 		xf_emit(ctx, 0x39f, 0);
 	else
 		xf_emit(ctx, 0x3a3, 0);
@@ -3285,15 +3266,15 @@
 static void
 nv50_graph_construct_xfer2(struct nouveau_grctx *ctx)
 {
-	struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
+	struct nouveau_device *device = ctx->device;
 	int i;
-	uint32_t offset;
-	uint32_t units = nv_rd32 (ctx->dev, 0x1540);
+	u32 offset;
+	u32 units = nv_rd32 (ctx->device, 0x1540);
 	int size = 0;
 
 	offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
 
-	if (dev_priv->chipset < 0xa0) {
+	if (device->chipset < 0xa0) {
 		for (i = 0; i < 8; i++) {
 			ctx->ctxvals_pos = offset + i;
 			/* that little bugger belongs to csched. No idea
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
index b19a406..c12e766 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
@@ -22,13 +22,10 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include <core/mm.h>
 #include "nvc0.h"
 
 void
-nv_icmd(struct drm_device *priv, u32 icmd, u32 data)
+nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data)
 {
 	nv_wr32(priv, 0x400204, data);
 	nv_wr32(priv, 0x400200, icmd);
@@ -36,21 +33,22 @@
 }
 
 int
-nvc0_grctx_init(struct drm_device *priv, struct nvc0_graph_priv *oprv,
-		struct nvc0_grctx *info)
+nvc0_grctx_init(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
+	struct nouveau_bar *bar = nouveau_bar(priv);
+	struct nouveau_object *parent = nv_object(priv);
 	struct nouveau_gpuobj *chan;
-	u32 size = (0x80000 + oprv->size + 4095) & ~4095;
+	u32 size = (0x80000 + priv->size + 4095) & ~4095;
 	int ret, i;
 
 	/* allocate memory to for a "channel", which we'll use to generate
 	 * the default context values
 	 */
-	ret = nouveau_gpuobj_new(priv, NULL, size, 0x1000,
+	ret = nouveau_gpuobj_new(parent, NULL, size, 0x1000,
 				 NVOBJ_FLAG_ZERO_ALLOC, &info->chan);
 	chan = info->chan;
 	if (ret) {
-		NV_ERROR(priv, "failed to allocate channel memory, %d\n", ret);
+		nv_error(priv, "failed to allocate channel memory, %d\n", ret);
 		return ret;
 	}
 
@@ -75,32 +73,31 @@
 	nv_wo32(chan, 0x0210, 0x00080004);
 	nv_wo32(chan, 0x0214, 0x00000000);
 
-	nvimem_flush(priv);
+	bar->flush(bar);
 
 	nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
 	nv_wr32(priv, 0x100cbc, 0x80000001);
 	nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
 
 	/* setup default state for mmio list construction */
-	info->dev  = priv;
-	info->data = oprv->mmio_data;
-	info->mmio = oprv->mmio_list;
+	info->data = priv->mmio_data;
+	info->mmio = priv->mmio_list;
 	info->addr = 0x2000 + (i * 8);
-	info->priv = oprv;
+	info->priv = priv;
 	info->buffer_nr = 0;
 
-	if (oprv->firmware) {
+	if (priv->firmware) {
 		nv_wr32(priv, 0x409840, 0x00000030);
 		nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
 		nv_wr32(priv, 0x409504, 0x00000003);
 		if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
-			NV_ERROR(priv, "load_ctx timeout\n");
+			nv_error(priv, "load_ctx timeout\n");
 
 		nv_wo32(chan, 0x8001c, 1);
 		nv_wo32(chan, 0x80020, 0);
 		nv_wo32(chan, 0x80028, 0);
 		nv_wo32(chan, 0x8002c, 0);
-		nvimem_flush(priv);
+		bar->flush(bar);
 		return 0;
 	}
 
@@ -109,7 +106,7 @@
 	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");
+		nv_error(priv, "HUB_SET_CHAN timeout\n");
 		nvc0_graph_ctxctl_debug(priv);
 		nouveau_gpuobj_ref(NULL, &info->chan);
 		return -EBUSY;
@@ -135,6 +132,8 @@
 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;
@@ -143,7 +142,7 @@
 
 	if (shift)
 		data |= info->buffer[buf] >> shift;
-	nv_wr32(info->dev, addr, data);
+	nv_wr32(priv, addr, data);
 }
 
 int
@@ -153,11 +152,11 @@
 	int i;
 
 	if (priv->firmware) {
-		nv_wr32(info->dev, 0x409840, 0x00000003);
-		nv_wr32(info->dev, 0x409500, 0x80000000 | info->chan->addr >> 12);
-		nv_wr32(info->dev, 0x409504, 0x00000009);
-		if (!nv_wait(info->dev, 0x409800, 0x00000001, 0x00000000)) {
-			NV_ERROR(info->dev, "unload_ctx timeout\n");
+		nv_wr32(priv, 0x409840, 0x00000003);
+		nv_wr32(priv, 0x409500, 0x80000000 | info->chan->addr >> 12);
+		nv_wr32(priv, 0x409504, 0x00000009);
+		if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000000)) {
+			nv_error(priv, "unload_ctx timeout\n");
 			return -EBUSY;
 		}
 
@@ -165,12 +164,12 @@
 	}
 
 	/* HUB_FUC(CTX_SAVE) */
-	nv_wr32(info->dev, 0x409840, 0x80000000);
-	nv_wr32(info->dev, 0x409500, 0x80000000 | info->chan->addr >> 12);
-	nv_wr32(info->dev, 0x409504, 0x00000002);
-	if (!nv_wait(info->dev, 0x409800, 0x80000000, 0x80000000)) {
-		NV_ERROR(info->dev, "HUB_CTX_SAVE timeout\n");
-		nvc0_graph_ctxctl_debug(info->dev);
+	nv_wr32(priv, 0x409840, 0x80000000);
+	nv_wr32(priv, 0x409500, 0x80000000 | info->chan->addr >> 12);
+	nv_wr32(priv, 0x409504, 0x00000002);
+	if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
+		nv_error(priv, "HUB_CTX_SAVE timeout\n");
+		nvc0_graph_ctxctl_debug(priv);
 		return -EBUSY;
 	}
 
@@ -186,7 +185,7 @@
 }
 
 static void
-nvc0_grctx_generate_9097(struct drm_device *priv)
+nvc0_grctx_generate_9097(struct nvc0_graph_priv *priv)
 {
 	u32 fermi = nvc0_graph_class(priv);
 	u32 mthd;
@@ -1343,7 +1342,7 @@
 }
 
 static void
-nvc0_grctx_generate_9197(struct drm_device *priv)
+nvc0_grctx_generate_9197(struct nvc0_graph_priv *priv)
 {
 	u32 fermi = nvc0_graph_class(priv);
 	u32 mthd;
@@ -1356,7 +1355,7 @@
 }
 
 static void
-nvc0_grctx_generate_9297(struct drm_device *priv)
+nvc0_grctx_generate_9297(struct nvc0_graph_priv *priv)
 {
 	u32 fermi = nvc0_graph_class(priv);
 	u32 mthd;
@@ -1374,7 +1373,7 @@
 }
 
 static void
-nvc0_grctx_generate_902d(struct drm_device *priv)
+nvc0_grctx_generate_902d(struct nvc0_graph_priv *priv)
 {
 	nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
 	nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
@@ -1396,7 +1395,7 @@
 }
 
 static void
-nvc0_grctx_generate_9039(struct drm_device *priv)
+nvc0_grctx_generate_9039(struct nvc0_graph_priv *priv)
 {
 	nv_mthd(priv, 0x9039, 0x030c, 0x00000000);
 	nv_mthd(priv, 0x9039, 0x0310, 0x00000000);
@@ -1409,12 +1408,11 @@
 }
 
 static void
-nvc0_grctx_generate_90c0(struct drm_device *priv)
+nvc0_grctx_generate_90c0(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
 	int i;
 
-	for (i = 0; dev_priv->chipset == 0xd9 && i < 4; i++) {
+	for (i = 0; nv_device(priv)->chipset == 0xd9 && 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);
@@ -1430,7 +1428,7 @@
 	nv_mthd(priv, 0x90c0, 0x27ac, 0x00000000);
 	nv_mthd(priv, 0x90c0, 0x27cc, 0x00000000);
 	nv_mthd(priv, 0x90c0, 0x27ec, 0x00000000);
-	for (i = 0; dev_priv->chipset == 0xd9 && i < 4; i++) {
+	for (i = 0; nv_device(priv)->chipset == 0xd9 && 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);
@@ -1458,7 +1456,7 @@
 }
 
 static void
-nvc0_grctx_generate_dispatch(struct drm_device *priv)
+nvc0_grctx_generate_dispatch(struct nvc0_graph_priv *priv)
 {
 	int i;
 
@@ -1511,7 +1509,7 @@
 }
 
 static void
-nvc0_grctx_generate_macro(struct drm_device *priv)
+nvc0_grctx_generate_macro(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404404, 0x00000000);
 	nv_wr32(priv, 0x404408, 0x00000000);
@@ -1536,7 +1534,7 @@
 }
 
 static void
-nvc0_grctx_generate_m2mf(struct drm_device *priv)
+nvc0_grctx_generate_m2mf(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404604, 0x00000015);
 	nv_wr32(priv, 0x404608, 0x00000000);
@@ -1600,7 +1598,7 @@
 }
 
 static void
-nvc0_grctx_generate_unk47xx(struct drm_device *priv)
+nvc0_grctx_generate_unk47xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404700, 0x00000000);
 	nv_wr32(priv, 0x404704, 0x00000000);
@@ -1627,16 +1625,15 @@
 }
 
 static void
-nvc0_grctx_generate_shaders(struct drm_device *priv)
+nvc0_grctx_generate_shaders(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
 
-	if (dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xd9) {
 		nv_wr32(priv, 0x405800, 0x0f8000bf);
 		nv_wr32(priv, 0x405830, 0x02180218);
 		nv_wr32(priv, 0x405834, 0x08000000);
 	} else
-	if (dev_priv->chipset == 0xc1) {
+	if (nv_device(priv)->chipset == 0xc1) {
 		nv_wr32(priv, 0x405800, 0x0f8000bf);
 		nv_wr32(priv, 0x405830, 0x02180218);
 		nv_wr32(priv, 0x405834, 0x00000000);
@@ -1657,7 +1654,7 @@
 }
 
 static void
-nvc0_grctx_generate_unk60xx(struct drm_device *priv)
+nvc0_grctx_generate_unk60xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x406020, 0x000103c1);
 	nv_wr32(priv, 0x406028, 0x00000001);
@@ -1667,25 +1664,24 @@
 }
 
 static void
-nvc0_grctx_generate_unk64xx(struct drm_device *priv)
+nvc0_grctx_generate_unk64xx(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
 
 	nv_wr32(priv, 0x4064a8, 0x00000000);
 	nv_wr32(priv, 0x4064ac, 0x00003fff);
 	nv_wr32(priv, 0x4064b4, 0x00000000);
 	nv_wr32(priv, 0x4064b8, 0x00000000);
-	if (dev_priv->chipset == 0xd9)
+	if (nv_device(priv)->chipset == 0xd9)
 		nv_wr32(priv, 0x4064bc, 0x00000000);
-	if (dev_priv->chipset == 0xc1 ||
-	    dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xc1 ||
+	    nv_device(priv)->chipset == 0xd9) {
 		nv_wr32(priv, 0x4064c0, 0x80140078);
 		nv_wr32(priv, 0x4064c4, 0x0086ffff);
 	}
 }
 
 static void
-nvc0_grctx_generate_tpbus(struct drm_device *priv)
+nvc0_grctx_generate_tpbus(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x407804, 0x00000023);
 	nv_wr32(priv, 0x40780c, 0x0a418820);
@@ -1698,7 +1694,7 @@
 }
 
 static void
-nvc0_grctx_generate_ccache(struct drm_device *priv)
+nvc0_grctx_generate_ccache(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x408000, 0x00000000);
 	nv_wr32(priv, 0x408004, 0x00000000);
@@ -1711,10 +1707,9 @@
 }
 
 static void
-nvc0_grctx_generate_rop(struct drm_device *priv)
+nvc0_grctx_generate_rop(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
-	int chipset = dev_priv->chipset;
+	int chipset = nv_device(priv)->chipset;
 
 	/* ROPC_BROADCAST */
 	nv_wr32(priv, 0x408800, 0x02802a3c);
@@ -1741,10 +1736,9 @@
 }
 
 static void
-nvc0_grctx_generate_gpc(struct drm_device *priv)
+nvc0_grctx_generate_gpc(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
-	int chipset = dev_priv->chipset;
+	int chipset = nv_device(priv)->chipset;
 	int i;
 
 	/* GPC_BROADCAST */
@@ -1834,10 +1828,9 @@
 }
 
 static void
-nvc0_grctx_generate_tp(struct drm_device *priv)
+nvc0_grctx_generate_tp(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
-	int chipset = dev_priv->chipset;
+	int chipset = nv_device(priv)->chipset;
 
 	/* GPC_BROADCAST.TP_BROADCAST */
 	nv_wr32(priv, 0x419818, 0x00000000);
@@ -1876,7 +1869,7 @@
 	nv_wr32(priv, 0x419c04, 0x00000006);
 	nv_wr32(priv, 0x419c08, 0x00000002);
 	nv_wr32(priv, 0x419c20, 0x00000000);
-	if (dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xd9) {
 		nv_wr32(priv, 0x419c24, 0x00084210);
 		nv_wr32(priv, 0x419c28, 0x3cf3cf3c);
 		nv_wr32(priv, 0x419cb0, 0x00020048);
@@ -1929,16 +1922,14 @@
 }
 
 int
-nvc0_grctx_generate(struct drm_device *priv)
+nvc0_grctx_generate(struct nvc0_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
-	struct nvc0_graph_priv *oprv = nv_engine(priv, NVOBJ_ENGINE_GR);
 	struct nvc0_grctx info;
 	int ret, i, gpc, tpc, id;
 	u32 fermi = nvc0_graph_class(priv);
 	u32 r000260, tmp;
 
-	ret = nvc0_grctx_init(priv, oprv, &info);
+	ret = nvc0_grctx_init(priv, &info);
 	if (ret)
 		return ret;
 
@@ -1975,11 +1966,11 @@
 	mmio_list(0x419008, 0x00000000,  0, 0);
 	mmio_list(0x418808, 0x00000000,  8, 0);
 	mmio_list(0x41880c, 0x80000018,  0, 0);
-	if (dev_priv->chipset != 0xc1) {
+	if (nv_device(priv)->chipset != 0xc1) {
 		tmp = 0x02180000;
 		mmio_list(0x405830, tmp, 0, 0);
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
-			for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) {
+		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;
@@ -1989,13 +1980,13 @@
 		tmp = 0x02180000;
 		mmio_list(0x405830, 0x00000218 | tmp, 0, 0);
 		mmio_list(0x4064c4, 0x0086ffff, 0, 0);
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
-			for (tpc = 0; tpc < oprv->tpc_nr[gpc]; tpc++) {
+		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 < oprv->tpc_nr[gpc]; tpc++) {
+			for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
 				u32 reg = TPC_UNIT(gpc, tpc, 0x0544);
 				mmio_list(reg, tmp, 0, 0);
 				tmp += 0x0324;
@@ -2004,8 +1995,8 @@
 	}
 
 	for (tpc = 0, id = 0; tpc < 4; tpc++) {
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
-			if (tpc < oprv->tpc_nr[gpc]) {
+		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);
@@ -2013,14 +2004,14 @@
 				id++;
 			}
 
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), oprv->tpc_nr[gpc]);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), oprv->tpc_nr[gpc]);
+			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 < oprv->gpc_nr; i++)
-		tmp |= oprv->tpc_nr[i] << (i * 4);
+	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);
 
@@ -2034,13 +2025,13 @@
 	if (1) {
 		u8 tpcnr[GPC_MAX], data[TPC_MAX];
 
-		memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
+		memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
 		memset(data, 0x1f, sizeof(data));
 
 		gpc = -1;
-		for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
+		for (tpc = 0; tpc < priv->tpc_total; tpc++) {
 			do {
-				gpc = (gpc + 1) % oprv->gpc_nr;
+				gpc = (gpc + 1) % priv->gpc_nr;
 			} while (!tpcnr[gpc]);
 			tpcnr[gpc]--;
 			data[tpc] = gpc;
@@ -2056,12 +2047,12 @@
 		u8 shift, ntpcv;
 
 		/* calculate first set of magics */
-		memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
+		memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
 
 		gpc = -1;
-		for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
+		for (tpc = 0; tpc < priv->tpc_total; tpc++) {
 			do {
-				gpc = (gpc + 1) % oprv->gpc_nr;
+				gpc = (gpc + 1) % priv->gpc_nr;
 			} while (!tpcnr[gpc]);
 			tpcnr[gpc]--;
 
@@ -2073,7 +2064,7 @@
 
 		/* and the second... */
 		shift = 0;
-		ntpcv = oprv->tpc_total;
+		ntpcv = priv->tpc_total;
 		while (!(ntpcv & (1 << 4))) {
 			ntpcv <<= 1;
 			shift++;
@@ -2086,22 +2077,22 @@
 			data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
 
 		/* GPC_BROADCAST */
-		nv_wr32(priv, 0x418bb8, (oprv->tpc_total << 8) |
-					oprv->magic_not_rop_nr);
+		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, (oprv->tpc_total << 8) |
-				       oprv->magic_not_rop_nr |
+		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, (oprv->tpc_total << 8) |
-					oprv->magic_not_rop_nr);
+		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]);
 	}
@@ -2110,18 +2101,18 @@
 		u32 tpc_mask = 0, tpc_set = 0;
 		u8  tpcnr[GPC_MAX], a, b;
 
-		memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++)
-			tpc_mask |= ((1 << oprv->tpc_nr[gpc]) - 1) << (gpc * 8);
+		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 * (oprv->tpc_total - 1)) / 32;
+			a = (i * (priv->tpc_total - 1)) / 32;
 			if (a != b) {
 				b = a;
 				do {
-					gpc = (gpc + 1) % oprv->gpc_nr;
+					gpc = (gpc + 1) % priv->gpc_nr;
 				} while (!tpcnr[gpc]);
-				tpc = oprv->tpc_nr[gpc] - tpcnr[gpc]--;
+				tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
 
 				tpc_set |= 1 << ((gpc * 8) + tpc);
 			}
@@ -2232,7 +2223,7 @@
 	nv_icmd(priv, 0x00000215, 0x00000040);
 	nv_icmd(priv, 0x00000216, 0x00000040);
 	nv_icmd(priv, 0x00000217, 0x00000040);
-	if (dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xd9) {
 		for (i = 0x0400; i <= 0x0417; i++)
 			nv_icmd(priv, i, 0x00000040);
 	}
@@ -2244,7 +2235,7 @@
 	nv_icmd(priv, 0x0000021d, 0x0000c080);
 	nv_icmd(priv, 0x0000021e, 0x0000c080);
 	nv_icmd(priv, 0x0000021f, 0x0000c080);
-	if (dev_priv->chipset == 0xd9) {
+	if (nv_device(priv)->chipset == 0xd9) {
 		for (i = 0x0440; i <= 0x0457; i++)
 			nv_icmd(priv, i, 0x0000c080);
 	}
@@ -2810,8 +2801,8 @@
 	nv_icmd(priv, 0x0000053f, 0xffff0000);
 	nv_icmd(priv, 0x00000585, 0x0000003f);
 	nv_icmd(priv, 0x00000576, 0x00000003);
-	if (dev_priv->chipset == 0xc1 ||
-	    dev_priv->chipset == 0xd9)
+	if (nv_device(priv)->chipset == 0xc1 ||
+	    nv_device(priv)->chipset == 0xd9)
 		nv_icmd(priv, 0x0000057b, 0x00000059);
 	nv_icmd(priv, 0x00000586, 0x00000040);
 	nv_icmd(priv, 0x00000582, 0x00000080);
@@ -2913,7 +2904,7 @@
 	nv_icmd(priv, 0x00000957, 0x00000003);
 	nv_icmd(priv, 0x0000095e, 0x20164010);
 	nv_icmd(priv, 0x0000095f, 0x00000020);
-	if (dev_priv->chipset == 0xd9)
+	if (nv_device(priv)->chipset == 0xd9)
 		nv_icmd(priv, 0x0000097d, 0x00000020);
 	nv_icmd(priv, 0x00000683, 0x00000006);
 	nv_icmd(priv, 0x00000685, 0x003fffff);
@@ -3056,5 +3047,6 @@
 	nvc0_grctx_generate_90c0(priv);
 
 	nv_wr32(priv, 0x000260, r000260);
+
 	return nvc0_grctx_fini(&info);
 }
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
index e550317..6d8c639 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
@@ -22,13 +22,10 @@
  * Authors: Ben Skeggs
  */
 
-#include "drmP.h"
-#include "nouveau_drv.h"
-#include <core/mm.h>
 #include "nvc0.h"
 
 static void
-nve0_grctx_generate_icmd(struct drm_device *priv)
+nve0_grctx_generate_icmd(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x400208, 0x80000000);
 	nv_icmd(priv, 0x001000, 0x00000004);
@@ -916,7 +913,7 @@
 }
 
 static void
-nve0_grctx_generate_a097(struct drm_device *priv)
+nve0_grctx_generate_a097(struct nvc0_graph_priv *priv)
 {
 	nv_mthd(priv, 0xa097, 0x0800, 0x00000000);
 	nv_mthd(priv, 0xa097, 0x0840, 0x00000000);
@@ -2146,7 +2143,7 @@
 }
 
 static void
-nve0_grctx_generate_902d(struct drm_device *priv)
+nve0_grctx_generate_902d(struct nvc0_graph_priv *priv)
 {
 	nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
 	nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
@@ -2169,7 +2166,7 @@
 }
 
 static void
-nve0_graph_generate_unk40xx(struct drm_device *priv)
+nve0_graph_generate_unk40xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404010, 0x0);
 	nv_wr32(priv, 0x404014, 0x0);
@@ -2213,7 +2210,7 @@
 }
 
 static void
-nve0_graph_generate_unk44xx(struct drm_device *priv)
+nve0_graph_generate_unk44xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404404, 0x0);
 	nv_wr32(priv, 0x404408, 0x0);
@@ -2238,7 +2235,7 @@
 }
 
 static void
-nve0_graph_generate_unk46xx(struct drm_device *priv)
+nve0_graph_generate_unk46xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404604, 0x14);
 	nv_wr32(priv, 0x404608, 0x0);
@@ -2278,7 +2275,7 @@
 }
 
 static void
-nve0_graph_generate_unk47xx(struct drm_device *priv)
+nve0_graph_generate_unk47xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x404700, 0x0);
 	nv_wr32(priv, 0x404704, 0x0);
@@ -2299,7 +2296,7 @@
 }
 
 static void
-nve0_graph_generate_unk58xx(struct drm_device *priv)
+nve0_graph_generate_unk58xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x405800, 0xf8000bf);
 	nv_wr32(priv, 0x405830, 0x2180648);
@@ -2318,7 +2315,7 @@
 }
 
 static void
-nve0_graph_generate_unk60xx(struct drm_device *priv)
+nve0_graph_generate_unk60xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x406020, 0x4103c1);
 	nv_wr32(priv, 0x406028, 0x1);
@@ -2328,7 +2325,7 @@
 }
 
 static void
-nve0_graph_generate_unk64xx(struct drm_device *priv)
+nve0_graph_generate_unk64xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x4064a8, 0x0);
 	nv_wr32(priv, 0x4064ac, 0x3fff);
@@ -2350,13 +2347,13 @@
 }
 
 static void
-nve0_graph_generate_unk70xx(struct drm_device *priv)
+nve0_graph_generate_unk70xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x407040, 0x0);
 }
 
 static void
-nve0_graph_generate_unk78xx(struct drm_device *priv)
+nve0_graph_generate_unk78xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x407804, 0x23);
 	nv_wr32(priv, 0x40780c, 0xa418820);
@@ -2369,7 +2366,7 @@
 }
 
 static void
-nve0_graph_generate_unk80xx(struct drm_device *priv)
+nve0_graph_generate_unk80xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x408000, 0x0);
 	nv_wr32(priv, 0x408004, 0x0);
@@ -2382,7 +2379,7 @@
 }
 
 static void
-nve0_graph_generate_unk88xx(struct drm_device *priv)
+nve0_graph_generate_unk88xx(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x408800, 0x2802a3c);
 	nv_wr32(priv, 0x408804, 0x40);
@@ -2395,7 +2392,7 @@
 }
 
 static void
-nve0_graph_generate_gpc(struct drm_device *priv)
+nve0_graph_generate_gpc(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x418380, 0x16);
 	nv_wr32(priv, 0x418400, 0x38004e00);
@@ -2521,7 +2518,7 @@
 }
 
 static void
-nve0_graph_generate_tpc(struct drm_device *priv)
+nve0_graph_generate_tpc(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x419848, 0x0);
 	nv_wr32(priv, 0x419864, 0x129);
@@ -2586,7 +2583,7 @@
 }
 
 static void
-nve0_graph_generate_tpcunk(struct drm_device *priv)
+nve0_graph_generate_tpcunk(struct nvc0_graph_priv *priv)
 {
 	nv_wr32(priv, 0x41be24, 0x6);
 	nv_wr32(priv, 0x41bec0, 0x12180000);
@@ -2604,9 +2601,8 @@
 }
 
 int
-nve0_grctx_generate(struct drm_device *priv)
+nve0_grctx_generate(struct nvc0_graph_priv *priv)
 {
-	struct nvc0_graph_priv *oprv = nv_engine(priv, NVOBJ_ENGINE_GR);
 	struct nvc0_grctx info;
 	int ret, i, gpc, tpc, id;
 	u32 data[6] = {}, data2[2] = {}, tmp;
@@ -2615,7 +2611,7 @@
 	u8 tpcnr[GPC_MAX], a, b;
 	u8 shift, ntpcv;
 
-	ret = nvc0_grctx_init(priv, oprv, &info);
+	ret = nvc0_grctx_init(priv, &info);
 	if (ret)
 		return ret;
 
@@ -2657,17 +2653,17 @@
 	mmio_list(0x419848, 0x10000000, 12, 2);
 	mmio_list(0x405830, 0x02180648,  0, 0);
 	mmio_list(0x4064c4, 0x0192ffff,  0, 0);
-	for (gpc = 0, offset = 0; gpc < oprv->gpc_nr; gpc++) {
-		u16 magic0 = 0x0218 * oprv->tpc_nr[gpc];
-		u16 magic1 = 0x0648 * oprv->tpc_nr[gpc];
+	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 * oprv->tpc_nr[gpc];
+		offset += 0x0324 * priv->tpc_nr[gpc];
 	}
-	for (gpc = 0; gpc < oprv->gpc_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 * oprv->tpc_nr[gpc];
+		offset += 0x07ff * priv->tpc_nr[gpc];
 	}
 	mmio_list(0x17e91c, 0x06060609, 0, 0);
 	mmio_list(0x17e920, 0x00090a05, 0, 0);
@@ -2680,22 +2676,22 @@
 	nv_wr32(priv, 0x419c00, 0xa);
 
 	for (tpc = 0, id = 0; tpc < 4; tpc++) {
-		for (gpc = 0; gpc < oprv->gpc_nr; gpc++) {
-			if (tpc < oprv->tpc_nr[gpc]) {
+		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), oprv->tpc_nr[gpc]);
-			nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), oprv->tpc_nr[gpc]);
+			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 < oprv->gpc_nr; i++)
-		tmp |= oprv->tpc_nr[i] << (i * 4);
+	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);
 
@@ -2707,12 +2703,12 @@
 	nv_wr32(priv, 0x40587c, 0x0);
 
 	/* calculate first set of magics */
-	memcpy(tpcnr, oprv->tpc_nr, sizeof(oprv->tpc_nr));
+	memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
 
 	gpc = -1;
-	for (tpc = 0; tpc < oprv->tpc_total; tpc++) {
+	for (tpc = 0; tpc < priv->tpc_total; tpc++) {
 		do {
-			gpc = (gpc + 1) % oprv->gpc_nr;
+			gpc = (gpc + 1) % priv->gpc_nr;
 		} while (!tpcnr[gpc]);
 		tpcnr[gpc]--;
 
@@ -2724,7 +2720,7 @@
 
 	/* and the second... */
 	shift = 0;
-	ntpcv = oprv->tpc_total;
+	ntpcv = priv->tpc_total;
 	while (!(ntpcv & (1 << 4))) {
 		ntpcv <<= 1;
 		shift++;
@@ -2733,13 +2729,13 @@
 	data2[0]  = ntpcv << 16;
 	data2[0] |= shift << 21;
 	data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
-	data2[0] |= oprv->tpc_total << 8;
-	data2[0] |= oprv->magic_not_rop_nr;
+	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, (oprv->tpc_total << 8) | oprv->magic_not_rop_nr);
+	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]);
 
@@ -2748,23 +2744,23 @@
 	for (i = 0; i < 6; i++)
 		nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
 
-	nv_wr32(priv, 0x4078bc, (oprv->tpc_total << 8) | oprv->magic_not_rop_nr);
+	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, oprv->tpc_nr, sizeof(oprv->tpc_nr));
-	for (gpc = 0; gpc < oprv->gpc_nr; gpc++)
-		tpc_mask |= ((1 << oprv->tpc_nr[gpc]) - 1) << (gpc * 8);
+	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 * (oprv->tpc_total - 1)) / 32;
+		a = (i * (priv->tpc_total - 1)) / 32;
 		if (a != b) {
 			b = a;
 			do {
-				gpc = (gpc + 1) % oprv->gpc_nr;
+				gpc = (gpc + 1) % priv->gpc_nr;
 			} while (!tpcnr[gpc]);
-			tpc = oprv->tpc_nr[gpc] - tpcnr[gpc]--;
+			tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
 
 			tpc_set |= 1 << ((gpc * 8) + tpc);
 		}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
index 7f3a275..e5b0189 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
@@ -22,19 +22,22 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
-#include "drm.h"
-#include <nouveau_drm.h>
-#include "nouveau_drv.h"
-#include "nouveau_hw.h"
-#include "nouveau_util.h"
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
+#include <core/namedb.h>
 
-struct nv04_graph_engine {
-	struct nouveau_exec_engine base;
-};
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/timer.h>
 
-static uint32_t nv04_graph_ctx_regs[] = {
+#include <engine/fifo.h>
+#include <engine/graph.h>
+
+#include "regs.h"
+
+static u32
+nv04_graph_ctx_regs[] = {
 	0x0040053c,
 	0x00400544,
 	0x00400540,
@@ -348,205 +351,28 @@
 	NV04_PGRAPH_DEBUG_3
 };
 
-struct graph_state {
-	uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
+struct nv04_graph_priv {
+	struct nouveau_graph base;
+	struct nv04_graph_chan *chan[16];
+	spinlock_t lock;
 };
 
-static struct nouveau_channel *
-nv04_graph_channel(struct drm_device *dev)
+struct nv04_graph_chan {
+	struct nouveau_object base;
+	int chid;
+	u32 nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
+};
+
+
+static inline struct nv04_graph_priv *
+nv04_graph_priv(struct nv04_graph_chan *chan)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int chid = 15;
-
-	if (nv_rd32(dev, NV04_PGRAPH_CTX_CONTROL) & 0x00010000)
-		chid = nv_rd32(dev, NV04_PGRAPH_CTX_USER) >> 24;
-
-	if (chid > 15)
-		return NULL;
-
-	return dev_priv->channels.ptr[chid];
+	return (void *)nv_object(chan)->engine;
 }
 
-static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) {
-		if (nv04_graph_ctx_regs[i] == reg)
-			return &ctx->nv04[i];
-	}
-
-	return NULL;
-}
-
-static int
-nv04_graph_load_context(struct nouveau_channel *chan)
-{
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct drm_device *dev = chan->dev;
-	uint32_t tmp;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
-		nv_wr32(dev, nv04_graph_ctx_regs[i], pgraph_ctx->nv04[i]);
-
-	nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
-
-	tmp  = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff;
-	nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp | chan->id << 24);
-
-	tmp = nv_rd32(dev, NV04_PGRAPH_FFINTFC_ST2);
-	nv_wr32(dev, NV04_PGRAPH_FFINTFC_ST2, tmp & 0x000fffff);
-
-	return 0;
-}
-
-static int
-nv04_graph_unload_context(struct drm_device *dev)
-{
-	struct nouveau_channel *chan = NULL;
-	struct graph_state *ctx;
-	uint32_t tmp;
-	int i;
-
-	chan = nv04_graph_channel(dev);
-	if (!chan)
-		return 0;
-	ctx = chan->engctx[NVOBJ_ENGINE_GR];
-
-	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
-		ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]);
-
-	nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
-	tmp  = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 15 << 24;
-	nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp);
-	return 0;
-}
-
-static int
-nv04_graph_context_new(struct nouveau_channel *chan, int engine)
-{
-	struct graph_state *pgraph_ctx;
-	NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
-
-	pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
-	if (pgraph_ctx == NULL)
-		return -ENOMEM;
-
-	*ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
-	chan->engctx[engine] = pgraph_ctx;
-	return 0;
-}
-
-static void
-nv04_graph_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct graph_state *pgraph_ctx = chan->engctx[engine];
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-
-	/* Unload the context if it's the currently active one */
-	if (nv04_graph_channel(dev) == chan)
-		nv04_graph_unload_context(dev);
-
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* Free the context resources */
-	kfree(pgraph_ctx);
-	chan->engctx[engine] = NULL;
-}
-
-int
-nv04_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
-	if (ret)
-		return ret;
-	obj->engine = 1;
-	obj->class  = class;
-
-#ifdef __BIG_ENDIAN
-	nv_wo32(obj, 0x00, 0x00080000 | class);
-#else
-	nv_wo32(obj, 0x00, class);
-#endif
-	nv_wo32(obj, 0x04, 0x00000000);
-	nv_wo32(obj, 0x08, 0x00000000);
-	nv_wo32(obj, 0x0c, 0x00000000);
-
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
-}
-
-static int
-nv04_graph_init(struct drm_device *dev, int engine)
-{
-	uint32_t tmp;
-
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
-			~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
-			 NV_PMC_ENABLE_PGRAPH);
-
-	/* Enable PGRAPH interrupts */
-	nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(dev, NV04_PGRAPH_VALID1, 0);
-	nv_wr32(dev, NV04_PGRAPH_VALID2, 0);
-	/*nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x000001FF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000);
-	/*1231C000 blob, 001 haiku*/
-	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100);
-	/*0x72111100 blob , 01 haiku*/
-	/*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
-	/*haiku same*/
-
-	/*nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
-	/*haiku and blob 10d4*/
-
-	nv_wr32(dev, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
-	tmp  = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 15 << 24;
-	nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp);
-
-	/* These don't belong here, they're part of a per-channel context */
-	nv_wr32(dev, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
-
-	return 0;
-}
-
-static int
-nv04_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-		return -EBUSY;
-	}
-	nv04_graph_unload_context(dev);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-	return 0;
-}
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
 
 /*
  * Software methods, why they are needed, and how they all work:
@@ -623,37 +449,35 @@
  */
 
 static void
-nv04_graph_set_ctx1(struct nouveau_channel *chan, u32 mask, u32 value)
+nv04_graph_set_ctx1(struct nouveau_object *object, u32 mask, u32 value)
 {
-	struct drm_device *dev = chan->dev;
-	u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4;
-	int subc = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
 	u32 tmp;
 
-	tmp  = nv_ri32(dev, instance);
+	tmp  = nv_ro32(object, 0x00);
 	tmp &= ~mask;
 	tmp |= value;
+	nv_wo32(object, 0x00, tmp);
 
-	nv_wi32(dev, instance, tmp);
-	nv_wr32(dev, NV04_PGRAPH_CTX_SWITCH1, tmp);
-	nv_wr32(dev, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
+	nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp);
+	nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
 }
 
 static void
-nv04_graph_set_ctx_val(struct nouveau_channel *chan, u32 mask, u32 value)
+nv04_graph_set_ctx_val(struct nouveau_object *object, u32 mask, u32 value)
 {
-	struct drm_device *dev = chan->dev;
-	u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4;
-	u32 tmp, ctx1;
 	int class, op, valid = 1;
+	u32 tmp, ctx1;
 
-	ctx1 = nv_ri32(dev, instance);
+	ctx1 = nv_ro32(object, 0x00);
 	class = ctx1 & 0xff;
 	op = (ctx1 >> 15) & 7;
-	tmp  = nv_ri32(dev, instance + 0xc);
+
+	tmp = nv_ro32(object, 0x0c);
 	tmp &= ~mask;
 	tmp |= value;
-	nv_wi32(dev, instance + 0xc, tmp);
+	nv_wo32(object, 0x0c, tmp);
 
 	/* check for valid surf2d/surf_dst/surf_color */
 	if (!(tmp & 0x02000000))
@@ -685,30 +509,34 @@
 		break;
 	}
 
-	nv04_graph_set_ctx1(chan, 0x01000000, valid << 24);
+	nv04_graph_set_ctx1(object, 0x01000000, valid << 24);
 }
 
 static int
-nv04_graph_mthd_set_operation(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_set_operation(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
+	u32 class = nv_ro32(object, 0) & 0xff;
+	u32 data = *(u32 *)args;
 	if (data > 5)
 		return 1;
 	/* Old versions of the objects only accept first three operations. */
 	if (data > 2 && class < 0x40)
 		return 1;
-	nv04_graph_set_ctx1(chan, 0x00038000, data << 15);
+	nv04_graph_set_ctx1(object, 0x00038000, data << 15);
 	/* changing operation changes set of objects needed for validation */
-	nv04_graph_set_ctx_val(chan, 0, 0);
+	nv04_graph_set_ctx_val(object, 0, 0);
 	return 0;
 }
 
 static int
-nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_surf3d_clip_h(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
-	uint32_t min = data & 0xffff, max;
-	uint32_t w = data >> 16;
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	u32 data = *(u32 *)args;
+	u32 min = data & 0xffff, max;
+	u32 w = data >> 16;
 	if (min & 0x8000)
 		/* too large */
 		return 1;
@@ -717,17 +545,19 @@
 		w |= 0xffff0000;
 	max = min + w;
 	max &= 0x3ffff;
-	nv_wr32(chan->dev, 0x40053c, min);
-	nv_wr32(chan->dev, 0x400544, max);
+	nv_wr32(priv, 0x40053c, min);
+	nv_wr32(priv, 0x400544, max);
 	return 0;
 }
 
 static int
-nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_surf3d_clip_v(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
-	uint32_t min = data & 0xffff, max;
-	uint32_t w = data >> 16;
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	u32 data = *(u32 *)args;
+	u32 min = data & 0xffff, max;
+	u32 w = data >> 16;
 	if (min & 0x8000)
 		/* too large */
 		return 1;
@@ -736,223 +566,661 @@
 		w |= 0xffff0000;
 	max = min + w;
 	max &= 0x3ffff;
-	nv_wr32(chan->dev, 0x400540, min);
-	nv_wr32(chan->dev, 0x400548, max);
+	nv_wr32(priv, 0x400540, min);
+	nv_wr32(priv, 0x400548, max);
 	return 0;
 }
 
-static int
-nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan,
-			    u32 class, u32 mthd, u32 data)
+static u16
+nv04_graph_mthd_bind_class(struct nouveau_object *object, u32 *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	struct nouveau_instmem *imem = nouveau_instmem(object);
+	u32 inst = *(u32 *)args << 4;
+	return nv_ro32(imem, inst);
+}
+
+static int
+nv04_graph_mthd_bind_surf2d(struct nouveau_object *object, u32 mthd,
+			    void *args, u32 size)
+{
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0);
+		nv04_graph_set_ctx1(object, 0x00004000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0);
 		return 0;
 	case 0x42:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx1(object, 0x00004000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan,
-				    u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_object *object, u32 mthd,
+				    void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0);
+		nv04_graph_set_ctx1(object, 0x00004000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0);
 		return 0;
 	case 0x42:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx1(object, 0x00004000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	case 0x52:
-		nv04_graph_set_ctx1(chan, 0x00004000, 0x00004000);
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx1(object, 0x00004000, 0x00004000);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan,
-			       u32 class, u32 mthd, u32 data)
+nv01_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd,
+			  void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x08000000, 0);
+		nv04_graph_set_ctx_val(object, 0x08000000, 0);
 		return 0;
 	case 0x18:
-		nv04_graph_set_ctx_val(chan, 0x08000000, 0x08000000);
+		nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan,
-			       u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd,
+			  void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x08000000, 0);
+		nv04_graph_set_ctx_val(object, 0x08000000, 0);
 		return 0;
 	case 0x44:
-		nv04_graph_set_ctx_val(chan, 0x08000000, 0x08000000);
+		nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_rop(struct nouveau_channel *chan,
-			 u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_rop(struct nouveau_object *object, u32 mthd,
+			 void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x10000000, 0);
+		nv04_graph_set_ctx_val(object, 0x10000000, 0);
 		return 0;
 	case 0x43:
-		nv04_graph_set_ctx_val(chan, 0x10000000, 0x10000000);
+		nv04_graph_set_ctx_val(object, 0x10000000, 0x10000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan,
-			   u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_beta1(struct nouveau_object *object, u32 mthd,
+			   void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x20000000, 0);
+		nv04_graph_set_ctx_val(object, 0x20000000, 0);
 		return 0;
 	case 0x12:
-		nv04_graph_set_ctx_val(chan, 0x20000000, 0x20000000);
+		nv04_graph_set_ctx_val(object, 0x20000000, 0x20000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan,
-			   u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_beta4(struct nouveau_object *object, u32 mthd,
+			   void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x40000000, 0);
+		nv04_graph_set_ctx_val(object, 0x40000000, 0);
 		return 0;
 	case 0x72:
-		nv04_graph_set_ctx_val(chan, 0x40000000, 0x40000000);
+		nv04_graph_set_ctx_val(object, 0x40000000, 0x40000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf_dst(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0);
 		return 0;
 	case 0x58:
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan,
-			      u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf_src(struct nouveau_object *object, u32 mthd,
+			      void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x04000000, 0);
+		nv04_graph_set_ctx_val(object, 0x04000000, 0);
 		return 0;
 	case 0x59:
-		nv04_graph_set_ctx_val(chan, 0x04000000, 0x04000000);
+		nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan,
-				u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf_color(struct nouveau_object *object, u32 mthd,
+				void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0);
 		return 0;
 	case 0x5a:
-		nv04_graph_set_ctx_val(chan, 0x02000000, 0x02000000);
+		nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan,
-			       u32 class, u32 mthd, u32 data)
+nv04_graph_mthd_bind_surf_zeta(struct nouveau_object *object, u32 mthd,
+			       void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx_val(chan, 0x04000000, 0);
+		nv04_graph_set_ctx_val(object, 0x04000000, 0);
 		return 0;
 	case 0x5b:
-		nv04_graph_set_ctx_val(chan, 0x04000000, 0x04000000);
+		nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_clip(struct nouveau_channel *chan,
-			  u32 class, u32 mthd, u32 data)
+nv01_graph_mthd_bind_clip(struct nouveau_object *object, u32 mthd,
+			  void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx1(chan, 0x2000, 0);
+		nv04_graph_set_ctx1(object, 0x2000, 0);
 		return 0;
 	case 0x19:
-		nv04_graph_set_ctx1(chan, 0x2000, 0x2000);
+		nv04_graph_set_ctx1(object, 0x2000, 0x2000);
 		return 0;
 	}
 	return 1;
 }
 
 static int
-nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan,
-			    u32 class, u32 mthd, u32 data)
+nv01_graph_mthd_bind_chroma(struct nouveau_object *object, u32 mthd,
+			    void *args, u32 size)
 {
-	switch (nv_ri32(chan->dev, data << 4) & 0xff) {
+	switch (nv04_graph_mthd_bind_class(object, args, size)) {
 	case 0x30:
-		nv04_graph_set_ctx1(chan, 0x1000, 0);
+		nv04_graph_set_ctx1(object, 0x1000, 0);
 		return 0;
 	/* Yes, for some reason even the old versions of objects
 	 * accept 0x57 and not 0x17. Consistency be damned.
 	 */
 	case 0x57:
-		nv04_graph_set_ctx1(chan, 0x1000, 0x1000);
+		nv04_graph_set_ctx1(object, 0x1000, 0x1000);
 		return 0;
 	}
 	return 1;
 }
 
-static struct nouveau_bitfield nv04_graph_intr[] = {
+static struct nouveau_omthds
+nv03_graph_gdi_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_patt },
+	{ 0x0188, nv04_graph_mthd_bind_rop },
+	{ 0x018c, nv04_graph_mthd_bind_beta1 },
+	{ 0x0190, nv04_graph_mthd_bind_surf_dst },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_gdi_omthds[] = {
+	{ 0x0188, nv04_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_beta4 },
+	{ 0x0198, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv01_graph_blit_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv01_graph_mthd_bind_patt },
+	{ 0x0190, nv04_graph_mthd_bind_rop },
+	{ 0x0194, nv04_graph_mthd_bind_beta1 },
+	{ 0x0198, nv04_graph_mthd_bind_surf_dst },
+	{ 0x019c, nv04_graph_mthd_bind_surf_src },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_blit_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv04_graph_mthd_bind_patt },
+	{ 0x0190, nv04_graph_mthd_bind_rop },
+	{ 0x0194, nv04_graph_mthd_bind_beta1 },
+	{ 0x0198, nv04_graph_mthd_bind_beta4 },
+	{ 0x019c, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_iifc_omthds[] = {
+	{ 0x0188, nv01_graph_mthd_bind_chroma },
+	{ 0x018c, nv01_graph_mthd_bind_clip },
+	{ 0x0190, nv04_graph_mthd_bind_patt },
+	{ 0x0194, nv04_graph_mthd_bind_rop },
+	{ 0x0198, nv04_graph_mthd_bind_beta1 },
+	{ 0x019c, nv04_graph_mthd_bind_beta4 },
+	{ 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf },
+	{ 0x03e4, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv01_graph_ifc_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv01_graph_mthd_bind_patt },
+	{ 0x0190, nv04_graph_mthd_bind_rop },
+	{ 0x0194, nv04_graph_mthd_bind_beta1 },
+	{ 0x0198, nv04_graph_mthd_bind_surf_dst },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_ifc_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv04_graph_mthd_bind_patt },
+	{ 0x0190, nv04_graph_mthd_bind_rop },
+	{ 0x0194, nv04_graph_mthd_bind_beta1 },
+	{ 0x0198, nv04_graph_mthd_bind_beta4 },
+	{ 0x019c, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv03_graph_sifc_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv01_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_surf_dst },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_sifc_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_chroma },
+	{ 0x0188, nv04_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_beta4 },
+	{ 0x0198, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv03_graph_sifm_omthds[] = {
+	{ 0x0188, nv01_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_surf_dst },
+	{ 0x0304, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_sifm_omthds[] = {
+	{ 0x0188, nv04_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_beta4 },
+	{ 0x0198, nv04_graph_mthd_bind_surf2d },
+	{ 0x0304, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_surf3d_omthds[] = {
+	{ 0x02f8, nv04_graph_mthd_surf3d_clip_h },
+	{ 0x02fc, nv04_graph_mthd_surf3d_clip_v },
+	{}
+};
+
+static struct nouveau_omthds
+nv03_graph_ttri_omthds[] = {
+	{ 0x0188, nv01_graph_mthd_bind_clip },
+	{ 0x018c, nv04_graph_mthd_bind_surf_color },
+	{ 0x0190, nv04_graph_mthd_bind_surf_zeta },
+	{}
+};
+
+static struct nouveau_omthds
+nv01_graph_prim_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_clip },
+	{ 0x0188, nv01_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_surf_dst },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static struct nouveau_omthds
+nv04_graph_prim_omthds[] = {
+	{ 0x0184, nv01_graph_mthd_bind_clip },
+	{ 0x0188, nv04_graph_mthd_bind_patt },
+	{ 0x018c, nv04_graph_mthd_bind_rop },
+	{ 0x0190, nv04_graph_mthd_bind_beta1 },
+	{ 0x0194, nv04_graph_mthd_bind_beta4 },
+	{ 0x0198, nv04_graph_mthd_bind_surf2d },
+	{ 0x02fc, nv04_graph_mthd_set_operation },
+	{}
+};
+
+static int
+nv04_graph_object_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
+{
+	struct nouveau_gpuobj *obj;
+	int ret;
+
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    16, 16, 0, &obj);
+	*pobject = nv_object(obj);
+	if (ret)
+		return ret;
+
+	nv_wo32(obj, 0x00, nv_mclass(obj));
+#ifdef __BIG_ENDIAN
+	nv_mo32(obj, 0x00, 0x00080000, 0x00080000);
+#endif
+	nv_wo32(obj, 0x04, 0x00000000);
+	nv_wo32(obj, 0x08, 0x00000000);
+	nv_wo32(obj, 0x0c, 0x00000000);
+	return 0;
+}
+
+struct nouveau_ofuncs
+nv04_graph_ofuncs = {
+	.ctor = nv04_graph_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
+
+static struct nouveau_oclass
+nv04_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+	{ 0x0017, &nv04_graph_ofuncs }, /* chroma */
+	{ 0x0018, &nv04_graph_ofuncs }, /* pattern (nv01) */
+	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
+	{ 0x001c, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* line */
+	{ 0x001d, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* tri */
+	{ 0x001e, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* rect */
+	{ 0x001f, &nv04_graph_ofuncs, nv01_graph_blit_omthds },
+	{ 0x0021, &nv04_graph_ofuncs, nv01_graph_ifc_omthds },
+	{ 0x0030, &nv04_graph_ofuncs }, /* null */
+	{ 0x0036, &nv04_graph_ofuncs, nv03_graph_sifc_omthds },
+	{ 0x0037, &nv04_graph_ofuncs, nv03_graph_sifm_omthds },
+	{ 0x0038, &nv04_graph_ofuncs }, /* dvd subpicture */
+	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+	{ 0x0042, &nv04_graph_ofuncs }, /* surf2d */
+	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
+	{ 0x0048, &nv04_graph_ofuncs, nv03_graph_ttri_omthds },
+	{ 0x004a, &nv04_graph_ofuncs, nv04_graph_gdi_omthds },
+	{ 0x004b, &nv04_graph_ofuncs, nv03_graph_gdi_omthds },
+	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+	{ 0x0053, &nv04_graph_ofuncs, nv04_graph_surf3d_omthds },
+	{ 0x0054, &nv04_graph_ofuncs }, /* ttri */
+	{ 0x0055, &nv04_graph_ofuncs }, /* mtri */
+	{ 0x0057, &nv04_graph_ofuncs }, /* chroma */
+	{ 0x0058, &nv04_graph_ofuncs }, /* surf_dst */
+	{ 0x0059, &nv04_graph_ofuncs }, /* surf_src */
+	{ 0x005a, &nv04_graph_ofuncs }, /* surf_color */
+	{ 0x005b, &nv04_graph_ofuncs }, /* surf_zeta */
+	{ 0x005c, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* line */
+	{ 0x005d, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* tri */
+	{ 0x005e, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* rect */
+	{ 0x005f, &nv04_graph_ofuncs, nv04_graph_blit_omthds },
+	{ 0x0060, &nv04_graph_ofuncs, nv04_graph_iifc_omthds },
+	{ 0x0061, &nv04_graph_ofuncs, nv04_graph_ifc_omthds },
+	{ 0x0064, &nv04_graph_ofuncs }, /* iifc (nv05) */
+	{ 0x0065, &nv04_graph_ofuncs }, /* ifc (nv05) */
+	{ 0x0066, &nv04_graph_ofuncs }, /* sifc (nv05) */
+	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+	{ 0x0076, &nv04_graph_ofuncs, nv04_graph_sifc_omthds },
+	{ 0x0077, &nv04_graph_ofuncs, nv04_graph_sifm_omthds },
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv04_graph_chan *
+nv04_graph_channel(struct nv04_graph_priv *priv)
+{
+	struct nv04_graph_chan *chan = NULL;
+	if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) {
+		int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24;
+		if (chid < ARRAY_SIZE(priv->chan))
+			chan = priv->chan[chid];
+	}
+	return chan;
+}
+
+static int
+nv04_graph_load_context(struct nv04_graph_chan *chan, int chid)
+{
+	struct nv04_graph_priv *priv = nv04_graph_priv(chan);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
+		nv_wr32(priv, nv04_graph_ctx_regs[i], chan->nv04[i]);
+
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+	nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000);
+	return 0;
+}
+
+static int
+nv04_graph_unload_context(struct nv04_graph_chan *chan)
+{
+	struct nv04_graph_priv *priv = nv04_graph_priv(chan);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
+		chan->nv04[i] = nv_rd32(priv, nv04_graph_ctx_regs[i]);
+
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+	return 0;
+}
+
+static void
+nv04_graph_context_switch(struct nv04_graph_priv *priv)
+{
+	struct nv04_graph_chan *prev = NULL;
+	struct nv04_graph_chan *next = NULL;
+	unsigned long flags;
+	int chid;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv04_graph_idle(priv);
+
+	/* If previous context is valid, we need to save it */
+	prev = nv04_graph_channel(priv);
+	if (prev)
+		nv04_graph_unload_context(prev);
+
+	/* load context for next channel */
+	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f;
+	next = priv->chan[chid];
+	if (next)
+		nv04_graph_load_context(next, chid);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static u32 *ctx_reg(struct nv04_graph_chan *chan, u32 reg)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) {
+		if (nv04_graph_ctx_regs[i] == reg)
+			return &chan->nv04[i];
+	}
+
+	return NULL;
+}
+
+static int
+nv04_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nouveau_fifo_chan *fifo = (void *)parent;
+	struct nv04_graph_priv *priv = (void *)engine;
+	struct nv04_graph_chan *chan;
+	unsigned long flags;
+	int ret;
+
+	ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->chan[fifo->chid]) {
+		*pobject = nv_object(priv->chan[fifo->chid]);
+		atomic_inc(&(*pobject)->refcount);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		nouveau_object_destroy(&chan->base);
+		return 1;
+	}
+
+	*ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+	priv->chan[fifo->chid] = chan;
+	chan->chid = fifo->chid;
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return 0;
+}
+
+static void
+nv04_graph_context_dtor(struct nouveau_object *object)
+{
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	struct nv04_graph_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->chan[chan->chid] = NULL;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	nouveau_object_destroy(&chan->base);
+}
+
+static int
+nv04_graph_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	struct nv04_graph_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	if (nv04_graph_channel(priv) == chan)
+		nv04_graph_unload_context(chan);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return nouveau_object_fini(&chan->base, suspend);
+}
+
+static struct nouveau_oclass
+nv04_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_graph_context_ctor,
+		.dtor = nv04_graph_context_dtor,
+		.init = nouveau_object_init,
+		.fini = nv04_graph_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+bool
+nv04_graph_idle(void *obj)
+{
+	struct nouveau_graph *graph = nouveau_graph(obj);
+	u32 mask = 0xffffffff;
+
+	if (nv_device(obj)->card_type == NV_40)
+		mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
+
+	if (!nv_wait(graph, NV04_PGRAPH_STATUS, mask, 0)) {
+		nv_error(graph, "idle timed out with status 0x%08x\n",
+			 nv_rd32(graph, NV04_PGRAPH_STATUS));
+		return false;
+	}
+
+	return true;
+}
+
+static struct nouveau_bitfield
+nv04_graph_intr_name[] = {
 	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
 	{}
 };
 
-static struct nouveau_bitfield nv04_graph_nstatus[] = {
+static struct nouveau_bitfield
+nv04_graph_nstatus[] = {
 	{ NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
 	{ NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
 	{ NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
@@ -960,7 +1228,8 @@
 	{}
 };
 
-struct nouveau_bitfield nv04_graph_nsource[] = {
+struct nouveau_bitfield
+nv04_graph_nsource[] = {
 	{ NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
 	{ NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
 	{ NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
@@ -984,343 +1253,135 @@
 };
 
 static void
-nv04_graph_context_switch(struct drm_device *dev)
+nv04_graph_intr(struct nouveau_subdev *subdev)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = NULL;
-	int chid;
+	struct nv04_graph_priv *priv = (void *)subdev;
+	struct nv04_graph_chan *chan = NULL;
+	struct nouveau_namedb *namedb = NULL;
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x0f000000) >> 24;
+	u32 subc = (addr & 0x0000e000) >> 13;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff;
+	u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4;
+	u32 show = stat;
+	unsigned long flags;
 
-	nouveau_wait_for_idle(dev);
-
-	/* If previous context is valid, we need to save it */
-	nv04_graph_unload_context(dev);
-
-	/* Load context for next channel */
-	chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) &
-			    NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
-	chan = dev_priv->channels.ptr[chid];
+	spin_lock_irqsave(&priv->lock, flags);
+	chan = priv->chan[chid];
 	if (chan)
-		nv04_graph_load_context(chan);
-}
+		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
-static void
-nv04_graph_isr(struct drm_device *dev)
-{
-	u32 stat;
-
-	while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-		u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-		u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 chid = (addr & 0x0f000000) >> 24;
-		u32 subc = (addr & 0x0000e000) >> 13;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
-		u32 show = stat;
-
-		if (stat & NV_PGRAPH_INTR_NOTIFY) {
-			if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-				if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-					show &= ~NV_PGRAPH_INTR_NOTIFY;
-			}
-		}
-
-		if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-			nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-			stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-			show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-			nv04_graph_context_switch(dev);
-		}
-
-		nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-		nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-		if (show && nouveau_ratelimit()) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv04_graph_intr, show);
-			printk(" nsource:");
-			nouveau_bitfield_print(nv04_graph_nsource, nsource);
-			printk(" nstatus:");
-			nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-				     "mthd 0x%04x data 0x%08x\n",
-				chid, subc, class, mthd, data);
+	if (stat & NV_PGRAPH_INTR_NOTIFY) {
+		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+			handle = nouveau_namedb_get_vinst(namedb, inst);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_NOTIFY;
 		}
 	}
+
+	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		nv04_graph_context_switch(priv);
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "");
+		nouveau_bitfield_print(nv04_graph_intr_name, show);
+		printk(" nsource:");
+		nouveau_bitfield_print(nv04_graph_nsource, nsource);
+		printk(" nstatus:");
+		nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
+		printk("\n");
+		nv_error(priv, "ch %d/%d class 0x%04x "
+			       "mthd 0x%04x data 0x%08x\n",
+			 chid, subc, class, mthd, data);
+	}
+
+	nouveau_namedb_put(handle);
 }
 
-static void
-nv04_graph_destroy(struct drm_device *dev, int engine)
+static int
+nv04_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
 {
-	struct nv04_graph_engine *pgraph = nv_engine(dev, engine);
+	struct nv04_graph_priv *priv;
+	int ret;
 
-	nouveau_irq_unregister(dev, 12);
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(pgraph);
-}
-
-int
-nv04_graph_create(struct drm_device *dev)
-{
-	struct nv04_graph_engine *pgraph;
-
-	pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
-
-	pgraph->base.destroy = nv04_graph_destroy;
-	pgraph->base.init = nv04_graph_init;
-	pgraph->base.fini = nv04_graph_fini;
-	pgraph->base.context_new = nv04_graph_context_new;
-	pgraph->base.context_del = nv04_graph_context_del;
-	pgraph->base.object_new = nv04_graph_object_new;
-
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	nouveau_irq_register(dev, 12, nv04_graph_isr);
-
-	/* dvd subpicture */
-	NVOBJ_CLASS(dev, 0x0038, GR);
-
-	/* m2mf */
-	NVOBJ_CLASS(dev, 0x0039, GR);
-
-	/* nv03 gdirect */
-	NVOBJ_CLASS(dev, 0x004b, GR);
-	NVOBJ_MTHD (dev, 0x004b, 0x0184, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x004b, 0x0188, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x004b, 0x018c, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x004b, 0x0190, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x004b, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 gdirect */
-	NVOBJ_CLASS(dev, 0x004a, GR);
-	NVOBJ_MTHD (dev, 0x004a, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x004a, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x004a, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x004a, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x004a, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x004a, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv01 imageblit */
-	NVOBJ_CLASS(dev, 0x001f, GR);
-	NVOBJ_MTHD (dev, 0x001f, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x001f, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x001f, 0x018c, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x001f, 0x0190, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x001f, 0x0194, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x001f, 0x0198, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x001f, 0x019c, nv04_graph_mthd_bind_surf_src);
-	NVOBJ_MTHD (dev, 0x001f, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 imageblit */
-	NVOBJ_CLASS(dev, 0x005f, GR);
-	NVOBJ_MTHD (dev, 0x005f, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x005f, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x005f, 0x018c, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x005f, 0x0190, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x005f, 0x0194, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x005f, 0x0198, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x005f, 0x019c, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x005f, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 iifc */
-	NVOBJ_CLASS(dev, 0x0060, GR);
-	NVOBJ_MTHD (dev, 0x0060, 0x0188, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0060, 0x018c, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x0060, 0x0190, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x0060, 0x0194, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0060, 0x0198, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0060, 0x019c, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x0060, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf);
-	NVOBJ_MTHD (dev, 0x0060, 0x03e4, nv04_graph_mthd_set_operation);
-
-	/* nv05 iifc */
-	NVOBJ_CLASS(dev, 0x0064, GR);
-
-	/* nv01 ifc */
-	NVOBJ_CLASS(dev, 0x0021, GR);
-	NVOBJ_MTHD (dev, 0x0021, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0021, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x0021, 0x018c, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x0021, 0x0190, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0021, 0x0194, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0021, 0x0198, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x0021, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 ifc */
-	NVOBJ_CLASS(dev, 0x0061, GR);
-	NVOBJ_MTHD (dev, 0x0061, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0061, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x0061, 0x018c, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x0061, 0x0190, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0061, 0x0194, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0061, 0x0198, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x0061, 0x019c, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x0061, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv05 ifc */
-	NVOBJ_CLASS(dev, 0x0065, GR);
-
-	/* nv03 sifc */
-	NVOBJ_CLASS(dev, 0x0036, GR);
-	NVOBJ_MTHD (dev, 0x0036, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0036, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x0036, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0036, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0036, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x0036, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 sifc */
-	NVOBJ_CLASS(dev, 0x0076, GR);
-	NVOBJ_MTHD (dev, 0x0076, 0x0184, nv04_graph_mthd_bind_chroma);
-	NVOBJ_MTHD (dev, 0x0076, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x0076, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0076, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0076, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x0076, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x0076, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv05 sifc */
-	NVOBJ_CLASS(dev, 0x0066, GR);
-
-	/* nv03 sifm */
-	NVOBJ_CLASS(dev, 0x0037, GR);
-	NVOBJ_MTHD (dev, 0x0037, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x0037, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0037, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0037, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x0037, 0x0304, nv04_graph_mthd_set_operation);
-
-	/* nv04 sifm */
-	NVOBJ_CLASS(dev, 0x0077, GR);
-	NVOBJ_MTHD (dev, 0x0077, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x0077, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x0077, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x0077, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x0077, 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf);
-	NVOBJ_MTHD (dev, 0x0077, 0x0304, nv04_graph_mthd_set_operation);
-
-	/* null */
-	NVOBJ_CLASS(dev, 0x0030, GR);
-
-	/* surf2d */
-	NVOBJ_CLASS(dev, 0x0042, GR);
-
-	/* rop */
-	NVOBJ_CLASS(dev, 0x0043, GR);
-
-	/* beta1 */
-	NVOBJ_CLASS(dev, 0x0012, GR);
-
-	/* beta4 */
-	NVOBJ_CLASS(dev, 0x0072, GR);
-
-	/* cliprect */
-	NVOBJ_CLASS(dev, 0x0019, GR);
-
-	/* nv01 pattern */
-	NVOBJ_CLASS(dev, 0x0018, GR);
-
-	/* nv04 pattern */
-	NVOBJ_CLASS(dev, 0x0044, GR);
-
-	/* swzsurf */
-	NVOBJ_CLASS(dev, 0x0052, GR);
-
-	/* surf3d */
-	NVOBJ_CLASS(dev, 0x0053, GR);
-	NVOBJ_MTHD (dev, 0x0053, 0x02f8, nv04_graph_mthd_surf3d_clip_h);
-	NVOBJ_MTHD (dev, 0x0053, 0x02fc, nv04_graph_mthd_surf3d_clip_v);
-
-	/* nv03 tex_tri */
-	NVOBJ_CLASS(dev, 0x0048, GR);
-	NVOBJ_MTHD (dev, 0x0048, 0x0188, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x0048, 0x018c, nv04_graph_mthd_bind_surf_color);
-	NVOBJ_MTHD (dev, 0x0048, 0x0190, nv04_graph_mthd_bind_surf_zeta);
-
-	/* tex_tri */
-	NVOBJ_CLASS(dev, 0x0054, GR);
-
-	/* multitex_tri */
-	NVOBJ_CLASS(dev, 0x0055, GR);
-
-	/* nv01 chroma */
-	NVOBJ_CLASS(dev, 0x0017, GR);
-
-	/* nv04 chroma */
-	NVOBJ_CLASS(dev, 0x0057, GR);
-
-	/* surf_dst */
-	NVOBJ_CLASS(dev, 0x0058, GR);
-
-	/* surf_src */
-	NVOBJ_CLASS(dev, 0x0059, GR);
-
-	/* surf_color */
-	NVOBJ_CLASS(dev, 0x005a, GR);
-
-	/* surf_zeta */
-	NVOBJ_CLASS(dev, 0x005b, GR);
-
-	/* nv01 line */
-	NVOBJ_CLASS(dev, 0x001c, GR);
-	NVOBJ_MTHD (dev, 0x001c, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x001c, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x001c, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x001c, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x001c, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x001c, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 line */
-	NVOBJ_CLASS(dev, 0x005c, GR);
-	NVOBJ_MTHD (dev, 0x005c, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x005c, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x005c, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x005c, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x005c, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x005c, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x005c, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv01 tri */
-	NVOBJ_CLASS(dev, 0x001d, GR);
-	NVOBJ_MTHD (dev, 0x001d, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x001d, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x001d, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x001d, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x001d, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x001d, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 tri */
-	NVOBJ_CLASS(dev, 0x005d, GR);
-	NVOBJ_MTHD (dev, 0x005d, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x005d, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x005d, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x005d, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x005d, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x005d, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x005d, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv01 rect */
-	NVOBJ_CLASS(dev, 0x001e, GR);
-	NVOBJ_MTHD (dev, 0x001e, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x001e, 0x0188, nv04_graph_mthd_bind_nv01_patt);
-	NVOBJ_MTHD (dev, 0x001e, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x001e, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x001e, 0x0194, nv04_graph_mthd_bind_surf_dst);
-	NVOBJ_MTHD (dev, 0x001e, 0x02fc, nv04_graph_mthd_set_operation);
-
-	/* nv04 rect */
-	NVOBJ_CLASS(dev, 0x005e, GR);
-	NVOBJ_MTHD (dev, 0x005e, 0x0184, nv04_graph_mthd_bind_clip);
-	NVOBJ_MTHD (dev, 0x005e, 0x0188, nv04_graph_mthd_bind_nv04_patt);
-	NVOBJ_MTHD (dev, 0x005e, 0x018c, nv04_graph_mthd_bind_rop);
-	NVOBJ_MTHD (dev, 0x005e, 0x0190, nv04_graph_mthd_bind_beta1);
-	NVOBJ_MTHD (dev, 0x005e, 0x0194, nv04_graph_mthd_bind_beta4);
-	NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d);
-	NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation);
-
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv04_graph_intr;
+	nv_engine(priv)->cclass = &nv04_graph_cclass;
+	nv_engine(priv)->sclass = nv04_graph_sclass;
+	spin_lock_init(&priv->lock);
 	return 0;
 }
+
+static int
+nv04_graph_init(struct nouveau_object *object)
+{
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nv04_graph_priv *priv = (void *)engine;
+	int ret;
+
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* Enable PGRAPH interrupts */
+	nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_VALID1, 0);
+	nv_wr32(priv, NV04_PGRAPH_VALID2, 0);
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000);
+	/*1231C000 blob, 001 haiku*/
+	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100);
+	/*0x72111100 blob , 01 haiku*/
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
+	/*haiku same*/
+
+	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
+	/*haiku and blob 10d4*/
+
+	nv_wr32(priv, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
+	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+
+	/* These don't belong here, they're part of a per-channel context */
+	nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
+	return 0;
+}
+
+struct nouveau_oclass
+nv04_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x04),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv04_graph_ctor,
+		.dtor = _nouveau_graph_dtor,
+		.init = nv04_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
index d006658..ce38196 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
@@ -22,27 +22,28 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
-#include "drm.h"
-#include <nouveau_drm.h>
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
 
-struct nv10_graph_engine {
-	struct nouveau_exec_engine base;
-};
+#include <subdev/fb.h>
+
+#include <engine/fifo.h>
+#include <engine/graph.h>
+
+#include "regs.h"
 
 struct pipe_state {
-	uint32_t pipe_0x0000[0x040/4];
-	uint32_t pipe_0x0040[0x010/4];
-	uint32_t pipe_0x0200[0x0c0/4];
-	uint32_t pipe_0x4400[0x080/4];
-	uint32_t pipe_0x6400[0x3b0/4];
-	uint32_t pipe_0x6800[0x2f0/4];
-	uint32_t pipe_0x6c00[0x030/4];
-	uint32_t pipe_0x7000[0x130/4];
-	uint32_t pipe_0x7400[0x0c0/4];
-	uint32_t pipe_0x7800[0x0c0/4];
+	u32 pipe_0x0000[0x040/4];
+	u32 pipe_0x0040[0x010/4];
+	u32 pipe_0x0200[0x0c0/4];
+	u32 pipe_0x4400[0x080/4];
+	u32 pipe_0x6400[0x3b0/4];
+	u32 pipe_0x6800[0x2f0/4];
+	u32 pipe_0x6c00[0x030/4];
+	u32 pipe_0x7000[0x130/4];
+	u32 pipe_0x7400[0x0c0/4];
+	u32 pipe_0x7800[0x0c0/4];
 };
 
 static int nv10_graph_ctx_regs[] = {
@@ -388,117 +389,322 @@
 	0x00400a04,
 };
 
-struct graph_state {
+struct nv10_graph_priv {
+	struct nouveau_graph base;
+	struct nv10_graph_chan *chan[32];
+	spinlock_t lock;
+};
+
+struct nv10_graph_chan {
+	struct nouveau_object base;
+	int chid;
 	int nv10[ARRAY_SIZE(nv10_graph_ctx_regs)];
 	int nv17[ARRAY_SIZE(nv17_graph_ctx_regs)];
 	struct pipe_state pipe_state;
-	uint32_t lma_window[4];
+	u32 lma_window[4];
 };
 
-#define PIPE_SAVE(dev, state, addr)					\
-	do {								\
-		int __i;						\
-		nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
-		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
-			state[__i] = nv_rd32(dev, NV10_PGRAPH_PIPE_DATA); \
-	} while (0)
 
-#define PIPE_RESTORE(dev, state, addr)					\
-	do {								\
-		int __i;						\
-		nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
-		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
-			nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, state[__i]); \
-	} while (0)
-
-static void nv10_graph_save_pipe(struct nouveau_channel *chan)
+static inline struct nv10_graph_priv *
+nv10_graph_priv(struct nv10_graph_chan *chan)
 {
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct pipe_state *pipe = &pgraph_ctx->pipe_state;
-	struct drm_device *dev = chan->dev;
-
-	PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
-	PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
-	PIPE_SAVE(dev, pipe->pipe_0x6400, 0x6400);
-	PIPE_SAVE(dev, pipe->pipe_0x6800, 0x6800);
-	PIPE_SAVE(dev, pipe->pipe_0x6c00, 0x6c00);
-	PIPE_SAVE(dev, pipe->pipe_0x7000, 0x7000);
-	PIPE_SAVE(dev, pipe->pipe_0x7400, 0x7400);
-	PIPE_SAVE(dev, pipe->pipe_0x7800, 0x7800);
-	PIPE_SAVE(dev, pipe->pipe_0x0040, 0x0040);
-	PIPE_SAVE(dev, pipe->pipe_0x0000, 0x0000);
+	return (void *)nv_object(chan)->engine;
 }
 
-static void nv10_graph_load_pipe(struct nouveau_channel *chan)
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+#define PIPE_SAVE(priv, state, addr)					\
+	do {								\
+		int __i;						\
+		nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
+		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
+			state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \
+	} while (0)
+
+#define PIPE_RESTORE(priv, state, addr)					\
+	do {								\
+		int __i;						\
+		nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
+		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
+			nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \
+	} while (0)
+
+static struct nouveau_oclass
+nv10_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
+	{ 0x0056, &nv04_graph_ofuncs }, /* celcius */
+	{},
+};
+
+static struct nouveau_oclass
+nv15_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
+	{ 0x0096, &nv04_graph_ofuncs }, /* celcius */
+	{},
+};
+
+static int
+nv17_graph_mthd_lma_window(struct nouveau_object *object, u32 mthd,
+			   void *args, u32 size)
 {
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct pipe_state *pipe = &pgraph_ctx->pipe_state;
-	struct drm_device *dev = chan->dev;
-	uint32_t xfmode0, xfmode1;
+	struct nv10_graph_chan *chan = (void *)object->parent;
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+	u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
+	u32 xfmode0, xfmode1;
+	u32 data = *(u32 *)args;
 	int i;
 
-	nouveau_wait_for_idle(dev);
-	/* XXX check haiku comments */
-	xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0);
-	xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+	chan->lma_window[(mthd - 0x1638) / 4] = data;
+
+	if (mthd != 0x1644)
+		return 0;
+
+	nv04_graph_idle(priv);
+
+	PIPE_SAVE(priv, pipe_0x0040, 0x0040);
+	PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+
+	PIPE_RESTORE(priv, chan->lma_window, 0x6790);
+
+	nv04_graph_idle(priv);
+
+	xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+	xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+
+	PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_SAVE(priv, pipe_0x64c0, 0x64c0);
+	PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0);
+	PIPE_SAVE(priv, pipe_0x6a80, 0x6a80);
+
+	nv04_graph_idle(priv);
+
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
 	for (i = 0; i < 4; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
 	for (i = 0; i < 4; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
 
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
 	for (i = 0; i < 3; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
 
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
 	for (i = 0; i < 3; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
 
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
 
+	PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
 
-	PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
-	nouveau_wait_for_idle(dev);
+	nv04_graph_idle(priv);
 
-	/* restore XFMODE */
-	nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
-	PIPE_RESTORE(dev, pipe->pipe_0x6400, 0x6400);
-	PIPE_RESTORE(dev, pipe->pipe_0x6800, 0x6800);
-	PIPE_RESTORE(dev, pipe->pipe_0x6c00, 0x6c00);
-	PIPE_RESTORE(dev, pipe->pipe_0x7000, 0x7000);
-	PIPE_RESTORE(dev, pipe->pipe_0x7400, 0x7400);
-	PIPE_RESTORE(dev, pipe->pipe_0x7800, 0x7800);
-	PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
-	PIPE_RESTORE(dev, pipe->pipe_0x0000, 0x0000);
-	PIPE_RESTORE(dev, pipe->pipe_0x0040, 0x0040);
-	nouveau_wait_for_idle(dev);
+	PIPE_RESTORE(priv, pipe_0x0040, 0x0040);
+
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+
+	PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0);
+	PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0);
+	PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80);
+	PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv04_graph_idle(priv);
+
+	return 0;
 }
 
-static void nv10_graph_create_pipe(struct nouveau_channel *chan)
+static int
+nv17_graph_mthd_lma_enable(struct nouveau_object *object, u32 mthd,
+			   void *args, u32 size)
 {
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
-	struct drm_device *dev = chan->dev;
-	uint32_t *fifo_pipe_state_addr;
+	struct nv10_graph_chan *chan = (void *)object->parent;
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+
+	nv04_graph_idle(priv);
+
+	nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100);
+	nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000);
+	return 0;
+}
+
+static struct nouveau_omthds
+nv17_celcius_omthds[] = {
+	{ 0x1638, nv17_graph_mthd_lma_window },
+	{ 0x163c, nv17_graph_mthd_lma_window },
+	{ 0x1640, nv17_graph_mthd_lma_window },
+	{ 0x1644, nv17_graph_mthd_lma_window },
+	{ 0x1658, nv17_graph_mthd_lma_enable },
+	{}
+};
+
+static struct nouveau_oclass
+nv17_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs }, /* pattern */
+	{ 0x004a, &nv04_graph_ofuncs }, /* gdi */
+	{ 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+	{ 0x005f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs }, /* blit */
+	{ 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+	{ 0x0094, &nv04_graph_ofuncs }, /* ttri */
+	{ 0x0095, &nv04_graph_ofuncs }, /* mtri */
+	{ 0x0099, &nv04_graph_ofuncs, nv17_celcius_omthds },
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv10_graph_chan *
+nv10_graph_channel(struct nv10_graph_priv *priv)
+{
+	struct nv10_graph_chan *chan = NULL;
+	if (nv_rd32(priv, 0x400144) & 0x00010000) {
+		int chid = nv_rd32(priv, 0x400148) >> 24;
+		if (chid < ARRAY_SIZE(priv->chan))
+			chan = priv->chan[chid];
+	}
+	return chan;
+}
+
+static void
+nv10_graph_save_pipe(struct nv10_graph_chan *chan)
+{
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+
+	PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+	PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400);
+	PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800);
+	PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00);
+	PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000);
+	PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400);
+	PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800);
+	PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040);
+	PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000);
+}
+
+static void
+nv10_graph_load_pipe(struct nv10_graph_chan *chan)
+{
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	struct pipe_state *pipe = &chan->pipe_state;
+	u32 xfmode0, xfmode1;
+	int i;
+
+	nv04_graph_idle(priv);
+	/* XXX check haiku comments */
+	xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+	xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+	for (i = 0; i < 4; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+	for (i = 0; i < 3; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+	for (i = 0; i < 3; i++)
+		nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+	nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+	nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+
+	PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
+	nv04_graph_idle(priv);
+
+	/* restore XFMODE */
+	nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+	nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+	PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400);
+	PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800);
+	PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00);
+	PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000);
+	PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400);
+	PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800);
+	PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+	PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000);
+	PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040);
+	nv04_graph_idle(priv);
+}
+
+static void
+nv10_graph_create_pipe(struct nv10_graph_chan *chan)
+{
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	struct pipe_state *pipe_state = &chan->pipe_state;
+	u32 *pipe_state_addr;
 	int i;
 #define PIPE_INIT(addr) \
 	do { \
-		fifo_pipe_state_addr = fifo_pipe_state->pipe_##addr; \
+		pipe_state_addr = pipe_state->pipe_##addr; \
 	} while (0)
 #define PIPE_INIT_END(addr) \
 	do { \
-		uint32_t *__end_addr = fifo_pipe_state->pipe_##addr + \
-				ARRAY_SIZE(fifo_pipe_state->pipe_##addr); \
-		if (fifo_pipe_state_addr != __end_addr) \
-			NV_ERROR(dev, "incomplete pipe init for 0x%x :  %p/%p\n", \
-				addr, fifo_pipe_state_addr, __end_addr); \
+		u32 *__end_addr = pipe_state->pipe_##addr + \
+				ARRAY_SIZE(pipe_state->pipe_##addr); \
+		if (pipe_state_addr != __end_addr) \
+			nv_error(priv, "incomplete pipe init for 0x%x :  %p/%p\n", \
+				addr, pipe_state_addr, __end_addr); \
 	} while (0)
-#define NV_WRITE_PIPE_INIT(value) *(fifo_pipe_state_addr++) = value
+#define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value
 
 	PIPE_INIT(0x0200);
 	for (i = 0; i < 48; i++)
@@ -634,34 +840,36 @@
 #undef NV_WRITE_PIPE_INIT
 }
 
-static int nv10_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
+static int
+nv10_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
 {
 	int i;
 	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) {
 		if (nv10_graph_ctx_regs[i] == reg)
 			return i;
 	}
-	NV_ERROR(dev, "unknow offset nv10_ctx_regs %d\n", reg);
+	nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg);
 	return -1;
 }
 
-static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
+static int
+nv17_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
 {
 	int i;
 	for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) {
 		if (nv17_graph_ctx_regs[i] == reg)
 			return i;
 	}
-	NV_ERROR(dev, "unknow offset nv17_ctx_regs %d\n", reg);
+	nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg);
 	return -1;
 }
 
-static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
-				       uint32_t inst)
+static void
+nv10_graph_load_dma_vtxbuf(struct nv10_graph_chan *chan, int chid, u32 inst)
 {
-	struct drm_device *dev = chan->dev;
-	uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
-	uint32_t ctx_user, ctx_switch[5];
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
+	u32 ctx_user, ctx_switch[5];
 	int i, subchan = -1;
 
 	/* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
@@ -671,7 +879,7 @@
 
 	/* Look for a celsius object */
 	for (i = 0; i < 8; i++) {
-		int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
+		int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
 
 		if (class == 0x56 || class == 0x96 || class == 0x99) {
 			subchan = i;
@@ -683,168 +891,158 @@
 		return;
 
 	/* Save the current ctx object */
-	ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
+	ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER);
 	for (i = 0; i < 5; i++)
-		ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i));
+		ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i));
 
 	/* Save the FIFO state */
-	st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
-	st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL);
-	st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH);
-	fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR);
+	st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2);
+	st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL);
+	st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH);
+	fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR);
 
 	for (i = 0; i < ARRAY_SIZE(fifo); i++)
-		fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i);
+		fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i);
 
 	/* Switch to the celsius subchannel */
 	for (i = 0; i < 5; i++)
-		nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i),
-			nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i)));
-	nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
+		nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i),
+			nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i)));
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
 
 	/* Inject NV10TCL_DMA_VTXBUF */
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2,
-		0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
-	nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2,
+		0x2c000000 | chid << 20 | subchan << 16 | 0x18c);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
+	nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
 
 	/* Restore the FIFO state */
 	for (i = 0; i < ARRAY_SIZE(fifo); i++)
-		nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]);
+		nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]);
 
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
 
 	/* Restore the current ctx object */
 	for (i = 0; i < 5; i++)
-		nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
+		nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
+	nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user);
 }
 
 static int
-nv10_graph_load_context(struct nouveau_channel *chan)
+nv10_graph_load_context(struct nv10_graph_chan *chan, int chid)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	uint32_t tmp;
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+	u32 inst;
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
-		nv_wr32(dev, nv10_graph_ctx_regs[i], pgraph_ctx->nv10[i]);
-	if (dev_priv->chipset >= 0x17) {
+		nv_wr32(priv, nv10_graph_ctx_regs[i], chan->nv10[i]);
+
+	if (nv_device(priv)->chipset >= 0x17) {
 		for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
-			nv_wr32(dev, nv17_graph_ctx_regs[i],
-						pgraph_ctx->nv17[i]);
+			nv_wr32(priv, nv17_graph_ctx_regs[i], chan->nv17[i]);
 	}
 
 	nv10_graph_load_pipe(chan);
-	nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1)
-					  & 0xffff));
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-	tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, (tmp & 0xffffff) | chan->id << 24);
-	tmp = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, tmp & 0xcfffffff);
+	inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff;
+	nv10_graph_load_dma_vtxbuf(chan, chid, inst);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+	nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000);
 	return 0;
 }
 
 static int
-nv10_graph_unload_context(struct drm_device *dev)
+nv10_graph_unload_context(struct nv10_graph_chan *chan)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	struct graph_state *ctx;
-	uint32_t tmp;
+	struct nv10_graph_priv *priv = nv10_graph_priv(chan);
 	int i;
 
-	chan = nv10_graph_channel(dev);
-	if (!chan)
-		return 0;
-	ctx = chan->engctx[NVOBJ_ENGINE_GR];
-
 	for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
-		ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]);
+		chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]);
 
-	if (dev_priv->chipset >= 0x17) {
+	if (nv_device(priv)->chipset >= 0x17) {
 		for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
-			ctx->nv17[i] = nv_rd32(dev, nv17_graph_ctx_regs[i]);
+			chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]);
 	}
 
 	nv10_graph_save_pipe(chan);
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-	tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 31 << 24;
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
 	return 0;
 }
 
 static void
-nv10_graph_context_switch(struct drm_device *dev)
+nv10_graph_context_switch(struct nv10_graph_priv *priv)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan = NULL;
+	struct nv10_graph_chan *prev = NULL;
+	struct nv10_graph_chan *next = NULL;
+	unsigned long flags;
 	int chid;
 
-	nouveau_wait_for_idle(dev);
+	spin_lock_irqsave(&priv->lock, flags);
+	nv04_graph_idle(priv);
 
 	/* If previous context is valid, we need to save it */
-	nv10_graph_unload_context(dev);
+	prev = nv10_graph_channel(priv);
+	if (prev)
+		nv10_graph_unload_context(prev);
 
-	/* Load context for next channel */
-	chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
-	chan = dev_priv->channels.ptr[chid];
-	if (chan && chan->engctx[NVOBJ_ENGINE_GR])
-		nv10_graph_load_context(chan);
+	/* load context for next channel */
+	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
+	next = priv->chan[chid];
+	if (next)
+		nv10_graph_load_context(next, chid);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 #define NV_WRITE_CTX(reg, val) do { \
-	int offset = nv10_graph_ctx_regs_find_offset(dev, reg); \
+	int offset = nv10_graph_ctx_regs_find_offset(priv, reg); \
 	if (offset > 0) \
-		pgraph_ctx->nv10[offset] = val; \
+		chan->nv10[offset] = val; \
 	} while (0)
 
 #define NV17_WRITE_CTX(reg, val) do { \
-	int offset = nv17_graph_ctx_regs_find_offset(dev, reg); \
+	int offset = nv17_graph_ctx_regs_find_offset(priv, reg); \
 	if (offset > 0) \
-		pgraph_ctx->nv17[offset] = val; \
+		chan->nv17[offset] = val; \
 	} while (0)
 
-struct nouveau_channel *
-nv10_graph_channel(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int chid = 31;
-
-	if (nv_rd32(dev, NV10_PGRAPH_CTX_CONTROL) & 0x00010000)
-		chid = nv_rd32(dev, NV10_PGRAPH_CTX_USER) >> 24;
-
-	if (chid >= 31)
-		return NULL;
-
-	return dev_priv->channels.ptr[chid];
-}
-
 static int
-nv10_graph_context_new(struct nouveau_channel *chan, int engine)
+nv10_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct graph_state *pgraph_ctx;
+	struct nouveau_fifo_chan *fifo = (void *)parent;
+	struct nv10_graph_priv *priv = (void *)engine;
+	struct nv10_graph_chan *chan;
+	unsigned long flags;
+	int ret;
 
-	NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id);
+	ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
 
-	pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
-	if (pgraph_ctx == NULL)
-		return -ENOMEM;
-	chan->engctx[engine] = pgraph_ctx;
+	spin_lock_irqsave(&priv->lock, flags);
+	if (priv->chan[fifo->chid]) {
+		*pobject = nv_object(priv->chan[fifo->chid]);
+		atomic_inc(&(*pobject)->refcount);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		nouveau_object_destroy(&chan->base);
+		return 1;
+	}
 
 	NV_WRITE_CTX(0x00400e88, 0x08000000);
 	NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
@@ -853,212 +1051,91 @@
 	NV_WRITE_CTX(0x00400e14, 0x00001000);
 	NV_WRITE_CTX(0x00400e30, 0x00080008);
 	NV_WRITE_CTX(0x00400e34, 0x00080008);
-	if (dev_priv->chipset >= 0x17) {
+	if (nv_device(priv)->chipset >= 0x17) {
 		/* is it really needed ??? */
 		NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
-					nv_rd32(dev, NV10_PGRAPH_DEBUG_4));
-		NV17_WRITE_CTX(0x004006b0, nv_rd32(dev, 0x004006b0));
+					nv_rd32(priv, NV10_PGRAPH_DEBUG_4));
+		NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0));
 		NV17_WRITE_CTX(0x00400eac, 0x0fff0000);
 		NV17_WRITE_CTX(0x00400eb0, 0x0fff0000);
 		NV17_WRITE_CTX(0x00400ec0, 0x00000080);
 		NV17_WRITE_CTX(0x00400ed0, 0x00000080);
 	}
-	NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->id << 24);
+	NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24);
 
 	nv10_graph_create_pipe(chan);
+
+	priv->chan[fifo->chid] = chan;
+	chan->chid = fifo->chid;
+	spin_unlock_irqrestore(&priv->lock, flags);
 	return 0;
 }
 
 static void
-nv10_graph_context_del(struct nouveau_channel *chan, int engine)
+nv10_graph_context_dtor(struct nouveau_object *object)
 {
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct graph_state *pgraph_ctx = chan->engctx[engine];
+	struct nv10_graph_priv *priv = (void *)object->engine;
+	struct nv10_graph_chan *chan = (void *)object;
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->chan[chan->chid] = NULL;
+	spin_unlock_irqrestore(&priv->lock, flags);
 
-	/* Unload the context if it's the currently active one */
-	if (nv10_graph_channel(dev) == chan)
-		nv10_graph_unload_context(dev);
-
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* Free the context resources */
-	chan->engctx[engine] = NULL;
-	kfree(pgraph_ctx);
+	nouveau_object_destroy(&chan->base);
 }
 
+static int
+nv10_graph_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv10_graph_priv *priv = (void *)object->engine;
+	struct nv10_graph_chan *chan = (void *)object;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+	if (nv10_graph_channel(priv) == chan)
+		nv10_graph_unload_context(chan);
+	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return nouveau_object_fini(&chan->base, suspend);
+}
+
+static struct nouveau_oclass
+nv10_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x10),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv10_graph_context_ctor,
+		.dtor = nv10_graph_context_dtor,
+		.init = nouveau_object_init,
+		.fini = nv10_graph_context_fini,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
 static void
-nv10_graph_set_tile_region(struct drm_device *dev, int i)
+nv10_graph_tile_prog(struct nouveau_engine *engine, int i)
 {
-	struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
-	nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), tile->limit);
-	nv_wr32(dev, NV10_PGRAPH_TSIZE(i), tile->pitch);
-	nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
+	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
+	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
+	struct nv10_graph_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_graph_idle(priv);
+
+	nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit);
+	nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch);
+	nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr);
+
+	pfifo->start(pfifo, &flags);
 }
 
-static int
-nv10_graph_init(struct drm_device *dev, int engine)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	u32 tmp;
-	int i;
-
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
-			~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
-			 NV_PMC_ENABLE_PGRAPH);
-
-	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x00118700);
-	/* nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0x55DE0830 |
-				      (1<<29) |
-				      (1<<31));
-	if (dev_priv->chipset >= 0x17) {
-		nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x1f000000);
-		nv_wr32(dev, 0x400a10, 0x3ff3fb6);
-		nv_wr32(dev, 0x400838, 0x2f8684);
-		nv_wr32(dev, 0x40083c, 0x115f3f);
-		nv_wr32(dev, 0x004006b0, 0x40000020);
-	} else
-		nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
-
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
-		nv10_graph_set_tile_region(dev, i);
-
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF);
-
-	tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 31 << 24;
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
-
-	return 0;
-}
-
-static int
-nv10_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-		return -EBUSY;
-	}
-	nv10_graph_unload_context(dev);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-	return 0;
-}
-
-static int
-nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
-			   u32 class, u32 mthd, u32 data)
-{
-	struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR];
-	struct drm_device *dev = chan->dev;
-	struct pipe_state *pipe = &ctx->pipe_state;
-	uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
-	uint32_t xfmode0, xfmode1;
-	int i;
-
-	ctx->lma_window[(mthd - 0x1638) / 4] = data;
-
-	if (mthd != 0x1644)
-		return 0;
-
-	nouveau_wait_for_idle(dev);
-
-	PIPE_SAVE(dev, pipe_0x0040, 0x0040);
-	PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
-
-	PIPE_RESTORE(dev, ctx->lma_window, 0x6790);
-
-	nouveau_wait_for_idle(dev);
-
-	xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0);
-	xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1);
-
-	PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
-	PIPE_SAVE(dev, pipe_0x64c0, 0x64c0);
-	PIPE_SAVE(dev, pipe_0x6ab0, 0x6ab0);
-	PIPE_SAVE(dev, pipe_0x6a80, 0x6a80);
-
-	nouveau_wait_for_idle(dev);
-
-	nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
-	for (i = 0; i < 4; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
-	for (i = 0; i < 3; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
-	for (i = 0; i < 3; i++)
-		nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
-
-	PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
-
-	nouveau_wait_for_idle(dev);
-
-	PIPE_RESTORE(dev, pipe_0x0040, 0x0040);
-
-	nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
-	nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
-
-	PIPE_RESTORE(dev, pipe_0x64c0, 0x64c0);
-	PIPE_RESTORE(dev, pipe_0x6ab0, 0x6ab0);
-	PIPE_RESTORE(dev, pipe_0x6a80, 0x6a80);
-	PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
-
-	nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
-	nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-	nouveau_wait_for_idle(dev);
-
-	return 0;
-}
-
-static int
-nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
-			   u32 class, u32 mthd, u32 data)
-{
-	struct drm_device *dev = chan->dev;
-
-	nouveau_wait_for_idle(dev);
-
-	nv_wr32(dev, NV10_PGRAPH_DEBUG_4,
-		nv_rd32(dev, NV10_PGRAPH_DEBUG_4) | 0x1 << 8);
-	nv_wr32(dev, 0x004006b0,
-		nv_rd32(dev, 0x004006b0) | 0x8 << 24);
-
-	return 0;
-}
-
-struct nouveau_bitfield nv10_graph_intr[] = {
+struct nouveau_bitfield nv10_graph_intr_name[] = {
 	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
 	{ NV_PGRAPH_INTR_ERROR,  "ERROR"  },
 	{}
@@ -1073,115 +1150,165 @@
 };
 
 static void
-nv10_graph_isr(struct drm_device *dev)
+nv10_graph_intr(struct nouveau_subdev *subdev)
 {
-	u32 stat;
+	struct nv10_graph_priv *priv = (void *)subdev;
+	struct nv10_graph_chan *chan = NULL;
+	struct nouveau_namedb *namedb = NULL;
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x01f00000) >> 20;
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+	u32 show = stat;
+	unsigned long flags;
 
-	while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-		u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-		u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 chid = (addr & 0x01f00000) >> 20;
-		u32 subc = (addr & 0x00070000) >> 16;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff;
-		u32 show = stat;
+	spin_lock_irqsave(&priv->lock, flags);
+	chan = priv->chan[chid];
+	if (chan)
+		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+	spin_unlock_irqrestore(&priv->lock, flags);
 
-		if (stat & NV_PGRAPH_INTR_ERROR) {
-			if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-				if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-					show &= ~NV_PGRAPH_INTR_ERROR;
-			}
-		}
-
-		if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-			nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-			stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-			show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-			nv10_graph_context_switch(dev);
-		}
-
-		nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-		nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-		if (show && nouveau_ratelimit()) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv10_graph_intr, show);
-			printk(" nsource:");
-			nouveau_bitfield_print(nv04_graph_nsource, nsource);
-			printk(" nstatus:");
-			nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-				     "mthd 0x%04x data 0x%08x\n",
-				chid, subc, class, mthd, data);
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+			handle = nouveau_namedb_get_class(namedb, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
 		}
 	}
+
+	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+		nv10_graph_context_switch(priv);
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_error(priv, "");
+		nouveau_bitfield_print(nv10_graph_intr_name, show);
+		printk(" nsource:");
+		nouveau_bitfield_print(nv04_graph_nsource, nsource);
+		printk(" nstatus:");
+		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+		printk("\n");
+		nv_error(priv, "ch %d/%d class 0x%04x "
+			       "mthd 0x%04x data 0x%08x\n",
+			 chid, subc, class, mthd, data);
+	}
+
+	nouveau_namedb_put(handle);
+}
+
+static int
+nv10_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
+{
+	struct nv10_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv10_graph_intr;
+	nv_engine(priv)->cclass = &nv10_graph_cclass;
+
+	if (nv_device(priv)->chipset <= 0x10)
+		nv_engine(priv)->sclass = nv10_graph_sclass;
+	else
+	if (nv_device(priv)->chipset <  0x17 ||
+	    nv_device(priv)->chipset == 0x1a)
+		nv_engine(priv)->sclass = nv15_graph_sclass;
+	else
+		nv_engine(priv)->sclass = nv17_graph_sclass;
+
+	nv_engine(priv)->tile_prog = nv10_graph_tile_prog;
+	spin_lock_init(&priv->lock);
+	return 0;
 }
 
 static void
-nv10_graph_destroy(struct drm_device *dev, int engine)
+nv10_graph_dtor(struct nouveau_object *object)
 {
-	struct nv10_graph_engine *pgraph = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 12);
-	kfree(pgraph);
+	struct nv10_graph_priv *priv = (void *)object;
+	nouveau_graph_destroy(&priv->base);
 }
 
-int
-nv10_graph_create(struct drm_device *dev)
+static int
+nv10_graph_init(struct nouveau_object *object)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv10_graph_engine *pgraph;
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	struct nv10_graph_priv *priv = (void *)engine;
+	int ret, i;
 
-	pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
 
-	pgraph->base.destroy = nv10_graph_destroy;
-	pgraph->base.init = nv10_graph_init;
-	pgraph->base.fini = nv10_graph_fini;
-	pgraph->base.context_new = nv10_graph_context_new;
-	pgraph->base.context_del = nv10_graph_context_del;
-	pgraph->base.object_new = nv04_graph_object_new;
-	pgraph->base.set_tile_region = nv10_graph_set_tile_region;
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	nouveau_irq_register(dev, 12, nv10_graph_isr);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+	/* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
 
-	NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-	NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-	NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-	NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
-	NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-	NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-	NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-	NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-	NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-	NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-	NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-	NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-	NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-	NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
-	NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
-	NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
-	NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
-
-	/* celcius */
-	if (dev_priv->chipset <= 0x10) {
-		NVOBJ_CLASS(dev, 0x0056, GR);
-	} else
-	if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
-		NVOBJ_CLASS(dev, 0x0096, GR);
+	if (nv_device(priv)->chipset >= 0x17) {
+		nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000);
+		nv_wr32(priv, 0x400a10, 0x03ff3fb6);
+		nv_wr32(priv, 0x400838, 0x002f8684);
+		nv_wr32(priv, 0x40083c, 0x00115f3f);
+		nv_wr32(priv, 0x4006b0, 0x40000020);
 	} else {
-		NVOBJ_CLASS(dev, 0x0099, GR);
-		NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
-		NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
-		NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
-		NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
-		NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+		nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
 	}
 
+	/* Turn all the tiling regions off. */
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
+	nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF);
+
+	nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
 	return 0;
 }
+
+static int
+nv10_graph_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv10_graph_priv *priv = (void *)object;
+	return nouveau_graph_fini(&priv->base, suspend);
+}
+
+struct nouveau_oclass
+nv10_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x10),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv10_graph_ctor,
+		.dtor = nv10_graph_dtor,
+		.init = nv10_graph_init,
+		.fini = nv10_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
index 0d874b8b..61faef9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
@@ -1,836 +1,378 @@
-#include "drmP.h"
-#include "drm.h"
-#include "nouveau_drv.h"
-#include <nouveau_drm.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/handle.h>
+#include <core/enum.h>
 
-/*
- * NV20
- * -----
- * There are 3 families :
- * NV20 is 0x10de:0x020*
- * NV25/28 is 0x10de:0x025* / 0x10de:0x028*
- * NV2A is 0x10de:0x02A0
- *
- * NV30
- * -----
- * There are 3 families :
- * NV30/31 is 0x10de:0x030* / 0x10de:0x031*
- * NV34 is 0x10de:0x032*
- * NV35/36 is 0x10de:0x033* / 0x10de:0x034*
- *
- * Not seen in the wild, no dumps (probably NV35) :
- * NV37 is 0x10de:0x00fc, 0x10de:0x00fd
- * NV38 is 0x10de:0x0333, 0x10de:0x00fe
- *
- */
+#include <subdev/timer.h>
+#include <subdev/fb.h>
 
-struct nv20_graph_engine {
-	struct nouveau_exec_engine base;
-	struct nouveau_gpuobj *ctxtab;
-	void (*grctx_init)(struct nouveau_gpuobj *);
-	u32 grctx_size;
-	u32 grctx_user;
+#include <engine/graph.h>
+#include <engine/fifo.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv20_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
+	{ 0x0097, &nv04_graph_ofuncs, NULL }, /* kelvin */
+	{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{},
 };
 
-#define NV20_GRCTX_SIZE (3580*4)
-#define NV25_GRCTX_SIZE (3529*4)
-#define NV2A_GRCTX_SIZE (3500*4)
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
 
-#define NV30_31_GRCTX_SIZE (24392)
-#define NV34_GRCTX_SIZE    (18140)
-#define NV35_36_GRCTX_SIZE (22396)
-
-int
-nv20_graph_unload_context(struct drm_device *dev)
+static int
+nv20_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
 {
-	struct nouveau_channel *chan;
-	struct nouveau_gpuobj *grctx;
-	u32 tmp;
+	struct nv20_graph_chan *chan;
+	int ret, i;
 
-	chan = nv10_graph_channel(dev);
-	if (!chan)
-		return 0;
-	grctx = chan->engctx[NVOBJ_ENGINE_GR];
-
-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->addr >> 4);
-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
-		     NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
-
-	nouveau_wait_for_idle(dev);
-
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-	tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-	tmp |= 31 << 24;
-	nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
-	return 0;
-}
-
-static void
-nv20_graph_rdi(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int i, writecount = 32;
-	uint32_t rdi_index = 0x2c80000;
-
-	if (dev_priv->chipset == 0x20) {
-		rdi_index = 0x3d0000;
-		writecount = 15;
-	}
-
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
-	for (i = 0; i < writecount; i++)
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
-
-	nouveau_wait_for_idle(dev);
-}
-
-static void
-nv20_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x033c, 0xffff0000);
-	nv_wo32(ctx, 0x03a0, 0x0fff0000);
-	nv_wo32(ctx, 0x03a4, 0x0fff0000);
-	nv_wo32(ctx, 0x047c, 0x00000101);
-	nv_wo32(ctx, 0x0490, 0x00000111);
-	nv_wo32(ctx, 0x04a8, 0x44400000);
-	for (i = 0x04d4; i <= 0x04e0; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x04f4; i <= 0x0500; i += 4)
-		nv_wo32(ctx, i, 0x00080000);
-	for (i = 0x050c; i <= 0x0518; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x051c; i <= 0x0528; i += 4)
-		nv_wo32(ctx, i, 0x000105b8);
-	for (i = 0x052c; i <= 0x0538; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	for (i = 0x055c; i <= 0x0598; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x05a4, 0x4b7fffff);
-	nv_wo32(ctx, 0x05fc, 0x00000001);
-	nv_wo32(ctx, 0x0604, 0x00004000);
-	nv_wo32(ctx, 0x0610, 0x00000001);
-	nv_wo32(ctx, 0x0618, 0x00040000);
-	nv_wo32(ctx, 0x061c, 0x00010000);
-	for (i = 0x1c1c; i <= 0x248c; i += 16) {
-		nv_wo32(ctx, (i + 0), 0x10700ff9);
-		nv_wo32(ctx, (i + 4), 0x0436086c);
-		nv_wo32(ctx, (i + 8), 0x000c001b);
-	}
-	nv_wo32(ctx, 0x281c, 0x3f800000);
-	nv_wo32(ctx, 0x2830, 0x3f800000);
-	nv_wo32(ctx, 0x285c, 0x40000000);
-	nv_wo32(ctx, 0x2860, 0x3f800000);
-	nv_wo32(ctx, 0x2864, 0x3f000000);
-	nv_wo32(ctx, 0x286c, 0x40000000);
-	nv_wo32(ctx, 0x2870, 0x3f800000);
-	nv_wo32(ctx, 0x2878, 0xbf800000);
-	nv_wo32(ctx, 0x2880, 0xbf800000);
-	nv_wo32(ctx, 0x34a4, 0x000fe000);
-	nv_wo32(ctx, 0x3530, 0x000003f8);
-	nv_wo32(ctx, 0x3540, 0x002fe000);
-	for (i = 0x355c; i <= 0x3578; i += 4)
-		nv_wo32(ctx, i, 0x001c527c);
-}
-
-static void
-nv25_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x035c, 0xffff0000);
-	nv_wo32(ctx, 0x03c0, 0x0fff0000);
-	nv_wo32(ctx, 0x03c4, 0x0fff0000);
-	nv_wo32(ctx, 0x049c, 0x00000101);
-	nv_wo32(ctx, 0x04b0, 0x00000111);
-	nv_wo32(ctx, 0x04c8, 0x00000080);
-	nv_wo32(ctx, 0x04cc, 0xffff0000);
-	nv_wo32(ctx, 0x04d0, 0x00000001);
-	nv_wo32(ctx, 0x04e4, 0x44400000);
-	nv_wo32(ctx, 0x04fc, 0x4b800000);
-	for (i = 0x0510; i <= 0x051c; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x0530; i <= 0x053c; i += 4)
-		nv_wo32(ctx, i, 0x00080000);
-	for (i = 0x0548; i <= 0x0554; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x0558; i <= 0x0564; i += 4)
-		nv_wo32(ctx, i, 0x000105b8);
-	for (i = 0x0568; i <= 0x0574; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	for (i = 0x0598; i <= 0x05d4; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x05e0, 0x4b7fffff);
-	nv_wo32(ctx, 0x0620, 0x00000080);
-	nv_wo32(ctx, 0x0624, 0x30201000);
-	nv_wo32(ctx, 0x0628, 0x70605040);
-	nv_wo32(ctx, 0x062c, 0xb0a09080);
-	nv_wo32(ctx, 0x0630, 0xf0e0d0c0);
-	nv_wo32(ctx, 0x0664, 0x00000001);
-	nv_wo32(ctx, 0x066c, 0x00004000);
-	nv_wo32(ctx, 0x0678, 0x00000001);
-	nv_wo32(ctx, 0x0680, 0x00040000);
-	nv_wo32(ctx, 0x0684, 0x00010000);
-	for (i = 0x1b04; i <= 0x2374; i += 16) {
-		nv_wo32(ctx, (i + 0), 0x10700ff9);
-		nv_wo32(ctx, (i + 4), 0x0436086c);
-		nv_wo32(ctx, (i + 8), 0x000c001b);
-	}
-	nv_wo32(ctx, 0x2704, 0x3f800000);
-	nv_wo32(ctx, 0x2718, 0x3f800000);
-	nv_wo32(ctx, 0x2744, 0x40000000);
-	nv_wo32(ctx, 0x2748, 0x3f800000);
-	nv_wo32(ctx, 0x274c, 0x3f000000);
-	nv_wo32(ctx, 0x2754, 0x40000000);
-	nv_wo32(ctx, 0x2758, 0x3f800000);
-	nv_wo32(ctx, 0x2760, 0xbf800000);
-	nv_wo32(ctx, 0x2768, 0xbf800000);
-	nv_wo32(ctx, 0x308c, 0x000fe000);
-	nv_wo32(ctx, 0x3108, 0x000003f8);
-	nv_wo32(ctx, 0x3468, 0x002fe000);
-	for (i = 0x3484; i <= 0x34a0; i += 4)
-		nv_wo32(ctx, i, 0x001c527c);
-}
-
-static void
-nv2a_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x033c, 0xffff0000);
-	nv_wo32(ctx, 0x03a0, 0x0fff0000);
-	nv_wo32(ctx, 0x03a4, 0x0fff0000);
-	nv_wo32(ctx, 0x047c, 0x00000101);
-	nv_wo32(ctx, 0x0490, 0x00000111);
-	nv_wo32(ctx, 0x04a8, 0x44400000);
-	for (i = 0x04d4; i <= 0x04e0; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x04f4; i <= 0x0500; i += 4)
-		nv_wo32(ctx, i, 0x00080000);
-	for (i = 0x050c; i <= 0x0518; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x051c; i <= 0x0528; i += 4)
-		nv_wo32(ctx, i, 0x000105b8);
-	for (i = 0x052c; i <= 0x0538; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	for (i = 0x055c; i <= 0x0598; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x05a4, 0x4b7fffff);
-	nv_wo32(ctx, 0x05fc, 0x00000001);
-	nv_wo32(ctx, 0x0604, 0x00004000);
-	nv_wo32(ctx, 0x0610, 0x00000001);
-	nv_wo32(ctx, 0x0618, 0x00040000);
-	nv_wo32(ctx, 0x061c, 0x00010000);
-	for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
-		nv_wo32(ctx, (i + 0), 0x10700ff9);
-		nv_wo32(ctx, (i + 4), 0x0436086c);
-		nv_wo32(ctx, (i + 8), 0x000c001b);
-	}
-	nv_wo32(ctx, 0x269c, 0x3f800000);
-	nv_wo32(ctx, 0x26b0, 0x3f800000);
-	nv_wo32(ctx, 0x26dc, 0x40000000);
-	nv_wo32(ctx, 0x26e0, 0x3f800000);
-	nv_wo32(ctx, 0x26e4, 0x3f000000);
-	nv_wo32(ctx, 0x26ec, 0x40000000);
-	nv_wo32(ctx, 0x26f0, 0x3f800000);
-	nv_wo32(ctx, 0x26f8, 0xbf800000);
-	nv_wo32(ctx, 0x2700, 0xbf800000);
-	nv_wo32(ctx, 0x3024, 0x000fe000);
-	nv_wo32(ctx, 0x30a0, 0x000003f8);
-	nv_wo32(ctx, 0x33fc, 0x002fe000);
-	for (i = 0x341c; i <= 0x3438; i += 4)
-		nv_wo32(ctx, i, 0x001c527c);
-}
-
-static void
-nv30_31_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x0410, 0x00000101);
-	nv_wo32(ctx, 0x0424, 0x00000111);
-	nv_wo32(ctx, 0x0428, 0x00000060);
-	nv_wo32(ctx, 0x0444, 0x00000080);
-	nv_wo32(ctx, 0x0448, 0xffff0000);
-	nv_wo32(ctx, 0x044c, 0x00000001);
-	nv_wo32(ctx, 0x0460, 0x44400000);
-	nv_wo32(ctx, 0x048c, 0xffff0000);
-	for (i = 0x04e0; i < 0x04e8; i += 4)
-		nv_wo32(ctx, i, 0x0fff0000);
-	nv_wo32(ctx, 0x04ec, 0x00011100);
-	for (i = 0x0508; i < 0x0548; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x0550, 0x4b7fffff);
-	nv_wo32(ctx, 0x058c, 0x00000080);
-	nv_wo32(ctx, 0x0590, 0x30201000);
-	nv_wo32(ctx, 0x0594, 0x70605040);
-	nv_wo32(ctx, 0x0598, 0xb8a89888);
-	nv_wo32(ctx, 0x059c, 0xf8e8d8c8);
-	nv_wo32(ctx, 0x05b0, 0xb0000000);
-	for (i = 0x0600; i < 0x0640; i += 4)
-		nv_wo32(ctx, i, 0x00010588);
-	for (i = 0x0640; i < 0x0680; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x06c0; i < 0x0700; i += 4)
-		nv_wo32(ctx, i, 0x0008aae4);
-	for (i = 0x0700; i < 0x0740; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x0740; i < 0x0780; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	nv_wo32(ctx, 0x085c, 0x00040000);
-	nv_wo32(ctx, 0x0860, 0x00010000);
-	for (i = 0x0864; i < 0x0874; i += 4)
-		nv_wo32(ctx, i, 0x00040004);
-	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
-		nv_wo32(ctx, i + 0, 0x10700ff9);
-		nv_wo32(ctx, i + 1, 0x0436086c);
-		nv_wo32(ctx, i + 2, 0x000c001b);
-	}
-	for (i = 0x30b8; i < 0x30c8; i += 4)
-		nv_wo32(ctx, i, 0x0000ffff);
-	nv_wo32(ctx, 0x344c, 0x3f800000);
-	nv_wo32(ctx, 0x3808, 0x3f800000);
-	nv_wo32(ctx, 0x381c, 0x3f800000);
-	nv_wo32(ctx, 0x3848, 0x40000000);
-	nv_wo32(ctx, 0x384c, 0x3f800000);
-	nv_wo32(ctx, 0x3850, 0x3f000000);
-	nv_wo32(ctx, 0x3858, 0x40000000);
-	nv_wo32(ctx, 0x385c, 0x3f800000);
-	nv_wo32(ctx, 0x3864, 0xbf800000);
-	nv_wo32(ctx, 0x386c, 0xbf800000);
-}
-
-static void
-nv34_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x040c, 0x01000101);
-	nv_wo32(ctx, 0x0420, 0x00000111);
-	nv_wo32(ctx, 0x0424, 0x00000060);
-	nv_wo32(ctx, 0x0440, 0x00000080);
-	nv_wo32(ctx, 0x0444, 0xffff0000);
-	nv_wo32(ctx, 0x0448, 0x00000001);
-	nv_wo32(ctx, 0x045c, 0x44400000);
-	nv_wo32(ctx, 0x0480, 0xffff0000);
-	for (i = 0x04d4; i < 0x04dc; i += 4)
-		nv_wo32(ctx, i, 0x0fff0000);
-	nv_wo32(ctx, 0x04e0, 0x00011100);
-	for (i = 0x04fc; i < 0x053c; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x0544, 0x4b7fffff);
-	nv_wo32(ctx, 0x057c, 0x00000080);
-	nv_wo32(ctx, 0x0580, 0x30201000);
-	nv_wo32(ctx, 0x0584, 0x70605040);
-	nv_wo32(ctx, 0x0588, 0xb8a89888);
-	nv_wo32(ctx, 0x058c, 0xf8e8d8c8);
-	nv_wo32(ctx, 0x05a0, 0xb0000000);
-	for (i = 0x05f0; i < 0x0630; i += 4)
-		nv_wo32(ctx, i, 0x00010588);
-	for (i = 0x0630; i < 0x0670; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x06b0; i < 0x06f0; i += 4)
-		nv_wo32(ctx, i, 0x0008aae4);
-	for (i = 0x06f0; i < 0x0730; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x0730; i < 0x0770; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	nv_wo32(ctx, 0x0850, 0x00040000);
-	nv_wo32(ctx, 0x0854, 0x00010000);
-	for (i = 0x0858; i < 0x0868; i += 4)
-		nv_wo32(ctx, i, 0x00040004);
-	for (i = 0x15ac; i <= 0x271c ; i += 16) {
-		nv_wo32(ctx, i + 0, 0x10700ff9);
-		nv_wo32(ctx, i + 1, 0x0436086c);
-		nv_wo32(ctx, i + 2, 0x000c001b);
-	}
-	for (i = 0x274c; i < 0x275c; i += 4)
-		nv_wo32(ctx, i, 0x0000ffff);
-	nv_wo32(ctx, 0x2ae0, 0x3f800000);
-	nv_wo32(ctx, 0x2e9c, 0x3f800000);
-	nv_wo32(ctx, 0x2eb0, 0x3f800000);
-	nv_wo32(ctx, 0x2edc, 0x40000000);
-	nv_wo32(ctx, 0x2ee0, 0x3f800000);
-	nv_wo32(ctx, 0x2ee4, 0x3f000000);
-	nv_wo32(ctx, 0x2eec, 0x40000000);
-	nv_wo32(ctx, 0x2ef0, 0x3f800000);
-	nv_wo32(ctx, 0x2ef8, 0xbf800000);
-	nv_wo32(ctx, 0x2f00, 0xbf800000);
-}
-
-static void
-nv35_36_graph_context_init(struct nouveau_gpuobj *ctx)
-{
-	int i;
-
-	nv_wo32(ctx, 0x040c, 0x00000101);
-	nv_wo32(ctx, 0x0420, 0x00000111);
-	nv_wo32(ctx, 0x0424, 0x00000060);
-	nv_wo32(ctx, 0x0440, 0x00000080);
-	nv_wo32(ctx, 0x0444, 0xffff0000);
-	nv_wo32(ctx, 0x0448, 0x00000001);
-	nv_wo32(ctx, 0x045c, 0x44400000);
-	nv_wo32(ctx, 0x0488, 0xffff0000);
-	for (i = 0x04dc; i < 0x04e4; i += 4)
-		nv_wo32(ctx, i, 0x0fff0000);
-	nv_wo32(ctx, 0x04e8, 0x00011100);
-	for (i = 0x0504; i < 0x0544; i += 4)
-		nv_wo32(ctx, i, 0x07ff0000);
-	nv_wo32(ctx, 0x054c, 0x4b7fffff);
-	nv_wo32(ctx, 0x0588, 0x00000080);
-	nv_wo32(ctx, 0x058c, 0x30201000);
-	nv_wo32(ctx, 0x0590, 0x70605040);
-	nv_wo32(ctx, 0x0594, 0xb8a89888);
-	nv_wo32(ctx, 0x0598, 0xf8e8d8c8);
-	nv_wo32(ctx, 0x05ac, 0xb0000000);
-	for (i = 0x0604; i < 0x0644; i += 4)
-		nv_wo32(ctx, i, 0x00010588);
-	for (i = 0x0644; i < 0x0684; i += 4)
-		nv_wo32(ctx, i, 0x00030303);
-	for (i = 0x06c4; i < 0x0704; i += 4)
-		nv_wo32(ctx, i, 0x0008aae4);
-	for (i = 0x0704; i < 0x0744; i += 4)
-		nv_wo32(ctx, i, 0x01012000);
-	for (i = 0x0744; i < 0x0784; i += 4)
-		nv_wo32(ctx, i, 0x00080008);
-	nv_wo32(ctx, 0x0860, 0x00040000);
-	nv_wo32(ctx, 0x0864, 0x00010000);
-	for (i = 0x0868; i < 0x0878; i += 4)
-		nv_wo32(ctx, i, 0x00040004);
-	for (i = 0x1f1c; i <= 0x308c ; i += 16) {
-		nv_wo32(ctx, i + 0, 0x10700ff9);
-		nv_wo32(ctx, i + 4, 0x0436086c);
-		nv_wo32(ctx, i + 8, 0x000c001b);
-	}
-	for (i = 0x30bc; i < 0x30cc; i += 4)
-		nv_wo32(ctx, i, 0x0000ffff);
-	nv_wo32(ctx, 0x3450, 0x3f800000);
-	nv_wo32(ctx, 0x380c, 0x3f800000);
-	nv_wo32(ctx, 0x3820, 0x3f800000);
-	nv_wo32(ctx, 0x384c, 0x40000000);
-	nv_wo32(ctx, 0x3850, 0x3f800000);
-	nv_wo32(ctx, 0x3854, 0x3f000000);
-	nv_wo32(ctx, 0x385c, 0x40000000);
-	nv_wo32(ctx, 0x3860, 0x3f800000);
-	nv_wo32(ctx, 0x3868, 0xbf800000);
-	nv_wo32(ctx, 0x3870, 0xbf800000);
-}
-
-int
-nv20_graph_context_new(struct nouveau_channel *chan, int engine)
-{
-	struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
-	struct nouveau_gpuobj *grctx = NULL;
-	struct drm_device *dev = chan->dev;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &grctx);
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
+					   0x37f0, 16, NVOBJ_FLAG_ZERO_ALLOC,
+					   &chan);
+	*pobject = nv_object(chan);
 	if (ret)
 		return ret;
 
-	/* Initialise default context values */
-	pgraph->grctx_init(grctx);
+	chan->chid = nouveau_fifo_chan(parent)->chid;
 
-	/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
-	/* CTX_USER */
-	nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1);
+	nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x033c, 0xffff0000);
+	nv_wo32(chan, 0x03a0, 0x0fff0000);
+	nv_wo32(chan, 0x03a4, 0x0fff0000);
+	nv_wo32(chan, 0x047c, 0x00000101);
+	nv_wo32(chan, 0x0490, 0x00000111);
+	nv_wo32(chan, 0x04a8, 0x44400000);
+	for (i = 0x04d4; i <= 0x04e0; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x04f4; i <= 0x0500; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x050c; i <= 0x0518; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x051c; i <= 0x0528; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x052c; i <= 0x0538; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x055c; i <= 0x0598; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05a4, 0x4b7fffff);
+	nv_wo32(chan, 0x05fc, 0x00000001);
+	nv_wo32(chan, 0x0604, 0x00004000);
+	nv_wo32(chan, 0x0610, 0x00000001);
+	nv_wo32(chan, 0x0618, 0x00040000);
+	nv_wo32(chan, 0x061c, 0x00010000);
+	for (i = 0x1c1c; i <= 0x248c; i += 16) {
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x281c, 0x3f800000);
+	nv_wo32(chan, 0x2830, 0x3f800000);
+	nv_wo32(chan, 0x285c, 0x40000000);
+	nv_wo32(chan, 0x2860, 0x3f800000);
+	nv_wo32(chan, 0x2864, 0x3f000000);
+	nv_wo32(chan, 0x286c, 0x40000000);
+	nv_wo32(chan, 0x2870, 0x3f800000);
+	nv_wo32(chan, 0x2878, 0xbf800000);
+	nv_wo32(chan, 0x2880, 0xbf800000);
+	nv_wo32(chan, 0x34a4, 0x000fe000);
+	nv_wo32(chan, 0x3530, 0x000003f8);
+	nv_wo32(chan, 0x3540, 0x002fe000);
+	for (i = 0x355c; i <= 0x3578; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
 
-	nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->addr >> 4);
-	chan->engctx[engine] = grctx;
+int
+nv20_graph_context_init(struct nouveau_object *object)
+{
+	struct nv20_graph_priv *priv = (void *)object->engine;
+	struct nv20_graph_chan *chan = (void *)object;
+	int ret;
+
+	ret = nouveau_graph_context_init(&chan->base);
+	if (ret)
+		return ret;
+
+	nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4);
+	return 0;
+}
+
+int
+nv20_graph_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv20_graph_priv *priv = (void *)object->engine;
+	struct nv20_graph_chan *chan = (void *)object;
+	int chid = -1;
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
+	if (nv_rd32(priv, 0x400144) & 0x00010000)
+		chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24;
+	if (chan->chid == chid) {
+		nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4);
+		nv_wr32(priv, 0x400788, 0x00000002);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+		nv_wr32(priv, 0x400144, 0x10000000);
+		nv_mask(priv, 0x400148, 0xff000000, 0x1f000000);
+	}
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
+
+	nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000);
+	return nouveau_graph_context_fini(&chan->base, suspend);
+}
+
+static struct nouveau_oclass
+nv20_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x20),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv20_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+void
+nv20_graph_tile_prog(struct nouveau_engine *engine, int i)
+{
+	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
+	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
+	struct nv20_graph_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_graph_idle(priv);
+
+	nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+	nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+	nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit);
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch);
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr);
+
+	if (nv_device(engine)->card_type == NV_20) {
+		nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp);
+	}
+
+	pfifo->start(pfifo, &flags);
+}
+
+void
+nv20_graph_intr(struct nouveau_subdev *subdev)
+{
+	struct nv20_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 chid = (addr & 0x01f00000) >> 20;
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+	u32 inst = nv_ro32(priv->ctxtab, (chid * 4)) << 4;
+	u32 show = stat;
+
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+			handle = nouveau_engctx_lookup_class(engine, inst, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
+			nouveau_engctx_handle_put(handle);
+		}
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_info(priv, "");
+		nouveau_bitfield_print(nv10_graph_intr_name, show);
+		printk(" nsource:");
+		nouveau_bitfield_print(nv04_graph_nsource, nsource);
+		printk(" nstatus:");
+		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+		printk("\n");
+		nv_info(priv, "ch %d/%d class 0x%04x mthd 0x%04x data 0x%08x\n",
+			chid, subc, class, mthd, data);
+	}
+}
+
+static int
+nv20_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv20_graph_cclass;
+	nv_engine(priv)->sclass = nv20_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
 	return 0;
 }
 
 void
-nv20_graph_context_del(struct nouveau_channel *chan, int engine)
+nv20_graph_dtor(struct nouveau_object *object)
 {
-	struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
-	struct nouveau_gpuobj *grctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-
-	/* Unload the context if it's the currently active one */
-	if (nv10_graph_channel(dev) == chan)
-		nv20_graph_unload_context(dev);
-
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* Free the context resources */
-	nv_wo32(pgraph->ctxtab, chan->id * 4, 0);
-
-	nouveau_gpuobj_ref(NULL, &grctx);
-	chan->engctx[engine] = NULL;
-}
-
-static void
-nv20_graph_set_tile_region(struct drm_device *dev, int i)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
-
-	nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
-	nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
-	nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
-
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->limit);
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->pitch);
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->addr);
-
-	if (dev_priv->card_type == NV_20) {
-		nv_wr32(dev, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->zcomp);
-	}
+	struct nv20_graph_priv *priv = (void *)object;
+	nouveau_gpuobj_ref(NULL, &priv->ctxtab);
+	nouveau_graph_destroy(&priv->base);
 }
 
 int
-nv20_graph_init(struct drm_device *dev, int engine)
+nv20_graph_init(struct nouveau_object *object)
 {
-	struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t tmp, vramsz;
-	int i;
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nv20_graph_priv *priv = (void *)engine;
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	u32 tmp, vramsz;
+	int ret, i;
 
-	nv_wr32(dev, NV03_PMC_ENABLE,
-		nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE,
-		nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
 
-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->addr >> 4);
+	nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
 
-	nv20_graph_rdi(dev);
+	if (nv_device(priv)->chipset == 0x20) {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000);
+		for (i = 0; i < 15; i++)
+			nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+	} else {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000);
+		for (i = 0; i < 32; i++)
+			nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
+		nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+	}
 
-	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x00118700);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
-	nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
-	nv_wr32(dev, 0x40009C           , 0x00000040);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
+	nv_wr32(priv, 0x40009C           , 0x00000040);
 
-	if (dev_priv->chipset >= 0x25) {
-		nv_wr32(dev, 0x400890, 0x00a8cfff);
-		nv_wr32(dev, 0x400610, 0x304B1FB6);
-		nv_wr32(dev, 0x400B80, 0x1cbd3883);
-		nv_wr32(dev, 0x400B84, 0x44000000);
-		nv_wr32(dev, 0x400098, 0x40000080);
-		nv_wr32(dev, 0x400B88, 0x000000ff);
+	if (nv_device(priv)->chipset >= 0x25) {
+		nv_wr32(priv, 0x400890, 0x00a8cfff);
+		nv_wr32(priv, 0x400610, 0x304B1FB6);
+		nv_wr32(priv, 0x400B80, 0x1cbd3883);
+		nv_wr32(priv, 0x400B84, 0x44000000);
+		nv_wr32(priv, 0x400098, 0x40000080);
+		nv_wr32(priv, 0x400B88, 0x000000ff);
 
 	} else {
-		nv_wr32(dev, 0x400880, 0x0008c7df);
-		nv_wr32(dev, 0x400094, 0x00000005);
-		nv_wr32(dev, 0x400B80, 0x45eae20e);
-		nv_wr32(dev, 0x400B84, 0x24000000);
-		nv_wr32(dev, 0x400098, 0x00000040);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030);
+		nv_wr32(priv, 0x400880, 0x0008c7df);
+		nv_wr32(priv, 0x400094, 0x00000005);
+		nv_wr32(priv, 0x400B80, 0x45eae20e);
+		nv_wr32(priv, 0x400B84, 0x24000000);
+		nv_wr32(priv, 0x400098, 0x00000040);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
 	}
 
 	/* Turn all the tiling regions off. */
-	for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
-		nv20_graph_set_tile_region(dev, i);
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
 
-	nv_wr32(dev, 0x4009a0, nv_rd32(dev, 0x100324));
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA, nv_rd32(dev, 0x100324));
+	nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324));
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
 
-	tmp = nv_rd32(dev, NV10_PGRAPH_SURFACE) & 0x0007ff00;
-	nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp);
-	tmp = nv_rd32(dev, NV10_PGRAPH_SURFACE) | 0x00020100;
-	nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp);
+	tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00;
+	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
+	tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100;
+	nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
 
 	/* begin RAM config */
-	vramsz = pci_resource_len(dev->pdev, 0) - 1;
-	nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
-	nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA , nv_rd32(dev, NV04_PFB_CFG0));
-	nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
-	nv_wr32(dev, NV10_PGRAPH_RDI_DATA , nv_rd32(dev, NV04_PFB_CFG1));
-	nv_wr32(dev, 0x400820, 0);
-	nv_wr32(dev, 0x400824, 0);
-	nv_wr32(dev, 0x400864, vramsz - 1);
-	nv_wr32(dev, 0x400868, vramsz - 1);
+	vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
+	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200));
+	nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+	nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204));
+	nv_wr32(priv, 0x400820, 0);
+	nv_wr32(priv, 0x400824, 0);
+	nv_wr32(priv, 0x400864, vramsz - 1);
+	nv_wr32(priv, 0x400868, vramsz - 1);
 
 	/* interesting.. the below overwrites some of the tile setup above.. */
-	nv_wr32(dev, 0x400B20, 0x00000000);
-	nv_wr32(dev, 0x400B04, 0xFFFFFFFF);
+	nv_wr32(priv, 0x400B20, 0x00000000);
+	nv_wr32(priv, 0x400B04, 0xFFFFFFFF);
 
-	nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
-	nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
-	nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
-	nv_wr32(dev, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
-
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
+	nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
 	return 0;
 }
 
-int
-nv30_graph_init(struct drm_device *dev, int engine)
-{
-	struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int i;
-
-	nv_wr32(dev, NV03_PMC_ENABLE,
-		nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE,
-		nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
-
-	nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->addr >> 4);
-
-	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x401287c0);
-	nv_wr32(dev, 0x400890, 0x01b463ff);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
-	nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00008000);
-	nv_wr32(dev, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
-	nv_wr32(dev, 0x400B80, 0x1003d888);
-	nv_wr32(dev, 0x400B84, 0x0c000000);
-	nv_wr32(dev, 0x400098, 0x00000000);
-	nv_wr32(dev, 0x40009C, 0x0005ad00);
-	nv_wr32(dev, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
-	nv_wr32(dev, 0x4000a0, 0x00000000);
-	nv_wr32(dev, 0x4000a4, 0x00000008);
-	nv_wr32(dev, 0x4008a8, 0xb784a400);
-	nv_wr32(dev, 0x400ba0, 0x002f8685);
-	nv_wr32(dev, 0x400ba4, 0x00231f3f);
-	nv_wr32(dev, 0x4008a4, 0x40000020);
-
-	if (dev_priv->chipset == 0x34) {
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00200201);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000008);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000032);
-		nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
-		nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000002);
-	}
-
-	nv_wr32(dev, 0x4000c0, 0x00000016);
-
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
-		nv20_graph_set_tile_region(dev, i);
-
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-	nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
-	nv_wr32(dev, 0x0040075c             , 0x00000001);
-
-	/* begin RAM config */
-	/* vramsz = pci_resource_len(dev->pdev, 0) - 1; */
-	nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
-	nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
-	if (dev_priv->chipset != 0x34) {
-		nv_wr32(dev, 0x400750, 0x00EA0000);
-		nv_wr32(dev, 0x400754, nv_rd32(dev, NV04_PFB_CFG0));
-		nv_wr32(dev, 0x400750, 0x00EA0004);
-		nv_wr32(dev, 0x400754, nv_rd32(dev, NV04_PFB_CFG1));
-	}
-
-	return 0;
-}
-
-int
-nv20_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-	if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-		nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-		return -EBUSY;
-	}
-	nv20_graph_unload_context(dev);
-	nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-	return 0;
-}
-
-static void
-nv20_graph_isr(struct drm_device *dev)
-{
-	u32 stat;
-
-	while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-		u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-		u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 chid = (addr & 0x01f00000) >> 20;
-		u32 subc = (addr & 0x00070000) >> 16;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff;
-		u32 show = stat;
-
-		if (stat & NV_PGRAPH_INTR_ERROR) {
-			if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-				if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-					show &= ~NV_PGRAPH_INTR_ERROR;
-			}
-		}
-
-		nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-		nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-		if (show && nouveau_ratelimit()) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv10_graph_intr, show);
-			printk(" nsource:");
-			nouveau_bitfield_print(nv04_graph_nsource, nsource);
-			printk(" nstatus:");
-			nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-				     "mthd 0x%04x data 0x%08x\n",
-				chid, subc, class, mthd, data);
-		}
-	}
-}
-
-static void
-nv20_graph_destroy(struct drm_device *dev, int engine)
-{
-	struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 12);
-	nouveau_gpuobj_ref(NULL, &pgraph->ctxtab);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(pgraph);
-}
-
-int
-nv20_graph_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv20_graph_engine *pgraph;
-	int ret;
-
-	pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
-
-	pgraph->base.destroy = nv20_graph_destroy;
-	pgraph->base.fini = nv20_graph_fini;
-	pgraph->base.context_new = nv20_graph_context_new;
-	pgraph->base.context_del = nv20_graph_context_del;
-	pgraph->base.object_new = nv04_graph_object_new;
-	pgraph->base.set_tile_region = nv20_graph_set_tile_region;
-
-	pgraph->grctx_user = 0x0028;
-	if (dev_priv->card_type == NV_20) {
-		pgraph->base.init = nv20_graph_init;
-		switch (dev_priv->chipset) {
-		case 0x20:
-			pgraph->grctx_init = nv20_graph_context_init;
-			pgraph->grctx_size = NV20_GRCTX_SIZE;
-			pgraph->grctx_user = 0x0000;
-			break;
-		case 0x25:
-		case 0x28:
-			pgraph->grctx_init = nv25_graph_context_init;
-			pgraph->grctx_size = NV25_GRCTX_SIZE;
-			break;
-		case 0x2a:
-			pgraph->grctx_init = nv2a_graph_context_init;
-			pgraph->grctx_size = NV2A_GRCTX_SIZE;
-			pgraph->grctx_user = 0x0000;
-			break;
-		default:
-			NV_ERROR(dev, "PGRAPH: unknown chipset\n");
-			kfree(pgraph);
-			return 0;
-		}
-	} else {
-		pgraph->base.init = nv30_graph_init;
-		switch (dev_priv->chipset) {
-		case 0x30:
-		case 0x31:
-			pgraph->grctx_init = nv30_31_graph_context_init;
-			pgraph->grctx_size = NV30_31_GRCTX_SIZE;
-			break;
-		case 0x34:
-			pgraph->grctx_init = nv34_graph_context_init;
-			pgraph->grctx_size = NV34_GRCTX_SIZE;
-			break;
-		case 0x35:
-		case 0x36:
-			pgraph->grctx_init = nv35_36_graph_context_init;
-			pgraph->grctx_size = NV35_36_GRCTX_SIZE;
-			break;
-		default:
-			NV_ERROR(dev, "PGRAPH: unknown chipset\n");
-			kfree(pgraph);
-			return 0;
-		}
-	}
-
-	/* Create Context Pointer Table */
-	ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC,
-				 &pgraph->ctxtab);
-	if (ret) {
-		kfree(pgraph);
-		return ret;
-	}
-
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	nouveau_irq_register(dev, 12, nv20_graph_isr);
-
-	NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-	NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-	NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-	NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-	NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-	NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-	NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-	NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-	NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-	NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-	NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-	NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-	if (dev_priv->card_type == NV_20) {
-		NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
-		NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
-
-		/* kelvin */
-		if (dev_priv->chipset < 0x25)
-			NVOBJ_CLASS(dev, 0x0097, GR);
-		else
-			NVOBJ_CLASS(dev, 0x0597, GR);
-	} else {
-		NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
-		NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
-		NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
-		NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
-
-		/* rankine */
-		if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
-			NVOBJ_CLASS(dev, 0x0397, GR);
-		else
-		if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
-			NVOBJ_CLASS(dev, 0x0697, GR);
-		else
-		if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
-			NVOBJ_CLASS(dev, 0x0497, GR);
-	}
-
-	return 0;
-}
+struct nouveau_oclass
+nv20_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x20),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv20_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv20_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
new file mode 100644
index 0000000..2bea731
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
@@ -0,0 +1,31 @@
+#ifndef __NV20_GRAPH_H__
+#define __NV20_GRAPH_H__
+
+#include <core/enum.h>
+
+#include <engine/graph.h>
+#include <engine/fifo.h>
+
+struct nv20_graph_priv {
+	struct nouveau_graph base;
+	struct nouveau_gpuobj *ctxtab;
+};
+
+struct nv20_graph_chan {
+	struct nouveau_graph_chan base;
+	int chid;
+};
+
+extern struct nouveau_oclass nv25_graph_sclass[];
+int  nv20_graph_context_init(struct nouveau_object *);
+int  nv20_graph_context_fini(struct nouveau_object *, bool);
+
+void nv20_graph_tile_prog(struct nouveau_engine *, int);
+void nv20_graph_intr(struct nouveau_subdev *);
+
+void nv20_graph_dtor(struct nouveau_object *);
+int  nv20_graph_init(struct nouveau_object *);
+
+int  nv30_graph_init(struct nouveau_object *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
new file mode 100644
index 0000000..b2b650d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
@@ -0,0 +1,167 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/graph.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nouveau_oclass
+nv25_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
+	{ 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x0597, &nv04_graph_ofuncs, NULL }, /* kelvin */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv25_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x3724,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x035c, 0xffff0000);
+	nv_wo32(chan, 0x03c0, 0x0fff0000);
+	nv_wo32(chan, 0x03c4, 0x0fff0000);
+	nv_wo32(chan, 0x049c, 0x00000101);
+	nv_wo32(chan, 0x04b0, 0x00000111);
+	nv_wo32(chan, 0x04c8, 0x00000080);
+	nv_wo32(chan, 0x04cc, 0xffff0000);
+	nv_wo32(chan, 0x04d0, 0x00000001);
+	nv_wo32(chan, 0x04e4, 0x44400000);
+	nv_wo32(chan, 0x04fc, 0x4b800000);
+	for (i = 0x0510; i <= 0x051c; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x0530; i <= 0x053c; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x0548; i <= 0x0554; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0558; i <= 0x0564; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x0568; i <= 0x0574; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x0598; i <= 0x05d4; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05e0, 0x4b7fffff);
+	nv_wo32(chan, 0x0620, 0x00000080);
+	nv_wo32(chan, 0x0624, 0x30201000);
+	nv_wo32(chan, 0x0628, 0x70605040);
+	nv_wo32(chan, 0x062c, 0xb0a09080);
+	nv_wo32(chan, 0x0630, 0xf0e0d0c0);
+	nv_wo32(chan, 0x0664, 0x00000001);
+	nv_wo32(chan, 0x066c, 0x00004000);
+	nv_wo32(chan, 0x0678, 0x00000001);
+	nv_wo32(chan, 0x0680, 0x00040000);
+	nv_wo32(chan, 0x0684, 0x00010000);
+	for (i = 0x1b04; i <= 0x2374; i += 16) {
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x2704, 0x3f800000);
+	nv_wo32(chan, 0x2718, 0x3f800000);
+	nv_wo32(chan, 0x2744, 0x40000000);
+	nv_wo32(chan, 0x2748, 0x3f800000);
+	nv_wo32(chan, 0x274c, 0x3f000000);
+	nv_wo32(chan, 0x2754, 0x40000000);
+	nv_wo32(chan, 0x2758, 0x3f800000);
+	nv_wo32(chan, 0x2760, 0xbf800000);
+	nv_wo32(chan, 0x2768, 0xbf800000);
+	nv_wo32(chan, 0x308c, 0x000fe000);
+	nv_wo32(chan, 0x3108, 0x000003f8);
+	nv_wo32(chan, 0x3468, 0x002fe000);
+	for (i = 0x3484; i <= 0x34a0; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv25_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x25),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv25_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv25_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv25_graph_cclass;
+	nv_engine(priv)->sclass = nv25_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv25_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x25),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv25_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv20_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
new file mode 100644
index 0000000..700462f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
@@ -0,0 +1,134 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/graph.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv2a_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x36b0,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x033c, 0xffff0000);
+	nv_wo32(chan, 0x03a0, 0x0fff0000);
+	nv_wo32(chan, 0x03a4, 0x0fff0000);
+	nv_wo32(chan, 0x047c, 0x00000101);
+	nv_wo32(chan, 0x0490, 0x00000111);
+	nv_wo32(chan, 0x04a8, 0x44400000);
+	for (i = 0x04d4; i <= 0x04e0; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x04f4; i <= 0x0500; i += 4)
+		nv_wo32(chan, i, 0x00080000);
+	for (i = 0x050c; i <= 0x0518; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x051c; i <= 0x0528; i += 4)
+		nv_wo32(chan, i, 0x000105b8);
+	for (i = 0x052c; i <= 0x0538; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	for (i = 0x055c; i <= 0x0598; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x05a4, 0x4b7fffff);
+	nv_wo32(chan, 0x05fc, 0x00000001);
+	nv_wo32(chan, 0x0604, 0x00004000);
+	nv_wo32(chan, 0x0610, 0x00000001);
+	nv_wo32(chan, 0x0618, 0x00040000);
+	nv_wo32(chan, 0x061c, 0x00010000);
+	for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
+		nv_wo32(chan, (i + 0), 0x10700ff9);
+		nv_wo32(chan, (i + 4), 0x0436086c);
+		nv_wo32(chan, (i + 8), 0x000c001b);
+	}
+	nv_wo32(chan, 0x269c, 0x3f800000);
+	nv_wo32(chan, 0x26b0, 0x3f800000);
+	nv_wo32(chan, 0x26dc, 0x40000000);
+	nv_wo32(chan, 0x26e0, 0x3f800000);
+	nv_wo32(chan, 0x26e4, 0x3f000000);
+	nv_wo32(chan, 0x26ec, 0x40000000);
+	nv_wo32(chan, 0x26f0, 0x3f800000);
+	nv_wo32(chan, 0x26f8, 0xbf800000);
+	nv_wo32(chan, 0x2700, 0xbf800000);
+	nv_wo32(chan, 0x3024, 0x000fe000);
+	nv_wo32(chan, 0x30a0, 0x000003f8);
+	nv_wo32(chan, 0x33fc, 0x002fe000);
+	for (i = 0x341c; i <= 0x3438; i += 4)
+		nv_wo32(chan, i, 0x001c527c);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv2a_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x2a),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv2a_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv2a_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv2a_graph_cclass;
+	nv_engine(priv)->sclass = nv25_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv2a_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x2a),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv2a_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv20_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
new file mode 100644
index 0000000..cedadaa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
@@ -0,0 +1,238 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/graph.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv30_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0397, &nv04_graph_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv30_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x5f48,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x0410, 0x00000101);
+	nv_wo32(chan, 0x0424, 0x00000111);
+	nv_wo32(chan, 0x0428, 0x00000060);
+	nv_wo32(chan, 0x0444, 0x00000080);
+	nv_wo32(chan, 0x0448, 0xffff0000);
+	nv_wo32(chan, 0x044c, 0x00000001);
+	nv_wo32(chan, 0x0460, 0x44400000);
+	nv_wo32(chan, 0x048c, 0xffff0000);
+	for (i = 0x04e0; i < 0x04e8; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04ec, 0x00011100);
+	for (i = 0x0508; i < 0x0548; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x0550, 0x4b7fffff);
+	nv_wo32(chan, 0x058c, 0x00000080);
+	nv_wo32(chan, 0x0590, 0x30201000);
+	nv_wo32(chan, 0x0594, 0x70605040);
+	nv_wo32(chan, 0x0598, 0xb8a89888);
+	nv_wo32(chan, 0x059c, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05b0, 0xb0000000);
+	for (i = 0x0600; i < 0x0640; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0640; i < 0x0680; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06c0; i < 0x0700; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x0700; i < 0x0740; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0740; i < 0x0780; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x085c, 0x00040000);
+	nv_wo32(chan, 0x0860, 0x00010000);
+	for (i = 0x0864; i < 0x0874; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x1f18; i <= 0x3088 ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 1, 0x0436086c);
+		nv_wo32(chan, i + 2, 0x000c001b);
+	}
+	for (i = 0x30b8; i < 0x30c8; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x344c, 0x3f800000);
+	nv_wo32(chan, 0x3808, 0x3f800000);
+	nv_wo32(chan, 0x381c, 0x3f800000);
+	nv_wo32(chan, 0x3848, 0x40000000);
+	nv_wo32(chan, 0x384c, 0x3f800000);
+	nv_wo32(chan, 0x3850, 0x3f000000);
+	nv_wo32(chan, 0x3858, 0x40000000);
+	nv_wo32(chan, 0x385c, 0x3f800000);
+	nv_wo32(chan, 0x3864, 0xbf800000);
+	nv_wo32(chan, 0x386c, 0xbf800000);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv30_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x30),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv30_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv30_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv30_graph_cclass;
+	nv_engine(priv)->sclass = nv30_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+int
+nv30_graph_init(struct nouveau_object *object)
+{
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nv20_graph_priv *priv = (void *)engine;
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	int ret, i;
+
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
+
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+	nv_wr32(priv, 0x400890, 0x01b463ff);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
+	nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
+	nv_wr32(priv, 0x400B80, 0x1003d888);
+	nv_wr32(priv, 0x400B84, 0x0c000000);
+	nv_wr32(priv, 0x400098, 0x00000000);
+	nv_wr32(priv, 0x40009C, 0x0005ad00);
+	nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
+	nv_wr32(priv, 0x4000a0, 0x00000000);
+	nv_wr32(priv, 0x4000a4, 0x00000008);
+	nv_wr32(priv, 0x4008a8, 0xb784a400);
+	nv_wr32(priv, 0x400ba0, 0x002f8685);
+	nv_wr32(priv, 0x400ba4, 0x00231f3f);
+	nv_wr32(priv, 0x4008a4, 0x40000020);
+
+	if (nv_device(priv)->chipset == 0x34) {
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032);
+		nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
+		nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002);
+	}
+
+	nv_wr32(priv, 0x4000c0, 0x00000016);
+
+	/* Turn all the tiling regions off. */
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
+
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+	nv_wr32(priv, 0x0040075c             , 0x00000001);
+
+	/* begin RAM config */
+	/* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */
+	nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+	nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+	if (nv_device(priv)->chipset != 0x34) {
+		nv_wr32(priv, 0x400750, 0x00EA0000);
+		nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x400750, 0x00EA0004);
+		nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204));
+	}
+	return 0;
+}
+
+struct nouveau_oclass
+nv30_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x30),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv30_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv30_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c
new file mode 100644
index 0000000..273f632
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c
@@ -0,0 +1,168 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include <engine/graph.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv34_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0697, &nv04_graph_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv34_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x46dc,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x040c, 0x01000101);
+	nv_wo32(chan, 0x0420, 0x00000111);
+	nv_wo32(chan, 0x0424, 0x00000060);
+	nv_wo32(chan, 0x0440, 0x00000080);
+	nv_wo32(chan, 0x0444, 0xffff0000);
+	nv_wo32(chan, 0x0448, 0x00000001);
+	nv_wo32(chan, 0x045c, 0x44400000);
+	nv_wo32(chan, 0x0480, 0xffff0000);
+	for (i = 0x04d4; i < 0x04dc; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04e0, 0x00011100);
+	for (i = 0x04fc; i < 0x053c; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x0544, 0x4b7fffff);
+	nv_wo32(chan, 0x057c, 0x00000080);
+	nv_wo32(chan, 0x0580, 0x30201000);
+	nv_wo32(chan, 0x0584, 0x70605040);
+	nv_wo32(chan, 0x0588, 0xb8a89888);
+	nv_wo32(chan, 0x058c, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05a0, 0xb0000000);
+	for (i = 0x05f0; i < 0x0630; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0630; i < 0x0670; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06b0; i < 0x06f0; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x06f0; i < 0x0730; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0730; i < 0x0770; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x0850, 0x00040000);
+	nv_wo32(chan, 0x0854, 0x00010000);
+	for (i = 0x0858; i < 0x0868; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x15ac; i <= 0x271c ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 1, 0x0436086c);
+		nv_wo32(chan, i + 2, 0x000c001b);
+	}
+	for (i = 0x274c; i < 0x275c; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x2ae0, 0x3f800000);
+	nv_wo32(chan, 0x2e9c, 0x3f800000);
+	nv_wo32(chan, 0x2eb0, 0x3f800000);
+	nv_wo32(chan, 0x2edc, 0x40000000);
+	nv_wo32(chan, 0x2ee0, 0x3f800000);
+	nv_wo32(chan, 0x2ee4, 0x3f000000);
+	nv_wo32(chan, 0x2eec, 0x40000000);
+	nv_wo32(chan, 0x2ef0, 0x3f800000);
+	nv_wo32(chan, 0x2ef8, 0xbf800000);
+	nv_wo32(chan, 0x2f00, 0xbf800000);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv34_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x34),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv34_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv34_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv34_graph_cclass;
+	nv_engine(priv)->sclass = nv34_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv34_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x34),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv34_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv30_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c
new file mode 100644
index 0000000..f40ee21
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c
@@ -0,0 +1,166 @@
+#include <core/os.h>
+#include <core/class.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+
+#include "nv20.h"
+#include "regs.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv35_graph_sclass[] = {
+	{ 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
+	{ 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
+	{ 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
+	{ 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
+	{ 0x0497, &nv04_graph_ofuncs, NULL }, /* rankine */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv35_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv20_graph_chan *chan;
+	int ret, i;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x577c,
+					   16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	chan->chid = nouveau_fifo_chan(parent)->chid;
+
+	nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+	nv_wo32(chan, 0x040c, 0x00000101);
+	nv_wo32(chan, 0x0420, 0x00000111);
+	nv_wo32(chan, 0x0424, 0x00000060);
+	nv_wo32(chan, 0x0440, 0x00000080);
+	nv_wo32(chan, 0x0444, 0xffff0000);
+	nv_wo32(chan, 0x0448, 0x00000001);
+	nv_wo32(chan, 0x045c, 0x44400000);
+	nv_wo32(chan, 0x0488, 0xffff0000);
+	for (i = 0x04dc; i < 0x04e4; i += 4)
+		nv_wo32(chan, i, 0x0fff0000);
+	nv_wo32(chan, 0x04e8, 0x00011100);
+	for (i = 0x0504; i < 0x0544; i += 4)
+		nv_wo32(chan, i, 0x07ff0000);
+	nv_wo32(chan, 0x054c, 0x4b7fffff);
+	nv_wo32(chan, 0x0588, 0x00000080);
+	nv_wo32(chan, 0x058c, 0x30201000);
+	nv_wo32(chan, 0x0590, 0x70605040);
+	nv_wo32(chan, 0x0594, 0xb8a89888);
+	nv_wo32(chan, 0x0598, 0xf8e8d8c8);
+	nv_wo32(chan, 0x05ac, 0xb0000000);
+	for (i = 0x0604; i < 0x0644; i += 4)
+		nv_wo32(chan, i, 0x00010588);
+	for (i = 0x0644; i < 0x0684; i += 4)
+		nv_wo32(chan, i, 0x00030303);
+	for (i = 0x06c4; i < 0x0704; i += 4)
+		nv_wo32(chan, i, 0x0008aae4);
+	for (i = 0x0704; i < 0x0744; i += 4)
+		nv_wo32(chan, i, 0x01012000);
+	for (i = 0x0744; i < 0x0784; i += 4)
+		nv_wo32(chan, i, 0x00080008);
+	nv_wo32(chan, 0x0860, 0x00040000);
+	nv_wo32(chan, 0x0864, 0x00010000);
+	for (i = 0x0868; i < 0x0878; i += 4)
+		nv_wo32(chan, i, 0x00040004);
+	for (i = 0x1f1c; i <= 0x308c ; i += 16) {
+		nv_wo32(chan, i + 0, 0x10700ff9);
+		nv_wo32(chan, i + 4, 0x0436086c);
+		nv_wo32(chan, i + 8, 0x000c001b);
+	}
+	for (i = 0x30bc; i < 0x30cc; i += 4)
+		nv_wo32(chan, i, 0x0000ffff);
+	nv_wo32(chan, 0x3450, 0x3f800000);
+	nv_wo32(chan, 0x380c, 0x3f800000);
+	nv_wo32(chan, 0x3820, 0x3f800000);
+	nv_wo32(chan, 0x384c, 0x40000000);
+	nv_wo32(chan, 0x3850, 0x3f800000);
+	nv_wo32(chan, 0x3854, 0x3f000000);
+	nv_wo32(chan, 0x385c, 0x40000000);
+	nv_wo32(chan, 0x3860, 0x3f800000);
+	nv_wo32(chan, 0x3868, 0xbf800000);
+	nv_wo32(chan, 0x3870, 0xbf800000);
+	return 0;
+}
+
+static struct nouveau_oclass
+nv35_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x35),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv35_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = nv20_graph_context_init,
+		.fini = nv20_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv35_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
+{
+	struct nv20_graph_priv *priv;
+	int ret;
+
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, NULL, 32 * 4, 16,
+				 NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv20_graph_intr;
+	nv_engine(priv)->cclass = &nv35_graph_cclass;
+	nv_engine(priv)->sclass = nv35_graph_sclass;
+	nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
+	return 0;
+}
+
+struct nouveau_oclass
+nv35_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x35),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv35_graph_ctor,
+		.dtor = nv20_graph_dtor,
+		.init = nv30_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
index 466d215..2f9f2c6 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
@@ -1,151 +1,238 @@
 /*
- * Copyright (C) 2007 Ben Skeggs.
- * All Rights Reserved.
+ * 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drmP.h"
-#include "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include <core/ramht.h>
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
+#include <core/engctx.h>
 
-struct nv40_graph_engine {
-	struct nouveau_exec_engine base;
-	u32 grctx_size;
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+#include <engine/graph.h>
+#include <engine/fifo.h>
+
+#include "nv40.h"
+#include "regs.h"
+
+struct nv40_graph_priv {
+	struct nouveau_graph base;
+	u32 size;
 };
 
+struct nv40_graph_chan {
+	struct nouveau_graph_chan base;
+};
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
 static int
-nv40_graph_context_new(struct nouveau_channel *chan, int engine)
+nv40_graph_object_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine);
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *grctx = NULL;
-	unsigned long flags;
+	struct nouveau_gpuobj *obj;
 	int ret;
 
-	ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
-				 NVOBJ_FLAG_ZERO_ALLOC, &grctx);
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    20, 16, 0, &obj);
+	*pobject = nv_object(obj);
 	if (ret)
 		return ret;
 
-	/* Initialise default context values */
-	nv40_grctx_fill(dev, grctx);
-	nv_wo32(grctx, 0, grctx->addr);
-
-	/* init grctx pointer in ramfc, and on PFIFO if channel is
-	 * already active there
-	 */
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_wo32(chan->ramfc, 0x38, grctx->addr >> 4);
-	nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
-	if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
-		nv_wr32(dev, 0x0032e0, grctx->addr >> 4);
-	nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	chan->engctx[engine] = grctx;
-	return 0;
-}
-
-static void
-nv40_graph_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nouveau_gpuobj *grctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	u32 inst = 0x01000000 | (grctx->addr >> 4);
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, 0x400720, 0x00000000, 0x00000001);
-	if (nv_rd32(dev, 0x40032c) == inst)
-		nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
-	if (nv_rd32(dev, 0x400330) == inst)
-		nv_mask(dev, 0x400330, 0x01000000, 0x00000000);
-	nv_mask(dev, 0x400720, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-	/* Free the context resources */
-	nouveau_gpuobj_ref(NULL, &grctx);
-	chan->engctx[engine] = NULL;
-}
-
-int
-nv40_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
-	int ret;
-
-	ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
-	if (ret)
-		return ret;
-	obj->engine = 1;
-	obj->class  = class;
-
-	nv_wo32(obj, 0x00, class);
+	nv_wo32(obj, 0x00, nv_mclass(obj));
 	nv_wo32(obj, 0x04, 0x00000000);
-#ifndef __BIG_ENDIAN
 	nv_wo32(obj, 0x08, 0x00000000);
-#else
-	nv_wo32(obj, 0x08, 0x01000000);
+#ifdef __BIG_ENDIAN
+	nv_mo32(obj, 0x08, 0x01000000, 0x01000000);
 #endif
 	nv_wo32(obj, 0x0c, 0x00000000);
 	nv_wo32(obj, 0x10, 0x00000000);
+	return 0;
+}
 
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
+struct nouveau_ofuncs
+nv40_graph_ofuncs = {
+	.ctor = nv40_graph_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
+
+static struct nouveau_oclass
+nv40_graph_sclass[] = {
+	{ 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
+	{ 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
+	{ 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
+	{ 0x4097, &nv40_graph_ofuncs, NULL }, /* curie */
+	{},
+};
+
+static struct nouveau_oclass
+nv44_graph_sclass[] = {
+	{ 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
+	{ 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
+	{ 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
+	{ 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
+	{ 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
+	{ 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
+	{ 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
+	{ 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
+	{ 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
+	{ 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
+	{ 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
+	{ 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
+	{ 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
+	{ 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
+	{ 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
+	{ 0x4497, &nv40_graph_ofuncs, NULL }, /* curie */
+	{},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv40_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
+{
+	struct nv40_graph_priv *priv = (void *)engine;
+	struct nv40_graph_chan *chan;
+	int ret;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
+					   priv->size, 16,
+					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan));
+	nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4);
+	return 0;
+}
+
+static int
+nv40_graph_context_fini(struct nouveau_object *object, bool suspend)
+{
+	struct nv04_graph_priv *priv = (void *)object->engine;
+	struct nv04_graph_chan *chan = (void *)object;
+	u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;
+	int ret = 0;
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
+
+	if (nv_rd32(priv, 0x40032c) == inst) {
+		if (suspend) {
+			nv_wr32(priv, 0x400720, 0x00000000);
+			nv_wr32(priv, 0x400784, inst);
+			nv_mask(priv, 0x400310, 0x00000020, 0x00000020);
+			nv_mask(priv, 0x400304, 0x00000001, 0x00000001);
+			if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) {
+				u32 insn = nv_rd32(priv, 0x400308);
+				nv_warn(priv, "ctxprog timeout 0x%08x\n", insn);
+				ret = -EBUSY;
+			}
+		}
+
+		nv_mask(priv, 0x40032c, 0x01000000, 0x00000000);
+	}
+
+	if (nv_rd32(priv, 0x400330) == inst)
+		nv_mask(priv, 0x400330, 0x01000000, 0x00000000);
+
+	nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
 	return ret;
 }
 
-static void
-nv40_graph_set_tile_region(struct drm_device *dev, int i)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
+static struct nouveau_oclass
+nv40_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x40),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv40_graph_context_ctor,
+		.dtor = _nouveau_graph_context_dtor,
+		.init = _nouveau_graph_context_init,
+		.fini = nv40_graph_context_fini,
+		.rd32 = _nouveau_graph_context_rd32,
+		.wr32 = _nouveau_graph_context_wr32,
+	},
+};
 
-	switch (dev_priv->chipset) {
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv40_graph_tile_prog(struct nouveau_engine *engine, int i)
+{
+	struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
+	struct nouveau_fifo *pfifo = nouveau_fifo(engine);
+	struct nv40_graph_priv *priv = (void *)engine;
+	unsigned long flags;
+
+	pfifo->pause(pfifo, &flags);
+	nv04_graph_idle(priv);
+
+	switch (nv_device(priv)->chipset) {
 	case 0x40:
 	case 0x41: /* guess */
 	case 0x42:
 	case 0x43:
 	case 0x45: /* guess */
 	case 0x4e:
-		nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
-		nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
-		nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
-		nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
+		nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+		nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+		nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+		nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
 		break;
 	case 0x44:
 	case 0x4a:
-		nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr);
+		nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
 		break;
 	case 0x46:
 	case 0x47:
@@ -154,149 +241,213 @@
 	case 0x4c:
 	case 0x67:
 	default:
-		nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch);
-		nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit);
-		nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr);
-		nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch);
-		nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit);
-		nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr);
+		nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch);
+		nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit);
+		nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr);
+		nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+		nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+		nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
 		break;
 	}
+
+	pfifo->start(pfifo, &flags);
+}
+
+static void
+nv40_graph_intr(struct nouveau_subdev *subdev)
+{
+	struct nv40_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+	u32 inst = (nv_rd32(priv, 0x40032c) & 0x000fffff) << 4;
+	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+	u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff;
+	u32 show = stat;
+
+	if (stat & NV_PGRAPH_INTR_ERROR) {
+		if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+			handle = nouveau_engctx_lookup_class(engine, inst, class);
+			if (handle && !nv_call(handle->object, mthd, data))
+				show &= ~NV_PGRAPH_INTR_ERROR;
+			nouveau_engctx_handle_put(handle);
+		}
+
+		if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
+			nv_mask(priv, 0x402000, 0, 0);
+		}
+	}
+
+	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+	if (show) {
+		nv_info(priv, "");
+		nouveau_bitfield_print(nv10_graph_intr_name, show);
+		printk(" nsource:");
+		nouveau_bitfield_print(nv04_graph_nsource, nsource);
+		printk(" nstatus:");
+		nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+		printk("\n");
+		nv_error(priv, "ch 0x%08x subc %d class 0x%04x "
+			       "mthd 0x%04x data 0x%08x\n",
+			 inst, subc, class, mthd, data);
+	}
 }
 
-/*
- * G70		0x47
- * G71		0x49
- * NV45		0x48
- * G72[M]	0x46
- * G73		0x4b
- * C51_G7X	0x4c
- * C51		0x4e
- */
-int
-nv40_graph_init(struct drm_device *dev, int engine)
+static int
+nv40_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t vramsz;
-	int i, j;
+	struct nv40_graph_priv *priv;
+	int ret;
 
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
-			~NV_PMC_ENABLE_PGRAPH);
-	nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
-			 NV_PMC_ENABLE_PGRAPH);
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
+
+	nv_subdev(priv)->unit = 0x00001000;
+	nv_subdev(priv)->intr = nv40_graph_intr;
+	nv_engine(priv)->cclass = &nv40_graph_cclass;
+	if (nv44_graph_class(priv))
+		nv_engine(priv)->sclass = nv44_graph_sclass;
+	else
+		nv_engine(priv)->sclass = nv40_graph_sclass;
+	nv_engine(priv)->tile_prog = nv40_graph_tile_prog;
+	return 0;
+}
+
+static int
+nv40_graph_init(struct nouveau_object *object)
+{
+	struct nouveau_engine *engine = nv_engine(object);
+	struct nouveau_fb *pfb = nouveau_fb(object);
+	struct nv40_graph_priv *priv = (void *)engine;
+	int ret, i, j;
+	u32 vramsz;
+
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
 
 	/* generate and upload context program */
-	nv40_grctx_init(dev, &pgraph->grctx_size);
+	nv40_grctx_init(nv_device(priv), &priv->size);
 
 	/* No context present currently */
-	nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
+	nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
 
-	nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-	nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
+	nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+	nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x401287c0);
-	nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
-	nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00008000);
-	nv_wr32(dev, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
+	nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
+	nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
 
-	nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-	nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
+	nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+	nv_wr32(priv, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
 
-	j = nv_rd32(dev, 0x1540) & 0xff;
+	j = nv_rd32(priv, 0x1540) & 0xff;
 	if (j) {
 		for (i = 0; !(j & 1); j >>= 1, i++)
 			;
-		nv_wr32(dev, 0x405000, i);
+		nv_wr32(priv, 0x405000, i);
 	}
 
-	if (dev_priv->chipset == 0x40) {
-		nv_wr32(dev, 0x4009b0, 0x83280fff);
-		nv_wr32(dev, 0x4009b4, 0x000000a0);
+	if (nv_device(priv)->chipset == 0x40) {
+		nv_wr32(priv, 0x4009b0, 0x83280fff);
+		nv_wr32(priv, 0x4009b4, 0x000000a0);
 	} else {
-		nv_wr32(dev, 0x400820, 0x83280eff);
-		nv_wr32(dev, 0x400824, 0x000000a0);
+		nv_wr32(priv, 0x400820, 0x83280eff);
+		nv_wr32(priv, 0x400824, 0x000000a0);
 	}
 
-	switch (dev_priv->chipset) {
+	switch (nv_device(priv)->chipset) {
 	case 0x40:
 	case 0x45:
-		nv_wr32(dev, 0x4009b8, 0x0078e366);
-		nv_wr32(dev, 0x4009bc, 0x0000014c);
+		nv_wr32(priv, 0x4009b8, 0x0078e366);
+		nv_wr32(priv, 0x4009bc, 0x0000014c);
 		break;
 	case 0x41:
 	case 0x42: /* pciid also 0x00Cx */
 	/* case 0x0120: XXX (pciid) */
-		nv_wr32(dev, 0x400828, 0x007596ff);
-		nv_wr32(dev, 0x40082c, 0x00000108);
+		nv_wr32(priv, 0x400828, 0x007596ff);
+		nv_wr32(priv, 0x40082c, 0x00000108);
 		break;
 	case 0x43:
-		nv_wr32(dev, 0x400828, 0x0072cb77);
-		nv_wr32(dev, 0x40082c, 0x00000108);
+		nv_wr32(priv, 0x400828, 0x0072cb77);
+		nv_wr32(priv, 0x40082c, 0x00000108);
 		break;
 	case 0x44:
 	case 0x46: /* G72 */
 	case 0x4a:
 	case 0x4c: /* G7x-based C51 */
 	case 0x4e:
-		nv_wr32(dev, 0x400860, 0);
-		nv_wr32(dev, 0x400864, 0);
+		nv_wr32(priv, 0x400860, 0);
+		nv_wr32(priv, 0x400864, 0);
 		break;
 	case 0x47: /* G70 */
 	case 0x49: /* G71 */
 	case 0x4b: /* G73 */
-		nv_wr32(dev, 0x400828, 0x07830610);
-		nv_wr32(dev, 0x40082c, 0x0000016A);
+		nv_wr32(priv, 0x400828, 0x07830610);
+		nv_wr32(priv, 0x40082c, 0x0000016A);
 		break;
 	default:
 		break;
 	}
 
-	nv_wr32(dev, 0x400b38, 0x2ffff800);
-	nv_wr32(dev, 0x400b3c, 0x00006000);
+	nv_wr32(priv, 0x400b38, 0x2ffff800);
+	nv_wr32(priv, 0x400b3c, 0x00006000);
 
 	/* Tiling related stuff. */
-	switch (dev_priv->chipset) {
+	switch (nv_device(priv)->chipset) {
 	case 0x44:
 	case 0x4a:
-		nv_wr32(dev, 0x400bc4, 0x1003d888);
-		nv_wr32(dev, 0x400bbc, 0xb7a7b500);
+		nv_wr32(priv, 0x400bc4, 0x1003d888);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b500);
 		break;
 	case 0x46:
-		nv_wr32(dev, 0x400bc4, 0x0000e024);
-		nv_wr32(dev, 0x400bbc, 0xb7a7b520);
+		nv_wr32(priv, 0x400bc4, 0x0000e024);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b520);
 		break;
 	case 0x4c:
 	case 0x4e:
 	case 0x67:
-		nv_wr32(dev, 0x400bc4, 0x1003d888);
-		nv_wr32(dev, 0x400bbc, 0xb7a7b540);
+		nv_wr32(priv, 0x400bc4, 0x1003d888);
+		nv_wr32(priv, 0x400bbc, 0xb7a7b540);
 		break;
 	default:
 		break;
 	}
 
 	/* Turn all the tiling regions off. */
-	for (i = 0; i < nvfb_tile_nr(dev); i++)
-		nv40_graph_set_tile_region(dev, i);
+	for (i = 0; i < pfb->tile.regions; i++)
+		engine->tile_prog(engine, i);
 
 	/* begin RAM config */
-	vramsz = pci_resource_len(dev->pdev, 0) - 1;
-	switch (dev_priv->chipset) {
+	vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
+	switch (nv_device(priv)->chipset) {
 	case 0x40:
-		nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0));
-		nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1));
-		nv_wr32(dev, 0x4069A4, nv_rd32(dev, NV04_PFB_CFG0));
-		nv_wr32(dev, 0x4069A8, nv_rd32(dev, NV04_PFB_CFG1));
-		nv_wr32(dev, 0x400820, 0);
-		nv_wr32(dev, 0x400824, 0);
-		nv_wr32(dev, 0x400864, vramsz);
-		nv_wr32(dev, 0x400868, vramsz);
+		nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x400820, 0);
+		nv_wr32(priv, 0x400824, 0);
+		nv_wr32(priv, 0x400864, vramsz);
+		nv_wr32(priv, 0x400868, vramsz);
 		break;
 	default:
-		switch (dev_priv->chipset) {
+		switch (nv_device(priv)->chipset) {
 		case 0x41:
 		case 0x42:
 		case 0x43:
@@ -304,163 +455,33 @@
 		case 0x4e:
 		case 0x44:
 		case 0x4a:
-			nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0));
-			nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1));
+			nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200));
+			nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204));
 			break;
 		default:
-			nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0));
-			nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1));
+			nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200));
+			nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204));
 			break;
 		}
-		nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0));
-		nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1));
-		nv_wr32(dev, 0x400840, 0);
-		nv_wr32(dev, 0x400844, 0);
-		nv_wr32(dev, 0x4008A0, vramsz);
-		nv_wr32(dev, 0x4008A4, vramsz);
+		nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200));
+		nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204));
+		nv_wr32(priv, 0x400840, 0);
+		nv_wr32(priv, 0x400844, 0);
+		nv_wr32(priv, 0x4008A0, vramsz);
+		nv_wr32(priv, 0x4008A4, vramsz);
 		break;
 	}
 
 	return 0;
 }
 
-static int
-nv40_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	u32 inst = nv_rd32(dev, 0x40032c);
-	if (inst & 0x01000000) {
-		nv_wr32(dev, 0x400720, 0x00000000);
-		nv_wr32(dev, 0x400784, inst);
-		nv_mask(dev, 0x400310, 0x00000020, 0x00000020);
-		nv_mask(dev, 0x400304, 0x00000001, 0x00000001);
-		if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) {
-			u32 insn = nv_rd32(dev, 0x400308);
-			NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn);
-		}
-		nv_mask(dev, 0x40032c, 0x01000000, 0x00000000);
-	}
-	return 0;
-}
-
-static int
-nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *grctx;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		if (!dev_priv->channels.ptr[i])
-			continue;
-		grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
-
-		if (grctx && grctx->addr == inst)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
-}
-
-static void
-nv40_graph_isr(struct drm_device *dev)
-{
-	u32 stat;
-
-	while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-		u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-		u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-		u32 inst = (nv_rd32(dev, 0x40032c) & 0x000fffff) << 4;
-		u32 chid = nv40_graph_isr_chid(dev, inst);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 subc = (addr & 0x00070000) >> 16;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xffff;
-		u32 show = stat;
-
-		if (stat & NV_PGRAPH_INTR_ERROR) {
-			if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-				if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-					show &= ~NV_PGRAPH_INTR_ERROR;
-			} else
-			if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
-				nv_mask(dev, 0x402000, 0, 0);
-			}
-		}
-
-		nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-		nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-		if (show && nouveau_ratelimit()) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv10_graph_intr, show);
-			printk(" nsource:");
-			nouveau_bitfield_print(nv04_graph_nsource, nsource);
-			printk(" nstatus:");
-			nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d (0x%08x) subc %d "
-				     "class 0x%04x mthd 0x%04x data 0x%08x\n",
-				chid, inst, subc, class, mthd, data);
-		}
-	}
-}
-
-static void
-nv40_graph_destroy(struct drm_device *dev, int engine)
-{
-	struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
-
-	nouveau_irq_unregister(dev, 12);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(pgraph);
-}
-
-int
-nv40_graph_create(struct drm_device *dev)
-{
-	struct nv40_graph_engine *pgraph;
-
-	pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
-
-	pgraph->base.destroy = nv40_graph_destroy;
-	pgraph->base.init = nv40_graph_init;
-	pgraph->base.fini = nv40_graph_fini;
-	pgraph->base.context_new = nv40_graph_context_new;
-	pgraph->base.context_del = nv40_graph_context_del;
-	pgraph->base.object_new = nv40_graph_object_new;
-	pgraph->base.set_tile_region = nv40_graph_set_tile_region;
-
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	nouveau_irq_register(dev, 12, nv40_graph_isr);
-
-	NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-	NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-	NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-	NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-	NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-	NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-	NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
-	NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-	NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
-	NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-	NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-	NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-	NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-	NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-	NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
-
-	/* curie */
-	if (nv44_graph_class(dev))
-		NVOBJ_CLASS(dev, 0x4497, GR);
-	else
-		NVOBJ_CLASS(dev, 0x4097, GR);
-
-	return 0;
-}
+struct nouveau_oclass
+nv40_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x40),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv40_graph_ctor,
+		.dtor = _nouveau_graph_dtor,
+		.init = nv40_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
new file mode 100644
index 0000000..d2ac975
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
@@ -0,0 +1,21 @@
+#ifndef __NV40_GRAPH_H__
+#define __NV40_GRAPH_H__
+
+/* returns 1 if device is one of the nv4x using the 0x4497 object class,
+ * helpful to determine a number of other hardware features
+ */
+static inline int
+nv44_graph_class(void *priv)
+{
+	struct nouveau_device *device = nv_device(priv);
+
+	if ((device->chipset & 0xf0) == 0x60)
+		return 1;
+
+	return !(0x0baf & (1 << (device->chipset & 0x0f)));
+}
+
+void nv40_grctx_init(struct nouveau_device *, u32 *size);
+void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
index 28932c4..8955bdd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
@@ -1,266 +1,234 @@
 /*
- * Copyright (C) 2007 Ben Skeggs.
- * All Rights Reserved.
+ * 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:
+ * 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 (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
+ * 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
+ * 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 "drmP.h"
-#include "drm.h"
-#include "nouveau_drv.h"
-#include <engine/fifo.h>
-#include <core/ramht.h>
-#include "nouveau_dma.h"
-#include "nv50_evo.h"
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
+#include <core/engctx.h>
+#include <core/enum.h>
 
-struct nv50_graph_engine {
-	struct nouveau_exec_engine base;
-	u32 ctxprog[512];
-	u32 ctxprog_size;
-	u32 grctx_size;
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+#include <subdev/timer.h>
+
+#include <engine/graph.h>
+
+#include "nv50.h"
+
+struct nv50_graph_priv {
+	struct nouveau_graph base;
+	spinlock_t lock;
+	u32 size;
 };
 
-static int
-nv50_graph_init(struct drm_device *dev, int engine)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
-	u32 units = nv_rd32(dev, 0x001540);
-	int i;
+struct nv50_graph_chan {
+	struct nouveau_graph_chan base;
+};
 
-	NV_DEBUG(dev, "\n");
-
-	/* master reset */
-	nv_mask(dev, 0x000200, 0x00201000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x00201000, 0x00201000);
-	nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
-
-	/* reset/enable traps and interrupts */
-	nv_wr32(dev, 0x400804, 0xc0000000);
-	nv_wr32(dev, 0x406800, 0xc0000000);
-	nv_wr32(dev, 0x400c04, 0xc0000000);
-	nv_wr32(dev, 0x401800, 0xc0000000);
-	nv_wr32(dev, 0x405018, 0xc0000000);
-	nv_wr32(dev, 0x402000, 0xc0000000);
-	for (i = 0; i < 16; i++) {
-		if (!(units & (1 << i)))
-			continue;
-
-		if (dev_priv->chipset < 0xa0) {
-			nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000);
-			nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000);
-			nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000);
-		} else {
-			nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000);
-			nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000);
-			nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000);
-		}
-	}
-
-	nv_wr32(dev, 0x400108, 0xffffffff);
-	nv_wr32(dev, 0x400138, 0xffffffff);
-	nv_wr32(dev, 0x400100, 0xffffffff);
-	nv_wr32(dev, 0x40013c, 0xffffffff);
-	nv_wr32(dev, 0x400500, 0x00010001);
-
-	/* upload context program, initialise ctxctl defaults */
-	nv_wr32(dev, 0x400324, 0x00000000);
-	for (i = 0; i < pgraph->ctxprog_size; i++)
-		nv_wr32(dev, 0x400328, pgraph->ctxprog[i]);
-	nv_wr32(dev, 0x400824, 0x00000000);
-	nv_wr32(dev, 0x400828, 0x00000000);
-	nv_wr32(dev, 0x40082c, 0x00000000);
-	nv_wr32(dev, 0x400830, 0x00000000);
-	nv_wr32(dev, 0x400724, 0x00000000);
-	nv_wr32(dev, 0x40032c, 0x00000000);
-	nv_wr32(dev, 0x400320, 4);	/* CTXCTL_CMD = NEWCTXDMA */
-
-	/* some unknown zcull magic */
-	switch (dev_priv->chipset & 0xf0) {
-	case 0x50:
-	case 0x80:
-	case 0x90:
-		nv_wr32(dev, 0x402ca8, 0x00000800);
-		break;
-	case 0xa0:
-	default:
-		nv_wr32(dev, 0x402cc0, 0x00000000);
-		if (dev_priv->chipset == 0xa0 ||
-		    dev_priv->chipset == 0xaa ||
-		    dev_priv->chipset == 0xac) {
-			nv_wr32(dev, 0x402ca8, 0x00000802);
-		} else {
-			nv_wr32(dev, 0x402cc0, 0x00000000);
-			nv_wr32(dev, 0x402ca8, 0x00000002);
-		}
-
-		break;
-	}
-
-	/* zero out zcull regions */
-	for (i = 0; i < 8; i++) {
-		nv_wr32(dev, 0x402c20 + (i * 8), 0x00000000);
-		nv_wr32(dev, 0x402c24 + (i * 8), 0x00000000);
-		nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000);
-		nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000);
-	}
-
-	return 0;
-}
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
 
 static int
-nv50_graph_fini(struct drm_device *dev, int engine, bool suspend)
+nv50_graph_object_ctor(struct nouveau_object *parent,
+		       struct nouveau_object *engine,
+		       struct nouveau_oclass *oclass, void *data, u32 size,
+		       struct nouveau_object **pobject)
 {
-	nv_wr32(dev, 0x40013c, 0x00000000);
-	return 0;
-}
-
-static int
-nv50_graph_context_new(struct nouveau_channel *chan, int engine)
-{
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_gpuobj *ramin = chan->ramin;
-	struct nouveau_gpuobj *grctx = NULL;
-	struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
-	int hdr, ret;
-
-	NV_DEBUG(dev, "ch%d\n", chan->id);
-
-	ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0,
-				 NVOBJ_FLAG_ZERO_ALLOC |
-				 NVOBJ_FLAG_ZERO_FREE, &grctx);
-	if (ret)
-		return ret;
-
-	hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
-	nv_wo32(ramin, hdr + 0x00, 0x00190002);
-	nv_wo32(ramin, hdr + 0x04, grctx->addr + grctx->size - 1);
-	nv_wo32(ramin, hdr + 0x08, grctx->addr);
-	nv_wo32(ramin, hdr + 0x0c, 0);
-	nv_wo32(ramin, hdr + 0x10, 0);
-	nv_wo32(ramin, hdr + 0x14, 0x00010000);
-
-	nv50_grctx_fill(dev, grctx);
-	nv_wo32(grctx, 0x00000, chan->ramin->addr >> 12);
-
-	nvimem_flush(dev);
-
-	nvvm_engref(chan->vm, engine, 1);
-	chan->engctx[NVOBJ_ENGINE_GR] = grctx;
-	return 0;
-}
-
-static void
-nv50_graph_context_del(struct nouveau_channel *chan, int engine)
-{
-	struct nouveau_gpuobj *grctx = chan->engctx[engine];
-	struct drm_device *dev = chan->dev;
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
-
-	for (i = hdr; i < hdr + 24; i += 4)
-		nv_wo32(chan->ramin, i, 0);
-	nvimem_flush(dev);
-
-	nvvm_engref(chan->vm, engine, -1);
-	nouveau_gpuobj_ref(NULL, &grctx);
-	chan->engctx[engine] = NULL;
-}
-
-static int
-nv50_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	struct drm_device *dev = chan->dev;
-	struct nouveau_gpuobj *obj = NULL;
+	struct nouveau_gpuobj *obj;
 	int ret;
 
-	ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+	ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
+				    16, 16, 0, &obj);
+	*pobject = nv_object(obj);
 	if (ret)
 		return ret;
-	obj->engine = 1;
-	obj->class  = class;
 
-	nv_wo32(obj, 0x00, class);
+	nv_wo32(obj, 0x00, nv_mclass(obj));
 	nv_wo32(obj, 0x04, 0x00000000);
 	nv_wo32(obj, 0x08, 0x00000000);
 	nv_wo32(obj, 0x0c, 0x00000000);
-	nvimem_flush(dev);
-
-	ret = nouveau_ramht_insert(chan, handle, obj);
-	nouveau_gpuobj_ref(NULL, &obj);
-	return ret;
+	return 0;
 }
 
-static void
-nv50_graph_tlb_flush(struct drm_device *dev, int engine)
+struct nouveau_ofuncs
+nv50_graph_ofuncs = {
+	.ctor = nv50_graph_object_ctor,
+	.dtor = _nouveau_gpuobj_dtor,
+	.init = _nouveau_gpuobj_init,
+	.fini = _nouveau_gpuobj_fini,
+	.rd32 = _nouveau_gpuobj_rd32,
+	.wr32 = _nouveau_gpuobj_wr32,
+};
+
+static struct nouveau_oclass
+nv50_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x5097, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nv84_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{ 0x8297, &nv50_graph_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nva0_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{ 0x8397, &nv50_graph_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nva3_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{ 0x8597, &nv50_graph_ofuncs },
+	{ 0x85c0, &nv50_graph_ofuncs },
+	{}
+};
+
+static struct nouveau_oclass
+nvaf_graph_sclass[] = {
+	{ 0x0030, &nv50_graph_ofuncs },
+	{ 0x502d, &nv50_graph_ofuncs },
+	{ 0x5039, &nv50_graph_ofuncs },
+	{ 0x50c0, &nv50_graph_ofuncs },
+	{ 0x85c0, &nv50_graph_ofuncs },
+	{ 0x8697, &nv50_graph_ofuncs },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv50_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *data, u32 size,
+			struct nouveau_object **pobject)
 {
-	nv50_vm_flush_engine(dev, 0);
+	struct nv50_graph_priv *priv = (void *)engine;
+	struct nv50_graph_chan *chan;
+	int ret;
+
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
+					   priv->size, 0,
+					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
+	if (ret)
+		return ret;
+
+	nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan));
+	return 0;
 }
 
-static void
-nv84_graph_tlb_flush(struct drm_device *dev, int engine)
+static struct nouveau_oclass
+nv50_graph_cclass = {
+	.handle = NV_ENGCTX(GR, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_graph_context_ctor,
+		.dtor = _nouveau_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 int
+nv50_graph_tlb_flush(struct nouveau_engine *engine)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	nv50_vm_flush_engine(&engine->base, 0x00);
+	return 0;
+}
+
+static int
+nv84_graph_tlb_flush(struct nouveau_engine *engine)
+{
+	struct nouveau_timer *ptimer = nouveau_timer(engine);
+	struct nv50_graph_priv *priv = (void *)engine;
 	bool idle, timeout = false;
 	unsigned long flags;
 	u64 start;
 	u32 tmp;
 
-	spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-	nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
+	spin_lock_irqsave(&priv->lock, flags);
+	nv_mask(priv, 0x400500, 0x00000001, 0x00000000);
 
-	start = nv_timer_read(dev);
+	start = ptimer->read(ptimer);
 	do {
 		idle = true;
 
-		for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
+		for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) {
 			if ((tmp & 7) == 1)
 				idle = false;
 		}
 
-		for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
+		for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) {
 			if ((tmp & 7) == 1)
 				idle = false;
 		}
 
-		for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
+		for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) {
 			if ((tmp & 7) == 1)
 				idle = false;
 		}
-	} while (!idle && !(timeout = nv_timer_read(dev) - start > 2000000000));
+	} while (!idle &&
+		 !(timeout = ptimer->read(ptimer) - start > 2000000000));
 
 	if (timeout) {
-		NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
+		nv_error(priv, "PGRAPH TLB flush idle timeout fail: "
 			      "0x%08x 0x%08x 0x%08x 0x%08x\n",
-			 nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
-			 nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
+			 nv_rd32(priv, 0x400700), nv_rd32(priv, 0x400380),
+			 nv_rd32(priv, 0x400384), nv_rd32(priv, 0x400388));
 	}
 
-	nv50_vm_flush_engine(dev, 0);
+	nv50_vm_flush_engine(&engine->base, 0x00);
 
-	nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+	nv_mask(priv, 0x400500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return timeout ? -EBUSY : 0;
 }
 
 static struct nouveau_enum nv50_mp_exec_error_names[] = {
@@ -341,7 +309,7 @@
 	{}
 };
 
-static struct nouveau_bitfield nv50_graph_intr[] = {
+static struct nouveau_bitfield nv50_graph_intr_name[] = {
 	{ 0x00000001, "NOTIFY" },
 	{ 0x00000002, "COMPUTE_QUERY" },
 	{ 0x00000010, "ILLEGAL_MTHD" },
@@ -356,95 +324,93 @@
 };
 
 static void
-nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
+nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	uint32_t units = nv_rd32(dev, 0x1540);
-	uint32_t addr, mp10, status, pc, oplow, ophigh;
+	u32 units = nv_rd32(priv, 0x1540);
+	u32 addr, mp10, status, pc, oplow, ophigh;
 	int i;
 	int mps = 0;
 	for (i = 0; i < 4; i++) {
 		if (!(units & 1 << (i+24)))
 			continue;
-		if (dev_priv->chipset < 0xa0)
+		if (nv_device(priv)->chipset < 0xa0)
 			addr = 0x408200 + (tpid << 12) + (i << 7);
 		else
 			addr = 0x408100 + (tpid << 11) + (i << 7);
-		mp10 = nv_rd32(dev, addr + 0x10);
-		status = nv_rd32(dev, addr + 0x14);
+		mp10 = nv_rd32(priv, addr + 0x10);
+		status = nv_rd32(priv, addr + 0x14);
 		if (!status)
 			continue;
 		if (display) {
-			nv_rd32(dev, addr + 0x20);
-			pc = nv_rd32(dev, addr + 0x24);
-			oplow = nv_rd32(dev, addr + 0x70);
-			ophigh = nv_rd32(dev, addr + 0x74);
-			NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
+			nv_rd32(priv, addr + 0x20);
+			pc = nv_rd32(priv, addr + 0x24);
+			oplow = nv_rd32(priv, addr + 0x70);
+			ophigh = nv_rd32(priv, addr + 0x74);
+			nv_error(priv, "TRAP_MP_EXEC - "
 					"TP %d MP %d: ", tpid, i);
 			nouveau_enum_print(nv50_mp_exec_error_names, status);
 			printk(" at %06x warp %d, opcode %08x %08x\n",
 					pc&0xffffff, pc >> 24,
 					oplow, ophigh);
 		}
-		nv_wr32(dev, addr + 0x10, mp10);
-		nv_wr32(dev, addr + 0x14, 0);
+		nv_wr32(priv, addr + 0x10, mp10);
+		nv_wr32(priv, addr + 0x14, 0);
 		mps++;
 	}
 	if (!mps && display)
-		NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: "
+		nv_error(priv, "TRAP_MP_EXEC - TP %d: "
 				"No MPs claiming errors?\n", tpid);
 }
 
 static void
-nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old,
-		uint32_t ustatus_new, int display, const char *name)
+nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
+		u32 ustatus_new, int display, const char *name)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
 	int tps = 0;
-	uint32_t units = nv_rd32(dev, 0x1540);
+	u32 units = nv_rd32(priv, 0x1540);
 	int i, r;
-	uint32_t ustatus_addr, ustatus;
+	u32 ustatus_addr, ustatus;
 	for (i = 0; i < 16; i++) {
 		if (!(units & (1 << i)))
 			continue;
-		if (dev_priv->chipset < 0xa0)
+		if (nv_device(priv)->chipset < 0xa0)
 			ustatus_addr = ustatus_old + (i << 12);
 		else
 			ustatus_addr = ustatus_new + (i << 11);
-		ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff;
+		ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff;
 		if (!ustatus)
 			continue;
 		tps++;
 		switch (type) {
 		case 6: /* texture error... unknown for now */
 			if (display) {
-				NV_ERROR(dev, "magic set %d:\n", i);
+				nv_error(priv, "magic set %d:\n", i);
 				for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
-					NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r,
-						nv_rd32(dev, r));
+					nv_error(priv, "\t0x%08x: 0x%08x\n", r,
+						nv_rd32(priv, r));
 			}
 			break;
 		case 7: /* MP error */
 			if (ustatus & 0x04030000) {
-				nv50_pgraph_mp_trap(dev, i, display);
+				nv50_priv_mp_trap(priv, i, display);
 				ustatus &= ~0x04030000;
 			}
 			break;
 		case 8: /* TPDMA error */
 			{
-			uint32_t e0c = nv_rd32(dev, ustatus_addr + 4);
-			uint32_t e10 = nv_rd32(dev, ustatus_addr + 8);
-			uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc);
-			uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10);
-			uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14);
-			uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18);
-			uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c);
+			u32 e0c = nv_rd32(priv, ustatus_addr + 4);
+			u32 e10 = nv_rd32(priv, ustatus_addr + 8);
+			u32 e14 = nv_rd32(priv, ustatus_addr + 0xc);
+			u32 e18 = nv_rd32(priv, ustatus_addr + 0x10);
+			u32 e1c = nv_rd32(priv, ustatus_addr + 0x14);
+			u32 e20 = nv_rd32(priv, ustatus_addr + 0x18);
+			u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c);
 			/* 2d engine destination */
 			if (ustatus & 0x00000010) {
 				if (display) {
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
+					nv_error(priv, "TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
 							i, e14, e10);
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+					nv_error(priv, "TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
 							i, e0c, e18, e1c, e20, e24);
 				}
 				ustatus &= ~0x00000010;
@@ -452,9 +418,9 @@
 			/* Render target */
 			if (ustatus & 0x00000040) {
 				if (display) {
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
+					nv_error(priv, "TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
 							i, e14, e10);
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+					nv_error(priv, "TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
 							i, e0c, e18, e1c, e20, e24);
 				}
 				ustatus &= ~0x00000040;
@@ -464,19 +430,19 @@
 				if (display) {
 					if (e18 & 0x80000000) {
 						/* g[] read fault? */
-						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
+						nv_error(priv, "TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
 								i, e14, e10 | ((e18 >> 24) & 0x1f));
 						e18 &= ~0x1f000000;
 					} else if (e18 & 0xc) {
 						/* g[] write fault? */
-						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
+						nv_error(priv, "TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
 								i, e14, e10 | ((e18 >> 7) & 0x1f));
 						e18 &= ~0x00000f80;
 					} else {
-						NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
+						nv_error(priv, "TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
 								i, e14, e10);
 					}
-					NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+					nv_error(priv, "TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
 							i, e0c, e18, e1c, e20, e24);
 				}
 				ustatus &= ~0x00000080;
@@ -486,23 +452,23 @@
 		}
 		if (ustatus) {
 			if (display)
-				NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
+				nv_info(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
 		}
-		nv_wr32(dev, ustatus_addr, 0xc0000000);
+		nv_wr32(priv, ustatus_addr, 0xc0000000);
 	}
 
 	if (!tps && display)
-		NV_INFO(dev, "%s - No TPs claiming errors?\n", name);
+		nv_info(priv, "%s - No TPs claiming errors?\n", name);
 }
 
 static int
-nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid)
+nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display, u64 inst)
 {
-	u32 status = nv_rd32(dev, 0x400108);
+	u32 status = nv_rd32(priv, 0x400108);
 	u32 ustatus;
 
 	if (!status && display) {
-		NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n");
+		nv_error(priv, "TRAP: no units reporting traps?\n");
 		return 1;
 	}
 
@@ -510,72 +476,72 @@
 	 * COND, QUERY. If you get a trap from it, the command is still stuck
 	 * in DISPATCH and you need to do something about it. */
 	if (status & 0x001) {
-		ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff;
+		ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff;
 		if (!ustatus && display) {
-			NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n");
+			nv_error(priv, "TRAP_DISPATCH - no ustatus?\n");
 		}
 
-		nv_wr32(dev, 0x400500, 0x00000000);
+		nv_wr32(priv, 0x400500, 0x00000000);
 
 		/* Known to be triggered by screwed up NOTIFY and COND... */
 		if (ustatus & 0x00000001) {
-			u32 addr = nv_rd32(dev, 0x400808);
+			u32 addr = nv_rd32(priv, 0x400808);
 			u32 subc = (addr & 0x00070000) >> 16;
 			u32 mthd = (addr & 0x00001ffc);
-			u32 datal = nv_rd32(dev, 0x40080c);
-			u32 datah = nv_rd32(dev, 0x400810);
-			u32 class = nv_rd32(dev, 0x400814);
-			u32 r848 = nv_rd32(dev, 0x400848);
+			u32 datal = nv_rd32(priv, 0x40080c);
+			u32 datah = nv_rd32(priv, 0x400810);
+			u32 class = nv_rd32(priv, 0x400814);
+			u32 r848 = nv_rd32(priv, 0x400848);
 
-			NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n");
+			nv_error(priv, "TRAP DISPATCH_FAULT\n");
 			if (display && (addr & 0x80000000)) {
-				NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) "
+				nv_error(priv, "ch 0x%010llx "
 					     "subc %d class 0x%04x mthd 0x%04x "
 					     "data 0x%08x%08x "
 					     "400808 0x%08x 400848 0x%08x\n",
-					chid, inst, subc, class, mthd, datah,
+					inst, subc, class, mthd, datah,
 					datal, addr, r848);
 			} else
 			if (display) {
-				NV_INFO(dev, "PGRAPH - no stuck command?\n");
+				nv_error(priv, "no stuck command?\n");
 			}
 
-			nv_wr32(dev, 0x400808, 0);
-			nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3);
-			nv_wr32(dev, 0x400848, 0);
+			nv_wr32(priv, 0x400808, 0);
+			nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3);
+			nv_wr32(priv, 0x400848, 0);
 			ustatus &= ~0x00000001;
 		}
 
 		if (ustatus & 0x00000002) {
-			u32 addr = nv_rd32(dev, 0x40084c);
+			u32 addr = nv_rd32(priv, 0x40084c);
 			u32 subc = (addr & 0x00070000) >> 16;
 			u32 mthd = (addr & 0x00001ffc);
-			u32 data = nv_rd32(dev, 0x40085c);
-			u32 class = nv_rd32(dev, 0x400814);
+			u32 data = nv_rd32(priv, 0x40085c);
+			u32 class = nv_rd32(priv, 0x400814);
 
-			NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n");
+			nv_error(priv, "TRAP DISPATCH_QUERY\n");
 			if (display && (addr & 0x80000000)) {
-				NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) "
+				nv_error(priv, "ch 0x%010llx "
 					     "subc %d class 0x%04x mthd 0x%04x "
 					     "data 0x%08x 40084c 0x%08x\n",
-					chid, inst, subc, class, mthd,
+					inst, subc, class, mthd,
 					data, addr);
 			} else
 			if (display) {
-				NV_INFO(dev, "PGRAPH - no stuck command?\n");
+				nv_error(priv, "no stuck command?\n");
 			}
 
-			nv_wr32(dev, 0x40084c, 0);
+			nv_wr32(priv, 0x40084c, 0);
 			ustatus &= ~0x00000002;
 		}
 
 		if (ustatus && display) {
-			NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown "
+			nv_error(priv, "TRAP_DISPATCH (unknown "
 				      "0x%08x)\n", ustatus);
 		}
 
-		nv_wr32(dev, 0x400804, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x001);
+		nv_wr32(priv, 0x400804, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x001);
 		status &= ~0x001;
 		if (!status)
 			return 0;
@@ -583,81 +549,81 @@
 
 	/* M2MF: Memory to memory copy engine. */
 	if (status & 0x002) {
-		u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff;
+		u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff;
 		if (display) {
-			NV_INFO(dev, "PGRAPH - TRAP_M2MF");
+			nv_error(priv, "TRAP_M2MF");
 			nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus);
 			printk("\n");
-			NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n",
-				nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808),
-				nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810));
+			nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808),
+				nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810));
 
 		}
 
 		/* No sane way found yet -- just reset the bugger. */
-		nv_wr32(dev, 0x400040, 2);
-		nv_wr32(dev, 0x400040, 0);
-		nv_wr32(dev, 0x406800, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x002);
+		nv_wr32(priv, 0x400040, 2);
+		nv_wr32(priv, 0x400040, 0);
+		nv_wr32(priv, 0x406800, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x002);
 		status &= ~0x002;
 	}
 
 	/* VFETCH: Fetches data from vertex buffers. */
 	if (status & 0x004) {
-		u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff;
+		u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff;
 		if (display) {
-			NV_INFO(dev, "PGRAPH - TRAP_VFETCH");
+			nv_error(priv, "TRAP_VFETCH");
 			nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus);
 			printk("\n");
-			NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n",
-				nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08),
-				nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10));
+			nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08),
+				nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10));
 		}
 
-		nv_wr32(dev, 0x400c04, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x004);
+		nv_wr32(priv, 0x400c04, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x004);
 		status &= ~0x004;
 	}
 
 	/* STRMOUT: DirectX streamout / OpenGL transform feedback. */
 	if (status & 0x008) {
-		ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff;
+		ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff;
 		if (display) {
-			NV_INFO(dev, "PGRAPH - TRAP_STRMOUT");
+			nv_error(priv, "TRAP_STRMOUT");
 			nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus);
 			printk("\n");
-			NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n",
-				nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808),
-				nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810));
+			nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n",
+				nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808),
+				nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810));
 
 		}
 
 		/* No sane way found yet -- just reset the bugger. */
-		nv_wr32(dev, 0x400040, 0x80);
-		nv_wr32(dev, 0x400040, 0);
-		nv_wr32(dev, 0x401800, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x008);
+		nv_wr32(priv, 0x400040, 0x80);
+		nv_wr32(priv, 0x400040, 0);
+		nv_wr32(priv, 0x401800, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x008);
 		status &= ~0x008;
 	}
 
 	/* CCACHE: Handles code and c[] caches and fills them. */
 	if (status & 0x010) {
-		ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff;
+		ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff;
 		if (display) {
-			NV_INFO(dev, "PGRAPH - TRAP_CCACHE");
+			nv_error(priv, "TRAP_CCACHE");
 			nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus);
 			printk("\n");
-			NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x"
+			nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x"
 				     " %08x %08x %08x\n",
-				nv_rd32(dev, 0x405000), nv_rd32(dev, 0x405004),
-				nv_rd32(dev, 0x405008), nv_rd32(dev, 0x40500c),
-				nv_rd32(dev, 0x405010), nv_rd32(dev, 0x405014),
-				nv_rd32(dev, 0x40501c));
+				nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004),
+				nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c),
+				nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014),
+				nv_rd32(priv, 0x40501c));
 
 		}
 
-		nv_wr32(dev, 0x405018, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x010);
+		nv_wr32(priv, 0x405018, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x010);
 		status &= ~0x010;
 	}
 
@@ -665,201 +631,248 @@
 	 * remaining, so try to handle it anyway. Perhaps related to that
 	 * unknown DMA slot on tesla? */
 	if (status & 0x20) {
-		ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff;
+		ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff;
 		if (display)
-			NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus);
-		nv_wr32(dev, 0x402000, 0xc0000000);
+			nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus);
+		nv_wr32(priv, 0x402000, 0xc0000000);
 		/* no status modifiction on purpose */
 	}
 
 	/* TEXTURE: CUDA texturing units */
 	if (status & 0x040) {
-		nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display,
-				    "PGRAPH - TRAP_TEXTURE");
-		nv_wr32(dev, 0x400108, 0x040);
+		nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display,
+				    "TRAP_TEXTURE");
+		nv_wr32(priv, 0x400108, 0x040);
 		status &= ~0x040;
 	}
 
 	/* MP: CUDA execution engines. */
 	if (status & 0x080) {
-		nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display,
-				    "PGRAPH - TRAP_MP");
-		nv_wr32(dev, 0x400108, 0x080);
+		nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display,
+				    "TRAP_MP");
+		nv_wr32(priv, 0x400108, 0x080);
 		status &= ~0x080;
 	}
 
 	/* TPDMA:  Handles TP-initiated uncached memory accesses:
 	 * l[], g[], stack, 2d surfaces, render targets. */
 	if (status & 0x100) {
-		nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display,
-				    "PGRAPH - TRAP_TPDMA");
-		nv_wr32(dev, 0x400108, 0x100);
+		nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display,
+				    "TRAP_TPDMA");
+		nv_wr32(priv, 0x400108, 0x100);
 		status &= ~0x100;
 	}
 
 	if (status) {
 		if (display)
-			NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status);
-		nv_wr32(dev, 0x400108, status);
+			nv_error(priv, "TRAP: unknown 0x%08x\n", status);
+		nv_wr32(priv, 0x400108, status);
 	}
 
 	return 1;
 }
 
-int
-nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		chan = dev_priv->channels.ptr[i];
-		if (!chan || !chan->ramin)
-			continue;
-
-		if (inst == chan->ramin->addr)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
-}
-
 static void
-nv50_graph_isr(struct drm_device *dev)
+nv50_graph_intr(struct nouveau_subdev *subdev)
 {
-	u32 stat;
+	struct nv50_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u32 stat = nv_rd32(priv, 0x400100);
+	u64 inst = (u64)(nv_rd32(priv, 0x40032c) & 0x0fffffff) << 12;
+	u32 addr = nv_rd32(priv, 0x400704);
+	u32 subc = (addr & 0x00070000) >> 16;
+	u32 mthd = (addr & 0x00001ffc);
+	u32 data = nv_rd32(priv, 0x400708);
+	u32 class = nv_rd32(priv, 0x400814);
+	u32 show = stat;
 
-	while ((stat = nv_rd32(dev, 0x400100))) {
-		u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12;
-		u32 chid = nv50_graph_isr_chid(dev, inst);
-		u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-		u32 subc = (addr & 0x00070000) >> 16;
-		u32 mthd = (addr & 0x00001ffc);
-		u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-		u32 class = nv_rd32(dev, 0x400814);
-		u32 show = stat;
-
-		if (stat & 0x00000010) {
-			if (!nouveau_gpuobj_mthd_call2(dev, chid, class,
-						       mthd, data))
-				show &= ~0x00000010;
-		}
-
-		show = (show && nouveau_ratelimit()) ? show : 0;
-
-		if (show & 0x00100000) {
-			u32 ecode = nv_rd32(dev, 0x400110);
-			NV_INFO(dev, "PGRAPH - DATA_ERROR ");
-			nouveau_enum_print(nv50_data_error_names, ecode);
-			printk("\n");
-		}
-
-		if (stat & 0x00200000) {
-			if (!nv50_pgraph_trap_handler(dev, show, inst, chid))
-				show &= ~0x00200000;
-		}
-
-		nv_wr32(dev, 0x400100, stat);
-		nv_wr32(dev, 0x400500, 0x00010001);
-
-		if (show) {
-			NV_INFO(dev, "PGRAPH -");
-			nouveau_bitfield_print(nv50_graph_intr, show);
-			printk("\n");
-			NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d "
-				     "class 0x%04x mthd 0x%04x data 0x%08x\n",
-				chid, inst, subc, class, mthd, data);
-			nv50_fb_vm_trap(dev, 1);
-		}
+	if (stat & 0x00000010) {
+		handle = nouveau_engctx_lookup_class(engine, inst, class);
+		if (handle && !nv_call(handle->object, mthd, data))
+			show &= ~0x00000010;
+		nouveau_engctx_handle_put(handle);
 	}
 
-	if (nv_rd32(dev, 0x400824) & (1 << 31))
-		nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
+	if (show & 0x00100000) {
+		u32 ecode = nv_rd32(priv, 0x400110);
+		nv_error(priv, "DATA_ERROR ");
+		nouveau_enum_print(nv50_data_error_names, ecode);
+		printk("\n");
+	}
+
+	if (stat & 0x00200000) {
+		if (!nv50_graph_trap_handler(priv, show, inst))
+			show &= ~0x00200000;
+	}
+
+	nv_wr32(priv, 0x400100, stat);
+	nv_wr32(priv, 0x400500, 0x00010001);
+
+	if (show) {
+		nv_info(priv, "");
+		nouveau_bitfield_print(nv50_graph_intr_name, show);
+		printk("\n");
+		nv_error(priv, "ch 0x%010llx subc %d class 0x%04x "
+			       "mthd 0x%04x data 0x%08x\n",
+			 inst, subc, class, mthd, data);
+		nv50_fb_trap(nouveau_fb(priv), 1);
+	}
+
+	if (nv_rd32(priv, 0x400824) & (1 << 31))
+		nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31));
 }
 
-static void
-nv50_graph_destroy(struct drm_device *dev, int engine)
+static int
+nv50_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-
-	nouveau_irq_unregister(dev, 12);
-	kfree(pgraph);
-}
-
-int
-nv50_graph_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nv50_graph_engine *pgraph;
+	struct nv50_graph_priv *priv;
 	int ret;
 
-	pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
-	if (!pgraph)
-		return -ENOMEM;
+	ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	ret = nv50_grctx_init(dev, pgraph->ctxprog, ARRAY_SIZE(pgraph->ctxprog),
-				  &pgraph->ctxprog_size,
-				  &pgraph->grctx_size);
-	if (ret) {
-		NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
-		kfree(pgraph);
-		return 0;
-	}
+	nv_subdev(priv)->unit = 0x00201000;
+	nv_subdev(priv)->intr = nv50_graph_intr;
+	nv_engine(priv)->cclass = &nv50_graph_cclass;
 
-	pgraph->base.destroy = nv50_graph_destroy;
-	pgraph->base.init = nv50_graph_init;
-	pgraph->base.fini = nv50_graph_fini;
-	pgraph->base.context_new = nv50_graph_context_new;
-	pgraph->base.context_del = nv50_graph_context_del;
-	pgraph->base.object_new = nv50_graph_object_new;
-	if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac)
-		pgraph->base.tlb_flush = nv50_graph_tlb_flush;
+	switch (nv_device(priv)->chipset) {
+	case 0x50:
+		nv_engine(priv)->sclass = nv50_graph_sclass;
+		break;
+	case 0x84:
+	case 0x86:
+	case 0x92:
+	case 0x94:
+	case 0x96:
+	case 0x98:
+		nv_engine(priv)->sclass = nv84_graph_sclass;
+		break;
+	case 0xa0:
+	case 0xaa:
+	case 0xac:
+		nv_engine(priv)->sclass = nva0_graph_sclass;
+		break;
+	case 0xa3:
+	case 0xa5:
+	case 0xa8:
+		nv_engine(priv)->sclass = nva3_graph_sclass;
+		break;
+	case 0xaf:
+		nv_engine(priv)->sclass = nvaf_graph_sclass;
+		break;
+
+	};
+
+	if (nv_device(priv)->chipset == 0x50 ||
+	    nv_device(priv)->chipset == 0xac)
+		nv_engine(priv)->tlb_flush = nv50_graph_tlb_flush;
 	else
-		pgraph->base.tlb_flush = nv84_graph_tlb_flush;
+		nv_engine(priv)->tlb_flush = nv84_graph_tlb_flush;
 
-	nouveau_irq_register(dev, 12, nv50_graph_isr);
+	spin_lock_init(&priv->lock);
+	return 0;
+}
 
-	NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-	NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-	NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
-	NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
+static int
+nv50_graph_init(struct nouveau_object *object)
+{
+	struct nv50_graph_priv *priv = (void *)object;
+	int ret, units, i;
 
-	/* tesla */
-	if (dev_priv->chipset == 0x50)
-		NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
-	else
-	if (dev_priv->chipset < 0xa0)
-		NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
-	else {
-		switch (dev_priv->chipset) {
-		case 0xa0:
-		case 0xaa:
-		case 0xac:
-			NVOBJ_CLASS(dev, 0x8397, GR);
-			break;
-		case 0xa3:
-		case 0xa5:
-		case 0xa8:
-			NVOBJ_CLASS(dev, 0x8597, GR);
-			break;
-		case 0xaf:
-			NVOBJ_CLASS(dev, 0x8697, GR);
-			break;
+	ret = nouveau_graph_init(&priv->base);
+	if (ret)
+		return ret;
+
+	/* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */
+	nv_wr32(priv, 0x40008c, 0x00000004);
+
+	/* reset/enable traps and interrupts */
+	nv_wr32(priv, 0x400804, 0xc0000000);
+	nv_wr32(priv, 0x406800, 0xc0000000);
+	nv_wr32(priv, 0x400c04, 0xc0000000);
+	nv_wr32(priv, 0x401800, 0xc0000000);
+	nv_wr32(priv, 0x405018, 0xc0000000);
+	nv_wr32(priv, 0x402000, 0xc0000000);
+
+	units = nv_rd32(priv, 0x001540);
+	for (i = 0; i < 16; i++) {
+		if (!(units & (1 << i)))
+			continue;
+
+		if (nv_device(priv)->chipset < 0xa0) {
+			nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000);
+			nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000);
+			nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000);
+		} else {
+			nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000);
+			nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000);
+			nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000);
 		}
 	}
 
-	/* compute */
-	NVOBJ_CLASS(dev, 0x50c0, GR);
-	if (dev_priv->chipset  > 0xa0 &&
-	    dev_priv->chipset != 0xaa &&
-	    dev_priv->chipset != 0xac)
-		NVOBJ_CLASS(dev, 0x85c0, GR);
+	nv_wr32(priv, 0x400108, 0xffffffff);
+	nv_wr32(priv, 0x400138, 0xffffffff);
+	nv_wr32(priv, 0x400100, 0xffffffff);
+	nv_wr32(priv, 0x40013c, 0xffffffff);
+	nv_wr32(priv, 0x400500, 0x00010001);
 
+	/* upload context program, initialise ctxctl defaults */
+	ret = nv50_grctx_init(nv_device(priv), &priv->size);
+	if (ret)
+		return ret;
+
+	nv_wr32(priv, 0x400824, 0x00000000);
+	nv_wr32(priv, 0x400828, 0x00000000);
+	nv_wr32(priv, 0x40082c, 0x00000000);
+	nv_wr32(priv, 0x400830, 0x00000000);
+	nv_wr32(priv, 0x400724, 0x00000000);
+	nv_wr32(priv, 0x40032c, 0x00000000);
+	nv_wr32(priv, 0x400320, 4);	/* CTXCTL_CMD = NEWCTXDMA */
+
+	/* some unknown zcull magic */
+	switch (nv_device(priv)->chipset & 0xf0) {
+	case 0x50:
+	case 0x80:
+	case 0x90:
+		nv_wr32(priv, 0x402ca8, 0x00000800);
+		break;
+	case 0xa0:
+	default:
+		nv_wr32(priv, 0x402cc0, 0x00000000);
+		if (nv_device(priv)->chipset == 0xa0 ||
+		    nv_device(priv)->chipset == 0xaa ||
+		    nv_device(priv)->chipset == 0xac) {
+			nv_wr32(priv, 0x402ca8, 0x00000802);
+		} else {
+			nv_wr32(priv, 0x402cc0, 0x00000000);
+			nv_wr32(priv, 0x402ca8, 0x00000002);
+		}
+
+		break;
+	}
+
+	/* zero out zcull regions */
+	for (i = 0; i < 8; i++) {
+		nv_wr32(priv, 0x402c20 + (i * 8), 0x00000000);
+		nv_wr32(priv, 0x402c24 + (i * 8), 0x00000000);
+		nv_wr32(priv, 0x402c28 + (i * 8), 0x00000000);
+		nv_wr32(priv, 0x402c2c + (i * 8), 0x00000000);
+	}
 	return 0;
 }
+
+struct nouveau_oclass
+nv50_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0x50),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nv50_graph_ctor,
+		.dtor = _nouveau_graph_dtor,
+		.init = nv50_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h
new file mode 100644
index 0000000..0505fb4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h
@@ -0,0 +1,7 @@
+#ifndef __NV50_GRAPH_H__
+#define __NV50_GRAPH_H__
+
+int  nv50_grctx_init(struct nouveau_device *, u32 *size);
+void nv50_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
index f994d2f..db8aefc 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * 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"),
@@ -22,94 +22,92 @@
  * Authors: Ben Skeggs
  */
 
-#include <linux/firmware.h>
-#include <linux/module.h>
-
-#include "drmP.h"
-
-#include "nouveau_drv.h"
-#include <core/mm.h>
-#include <engine/fifo.h>
-
 #include "nvc0.h"
 #include "fuc/hubnvc0.fuc.h"
 #include "fuc/gpcnvc0.fuc.h"
 
-static void
-nvc0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base)
-{
-	NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base,
-		nv_rd32(dev, base + 0x400));
-	NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804),
-		nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c));
-	NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814),
-		nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c));
-}
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
 
-void
-nvc0_graph_ctxctl_debug(struct drm_device *dev)
-{
-	u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff;
-	u32 gpc;
+static struct nouveau_oclass
+nvc0_graph_sclass[] = {
+	{ 0x902d, &nouveau_object_ofuncs },
+	{ 0x9039, &nouveau_object_ofuncs },
+	{ 0x9097, &nouveau_object_ofuncs },
+	{ 0x90c0, &nouveau_object_ofuncs },
+	{}
+};
 
-	nvc0_graph_ctxctl_debug_unit(dev, 0x409000);
-	for (gpc = 0; gpc < gpcnr; gpc++)
-		nvc0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000));
-}
+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 },
+	{}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
 
 int
-nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
+nvc0_graph_context_ctor(struct nouveau_object *parent,
+			struct nouveau_object *engine,
+			struct nouveau_oclass *oclass, void *args, u32 size,
+			struct nouveau_object **pobject)
 {
-	struct drm_device *dev = chan->dev;
-	struct nvc0_graph_priv *priv = nv_engine(dev, engine);
+	struct nouveau_vm *vm = nouveau_client(parent)->vm;
+	struct nvc0_graph_priv *priv = (void *)engine;
 	struct nvc0_graph_data *data = priv->mmio_data;
 	struct nvc0_graph_mmio *mmio = priv->mmio_list;
-	struct nvc0_graph_chan *grch;
-	struct nouveau_gpuobj *grctx;
+	struct nvc0_graph_chan *chan;
 	int ret, i;
 
-	grch = kzalloc(sizeof(*grch), GFP_KERNEL);
-	if (!grch)
-		return -ENOMEM;
-	chan->engctx[NVOBJ_ENGINE_GR] = grch;
-
-	ret = nouveau_gpuobj_new(dev, NULL, priv->size, 256, 0, &grch->grctx);
-	if (ret)
-		goto error;
-
-	ret = nouveau_gpuobj_map_vm(grch->grctx, chan->vm, NV_MEM_ACCESS_RW |
-				    NV_MEM_ACCESS_SYS, &grch->grctx_vma);
+	/* allocate memory for context, and fill with default values */
+	ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
+					   priv->size, 0x100,
+					   NVOBJ_FLAG_ZERO_ALLOC, &chan);
+	*pobject = nv_object(chan);
 	if (ret)
 		return ret;
 
-	grctx = grch->grctx;
-
 	/* allocate memory for a "mmio list" buffer that's used by the HUB
 	 * fuc to modify some per-context register settings on first load
 	 * of the context.
 	 */
-	ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x100, 0, &grch->mmio);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x100, 0, &chan->mmio);
 	if (ret)
 		return ret;
 
-	ret = nouveau_gpuobj_map_vm(grch->mmio, chan->vm,
+	ret = nouveau_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm,
 				    NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS,
-				    &grch->mmio_vma);
+				    &chan->mmio_vma);
 	if (ret)
 		return ret;
 
 	/* allocate buffers referenced by mmio list */
 	for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) {
-		ret = nouveau_gpuobj_new(dev, NULL, data->size, data->align,
-					 0, &grch->data[i].mem);
+		ret = nouveau_gpuobj_new(parent, NULL, data->size, data->align,
+					 0, &chan->data[i].mem);
 		if (ret)
 			return ret;
 
-		ret = nouveau_gpuobj_map_vm(grch->data[i].mem, chan->vm,
-					    data->access,
-					   &grch->data[i].vma);
+		ret = nouveau_gpuobj_map_vm(chan->data[i].mem, vm, data->access,
+					   &chan->data[i].vma);
 		if (ret)
 			return ret;
 
@@ -122,495 +120,193 @@
 		u32 data = mmio->data;
 
 		if (mmio->shift) {
-			u64 info = grch->data[mmio->buffer].vma.offset;
+			u64 info = chan->data[mmio->buffer].vma.offset;
 			data |= info >> mmio->shift;
 		}
 
-		nv_wo32(grch->mmio, grch->mmio_nr++ * 4, addr);
-		nv_wo32(grch->mmio, grch->mmio_nr++ * 4, data);
+		nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr);
+		nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data);
 		mmio++;
 	}
 
 	for (i = 0; i < priv->size; i += 4)
-		nv_wo32(grch->grctx, i, priv->data[i / 4]);
-
-	nv_wo32(chan->ramin, 0x0210, lower_32_bits(grch->grctx_vma.offset) | 4);
-	nv_wo32(chan->ramin, 0x0214, upper_32_bits(grch->grctx_vma.offset));
-	nvimem_flush(dev);
+		nv_wo32(chan, i, priv->data[i / 4]);
 
 	if (!priv->firmware) {
-		nv_wo32(grctx, 0x00, grch->mmio_nr / 2);
-		nv_wo32(grctx, 0x04, grch->mmio_vma.offset >> 8);
+		nv_wo32(chan, 0x00, chan->mmio_nr / 2);
+		nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8);
 	} else {
-		nv_wo32(grctx, 0xf4, 0);
-		nv_wo32(grctx, 0xf8, 0);
-		nv_wo32(grctx, 0x10, grch->mmio_nr / 2);
-		nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio_vma.offset));
-		nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio_vma.offset));
-		nv_wo32(grctx, 0x1c, 1);
-		nv_wo32(grctx, 0x20, 0);
-		nv_wo32(grctx, 0x28, 0);
-		nv_wo32(grctx, 0x2c, 0);
+		nv_wo32(chan, 0xf4, 0);
+		nv_wo32(chan, 0xf8, 0);
+		nv_wo32(chan, 0x10, chan->mmio_nr / 2);
+		nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset));
+		nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset));
+		nv_wo32(chan, 0x1c, 1);
+		nv_wo32(chan, 0x20, 0);
+		nv_wo32(chan, 0x28, 0);
+		nv_wo32(chan, 0x2c, 0);
 	}
-	nvimem_flush(dev);
-	return 0;
 
-error:
-	priv->base.context_del(chan, engine);
-	return ret;
+	return 0;
 }
 
 void
-nvc0_graph_context_del(struct nouveau_channel *chan, int engine)
+nvc0_graph_context_dtor(struct nouveau_object *object)
 {
-	struct nvc0_graph_chan *grch = chan->engctx[engine];
+	struct nvc0_graph_chan *chan = (void *)object;
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(grch->data); i++) {
-		nouveau_gpuobj_unmap(&grch->data[i].vma);
-		nouveau_gpuobj_ref(NULL, &grch->data[i].mem);
+	for (i = 0; i < ARRAY_SIZE(chan->data); i++) {
+		nouveau_gpuobj_unmap(&chan->data[i].vma);
+		nouveau_gpuobj_ref(NULL, &chan->data[i].mem);
 	}
 
-	nouveau_gpuobj_unmap(&grch->mmio_vma);
-	nouveau_gpuobj_ref(NULL, &grch->mmio);
+	nouveau_gpuobj_unmap(&chan->mmio_vma);
+	nouveau_gpuobj_ref(NULL, &chan->mmio);
 
-	nouveau_gpuobj_unmap(&grch->grctx_vma);
-	nouveau_gpuobj_ref(NULL, &grch->grctx);
-	chan->engctx[engine] = NULL;
+	nouveau_graph_context_destroy(&chan->base);
 }
 
-static int
-nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
+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)
 {
-	return 0;
+	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));
 }
 
-static int
-nvc0_graph_fini(struct drm_device *dev, int engine, bool suspend)
+void
+nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv)
 {
-	return 0;
+	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_init_obj418880(struct drm_device *dev)
+nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
 {
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int i;
-
-	nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
-	nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-}
-
-static void
-nvc0_graph_init_regs(struct drm_device *dev)
-{
-	nv_wr32(dev, 0x400080, 0x003083c2);
-	nv_wr32(dev, 0x400088, 0x00006fe7);
-	nv_wr32(dev, 0x40008c, 0x00000000);
-	nv_wr32(dev, 0x400090, 0x00000030);
-	nv_wr32(dev, 0x40013c, 0x013901f7);
-	nv_wr32(dev, 0x400140, 0x00000100);
-	nv_wr32(dev, 0x400144, 0x00000000);
-	nv_wr32(dev, 0x400148, 0x00000110);
-	nv_wr32(dev, 0x400138, 0x00000000);
-	nv_wr32(dev, 0x400130, 0x00000000);
-	nv_wr32(dev, 0x400134, 0x00000000);
-	nv_wr32(dev, 0x400124, 0x00000002);
-}
-
-static void
-nvc0_graph_init_gpc_0(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
-	u32 data[TPC_MAX / 8];
-	u8  tpnr[GPC_MAX];
-	int i, gpc, tpc;
-
-	nv_wr32(dev, 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(tpnr, 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 (!tpnr[gpc]);
-		tpc = priv->tpc_nr[gpc] - tpnr[gpc]--;
-
-		data[i / 8] |= tpc << ((i % 8) * 4);
-	}
-
-	nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
-						  priv->tpc_nr[gpc]);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918);
-	nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800));
-}
-
-static void
-nvc0_graph_init_units(struct drm_device *dev)
-{
-	nv_wr32(dev, 0x409c24, 0x000f0000);
-	nv_wr32(dev, 0x404000, 0xc0000000); /* DISPATCH */
-	nv_wr32(dev, 0x404600, 0xc0000000); /* M2MF */
-	nv_wr32(dev, 0x408030, 0xc0000000);
-	nv_wr32(dev, 0x40601c, 0xc0000000);
-	nv_wr32(dev, 0x404490, 0xc0000000); /* MACRO */
-	nv_wr32(dev, 0x406018, 0xc0000000);
-	nv_wr32(dev, 0x405840, 0xc0000000);
-	nv_wr32(dev, 0x405844, 0x00ffffff);
-	nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008);
-	nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000);
-}
-
-static void
-nvc0_graph_init_gpc_1(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int gpc, tp;
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tp = 0; tp < priv->tpc_nr[gpc]; tp++) {
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x508), 0xffffffff);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x50c), 0xffffffff);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x224), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x48c), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x084), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x644), 0x001ffffe);
-			nv_wr32(dev, TPC_UNIT(gpc, tp, 0x64c), 0x0000000f);
-		}
-		nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-}
-
-static void
-nvc0_graph_init_rop(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int rop;
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
-		nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
-		nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-}
-
-static void
-nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
-		    struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
-{
-	int i;
-
-	nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
-	for (i = 0; i < data->size / 4; i++)
-		nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
-
-	nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
-	for (i = 0; i < code->size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, fuc_base + 0x0188, i >> 6);
-		nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
-	}
-}
-
-static int
-nvc0_graph_init_ctxctl(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	u32 r000260;
-	int i;
-
-	if (priv->firmware) {
-		/* load fuc microcode */
-		r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-		nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c,
-						   &priv->fuc409d);
-		nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac,
-						   &priv->fuc41ad);
-		nv_wr32(dev, 0x000260, r000260);
-
-		/* start both of them running */
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x41a10c, 0x00000000);
-		nv_wr32(dev, 0x40910c, 0x00000000);
-		nv_wr32(dev, 0x41a100, 0x00000002);
-		nv_wr32(dev, 0x409100, 0x00000002);
-		if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001))
-			NV_INFO(dev, "0x409800 wait failed\n");
-
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x409500, 0x7fffffff);
-		nv_wr32(dev, 0x409504, 0x00000021);
-
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x409500, 0x00000000);
-		nv_wr32(dev, 0x409504, 0x00000010);
-		if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-			NV_ERROR(dev, "fuc09 req 0x10 timeout\n");
-			return -EBUSY;
-		}
-		priv->size = nv_rd32(dev, 0x409800);
-
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x409500, 0x00000000);
-		nv_wr32(dev, 0x409504, 0x00000016);
-		if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-			NV_ERROR(dev, "fuc09 req 0x16 timeout\n");
-			return -EBUSY;
-		}
-
-		nv_wr32(dev, 0x409840, 0xffffffff);
-		nv_wr32(dev, 0x409500, 0x00000000);
-		nv_wr32(dev, 0x409504, 0x00000025);
-		if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-			NV_ERROR(dev, "fuc09 req 0x25 timeout\n");
-			return -EBUSY;
-		}
-
-		goto done;
-	}
-
-	/* load HUB microcode */
-	r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-	nv_wr32(dev, 0x4091c0, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++)
-		nv_wr32(dev, 0x4091c4, nvc0_grhub_data[i]);
-
-	nv_wr32(dev, 0x409180, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, 0x409188, i >> 6);
-		nv_wr32(dev, 0x409184, nvc0_grhub_code[i]);
-	}
-
-	/* load GPC microcode */
-	nv_wr32(dev, 0x41a1c0, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++)
-		nv_wr32(dev, 0x41a1c4, nvc0_grgpc_data[i]);
-
-	nv_wr32(dev, 0x41a180, 0x01000000);
-	for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, 0x41a188, i >> 6);
-		nv_wr32(dev, 0x41a184, nvc0_grgpc_code[i]);
-	}
-	nv_wr32(dev, 0x000260, r000260);
-
-	/* start HUB ucode running, it'll init the GPCs */
-	nv_wr32(dev, 0x409800, dev_priv->chipset);
-	nv_wr32(dev, 0x40910c, 0x00000000);
-	nv_wr32(dev, 0x409100, 0x00000002);
-	if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) {
-		NV_ERROR(dev, "PGRAPH: HUB_INIT timed out\n");
-		nvc0_graph_ctxctl_debug(dev);
-		return -EBUSY;
-	}
-
-	priv->size = nv_rd32(dev, 0x409804);
-done:
-	if (priv->data == NULL) {
-		int ret = nvc0_grctx_generate(dev);
-		if (ret) {
-			NV_ERROR(dev, "PGRAPH: failed to construct context\n");
-			return ret;
-		}
-
-		return 1;
-	}
-
-	return 0;
-}
-
-static int
-nvc0_graph_init(struct drm_device *dev, int engine)
-{
-	int ret;
-
-reset:
-	nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
-
-	nvc0_graph_init_obj418880(dev);
-	nvc0_graph_init_regs(dev);
-	/*nvc0_graph_init_unitplemented_magics(dev);*/
-	nvc0_graph_init_gpc_0(dev);
-	/*nvc0_graph_init_unitplemented_c242(dev);*/
-
-	nv_wr32(dev, 0x400500, 0x00010001);
-	nv_wr32(dev, 0x400100, 0xffffffff);
-	nv_wr32(dev, 0x40013c, 0xffffffff);
-
-	nvc0_graph_init_units(dev);
-	nvc0_graph_init_gpc_1(dev);
-	nvc0_graph_init_rop(dev);
-
-	nv_wr32(dev, 0x400108, 0xffffffff);
-	nv_wr32(dev, 0x400138, 0xffffffff);
-	nv_wr32(dev, 0x400118, 0xffffffff);
-	nv_wr32(dev, 0x400130, 0xffffffff);
-	nv_wr32(dev, 0x40011c, 0xffffffff);
-	nv_wr32(dev, 0x400134, 0xffffffff);
-	nv_wr32(dev, 0x400054, 0x34ce3464);
-
-	ret = nvc0_graph_init_ctxctl(dev);
-	if (ret) {
-		if (ret == 1)
-			goto reset;
-		return ret;
-	}
-
-	return 0;
-}
-
-int
-nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		chan = dev_priv->channels.ptr[i];
-		if (!chan || !chan->ramin)
-			continue;
-
-		if (inst == chan->ramin->addr)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
-}
-
-static void
-nvc0_graph_ctxctl_isr(struct drm_device *dev)
-{
-	u32 ustat = nv_rd32(dev, 0x409c18);
+	u32 ustat = nv_rd32(priv, 0x409c18);
 
 	if (ustat & 0x00000001)
-		NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n");
+		nv_error(priv, "CTXCTRL ucode error\n");
 	if (ustat & 0x00080000)
-		NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n");
+		nv_error(priv, "CTXCTRL watchdog timeout\n");
 	if (ustat & ~0x00080001)
-		NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat);
+		nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
 
-	nvc0_graph_ctxctl_debug(dev);
-	nv_wr32(dev, 0x409c20, ustat);
+	nvc0_graph_ctxctl_debug(priv);
+	nv_wr32(priv, 0x409c20, ustat);
 }
 
 static void
-nvc0_graph_isr(struct drm_device *dev)
+nvc0_graph_intr(struct nouveau_subdev *subdev)
 {
-	u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
-	u32 chid = nvc0_graph_isr_chid(dev, inst);
-	u32 stat = nv_rd32(dev, 0x400100);
-	u32 addr = nv_rd32(dev, 0x400704);
+	struct nvc0_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u64 inst = (u64)(nv_rd32(priv, 0x409b00) & 0x0fffffff) << 12;
+	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(dev, 0x400708);
-	u32 code = nv_rd32(dev, 0x400110);
-	u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
+	u32 data = nv_rd32(priv, 0x400708);
+	u32 code = nv_rd32(priv, 0x400110);
+	u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
 
 	if (stat & 0x00000010) {
-		if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) {
-			NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] "
+		handle = nouveau_engctx_lookup_class(engine, inst, class);
+		if (!handle || nv_call(handle->object, mthd, data)) {
+			nv_error(priv, "ILLEGAL_MTHD ch 0x%010llx "
 				     "subc %d class 0x%04x mthd 0x%04x "
 				     "data 0x%08x\n",
-				chid, inst, subc, class, mthd, data);
+				 inst, subc, class, mthd, data);
 		}
-		nv_wr32(dev, 0x400100, 0x00000010);
+		nouveau_engctx_handle_put(handle);
+		nv_wr32(priv, 0x400100, 0x00000010);
 		stat &= ~0x00000010;
 	}
 
 	if (stat & 0x00000020) {
-		NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
+		nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d "
 			     "class 0x%04x mthd 0x%04x data 0x%08x\n",
-			chid, inst, subc, class, mthd, data);
-		nv_wr32(dev, 0x400100, 0x00000020);
+			inst, subc, class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00000020);
 		stat &= ~0x00000020;
 	}
 
 	if (stat & 0x00100000) {
-		NV_INFO(dev, "PGRAPH: DATA_ERROR [");
+		nv_error(priv, "DATA_ERROR [");
 		nouveau_enum_print(nv50_data_error_names, code);
-		printk("] ch %d [0x%010llx] subc %d class 0x%04x "
+		printk("] ch 0x%010llx subc %d class 0x%04x "
 		       "mthd 0x%04x data 0x%08x\n",
-		       chid, inst, subc, class, mthd, data);
-		nv_wr32(dev, 0x400100, 0x00100000);
+		       inst, subc, class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00100000);
 		stat &= ~0x00100000;
 	}
 
 	if (stat & 0x00200000) {
-		u32 trap = nv_rd32(dev, 0x400108);
-		NV_INFO(dev, "PGRAPH: TRAP ch %d status 0x%08x\n", chid, trap);
-		nv_wr32(dev, 0x400108, trap);
-		nv_wr32(dev, 0x400100, 0x00200000);
+		u32 trap = nv_rd32(priv, 0x400108);
+		nv_error(priv, "TRAP ch 0x%010llx status 0x%08x\n", inst, trap);
+		nv_wr32(priv, 0x400108, trap);
+		nv_wr32(priv, 0x400100, 0x00200000);
 		stat &= ~0x00200000;
 	}
 
 	if (stat & 0x00080000) {
-		nvc0_graph_ctxctl_isr(dev);
-		nv_wr32(dev, 0x400100, 0x00080000);
+		nvc0_graph_ctxctl_isr(priv);
+		nv_wr32(priv, 0x400100, 0x00080000);
 		stat &= ~0x00080000;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat);
-		nv_wr32(dev, 0x400100, stat);
+		nv_error(priv, "unknown stat 0x%08x\n", stat);
+		nv_wr32(priv, 0x400100, stat);
 	}
 
-	nv_wr32(dev, 0x400500, 0x00010001);
+	nv_wr32(priv, 0x400500, 0x00010001);
 }
 
-static int
-nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
-		     struct nvc0_graph_fuc *fuc)
+int
+nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
+		   struct nvc0_graph_fuc *fuc)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_device *device = nv_device(priv);
 	const struct firmware *fw;
 	char f[32];
 	int ret;
 
-	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
-	ret = request_firmware(&fw, f, &dev->pdev->dev);
+	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
+	ret = request_firmware(&fw, f, &device->pdev->dev);
 	if (ret) {
 		snprintf(f, sizeof(f), "nouveau/%s", fwname);
-		ret = request_firmware(&fw, f, &dev->pdev->dev);
+		ret = request_firmware(&fw, f, &device->pdev->dev);
 		if (ret) {
-			NV_ERROR(dev, "failed to load %s\n", fwname);
+			nv_error(priv, "failed to load %s\n", fwname);
 			return ret;
 		}
 	}
@@ -621,99 +317,77 @@
 	return (fuc->data != NULL) ? 0 : -ENOMEM;
 }
 
-static void
-nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
+static int
+nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+		struct nouveau_oclass *oclass, void *data, u32 size,
+		struct nouveau_object **pobject)
 {
-	if (fuc->data) {
-		kfree(fuc->data);
-		fuc->data = NULL;
-	}
-}
-
-static void
-nvc0_graph_destroy(struct drm_device *dev, int engine)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, engine);
-
-	nvc0_graph_destroy_fw(&priv->fuc409c);
-	nvc0_graph_destroy_fw(&priv->fuc409d);
-	nvc0_graph_destroy_fw(&priv->fuc41ac);
-	nvc0_graph_destroy_fw(&priv->fuc41ad);
-
-	nouveau_irq_unregister(dev, 12);
-
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
-	if (priv->data)
-		kfree(priv->data);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(priv);
-}
-
-int
-nvc0_graph_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
+	struct nouveau_device *device = nv_device(parent);
 	struct nvc0_graph_priv *priv;
-	int ret, gpc, i;
-	u32 fermi;
+	bool enable = true;
+	int ret, i;
 
-	fermi = nvc0_graph_class(dev);
-	if (!fermi) {
-		NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
-		return 0;
+	switch (device->chipset) {
+	case 0xd9: /* known broken without binary driver firmware */
+		enable = false;
+		break;
+	default:
+		break;
 	}
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	ret = nouveau_graph_create(parent, engine, oclass, enable, &priv);
+	*pobject = nv_object(priv);
+	if (ret)
+		return ret;
 
-	priv->base.destroy = nvc0_graph_destroy;
-	priv->base.init = nvc0_graph_init;
-	priv->base.fini = nvc0_graph_fini;
-	priv->base.context_new = nvc0_graph_context_new;
-	priv->base.context_del = nvc0_graph_context_del;
-	priv->base.object_new = nvc0_graph_object_new;
+	nv_subdev(priv)->unit = 0x18001000;
+	nv_subdev(priv)->intr = nvc0_graph_intr;
+	nv_engine(priv)->cclass = &nvc0_graph_cclass;
 
-	NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
-	nouveau_irq_register(dev, 12, nvc0_graph_isr);
-
-	if (nouveau_ctxfw) {
-		NV_INFO(dev, "PGRAPH: using external firmware\n");
-		if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
-		    nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
-		    nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
-		    nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
-			ret = 0;
-			goto error;
-		}
+	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(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
-	if (ret)
-		goto error;
+	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(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4);
 	if (ret)
-		goto error;
+		return ret;
+
+	ret = nouveau_gpuobj_new(parent, 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(dev, 0x409604) & 0x0000001f;
-	priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		priv->tpc_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
-		priv->tpc_total += priv->tpc_nr[gpc];
+	priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
+	priv->gpc_nr =  nv_rd32(priv, 0x409604) & 0x0000001f;
+	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];
 	}
 
-	/*XXX: these need figuring out... */
-	switch (dev_priv->chipset) {
+	/*XXX: these need figuring out... though it might not even matter */
+	switch (nv_device(priv)->chipset) {
 	case 0xc0:
 		if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
 			priv->magic_not_rop_nr = 0x07;
@@ -748,24 +422,348 @@
 		break;
 	}
 
-	if (!priv->magic_not_rop_nr) {
-		NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
-			 priv->tpc_nr[0], priv->tpc_nr[1], priv->tpc_nr[2],
-			 priv->tpc_nr[3], priv->rop_nr);
-		priv->magic_not_rop_nr = 0x00;
+	return 0;
+}
+
+static void
+nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
+{
+	if (fuc->data) {
+		kfree(fuc->data);
+		fuc->data = NULL;
+	}
+}
+
+void
+nvc0_graph_dtor(struct nouveau_object *object)
+{
+	struct nvc0_graph_priv *priv = (void *)object;
+
+	if (priv->data)
+		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);
+}
+
+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);
 	}
 
-	NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
-	NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
-	NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
-	if (fermi >= 0x9197)
-		NVOBJ_CLASS(dev, 0x9197, GR); /* 3D (NVC1-) */
-	if (fermi >= 0x9297)
-		NVOBJ_CLASS(dev, 0x9297, GR); /* 3D (NVC8-) */
-	NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
-	return 0;
+	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]);
 
-error:
-	nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
-	return ret;
+	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_info(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 1;
+	}
+
+	return 0;
+}
+
+static int
+nvc0_graph_init(struct nouveau_object *object)
+{
+	struct nvc0_graph_priv *priv = (void *)object;
+	int ret;
+
+reset:
+	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) {
+		if (ret == 1)
+			goto reset;
+		return ret;
+	}
+
+	return 0;
+}
+
+struct nouveau_oclass
+nvc0_graph_oclass = {
+	.handle = NV_ENGINE(GR, 0xc0),
+	.ofuncs = &(struct nouveau_ofuncs) {
+		.ctor = nvc0_graph_ctor,
+		.dtor = nvc0_graph_dtor,
+		.init = nvc0_graph_init,
+		.fini = _nouveau_graph_fini,
+	},
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
index 30ea3ab..26f8268 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
@@ -25,6 +25,18 @@
 #ifndef __NVC0_GRAPH_H__
 #define __NVC0_GRAPH_H__
 
+#include <core/client.h>
+#include <core/handle.h>
+#include <core/gpuobj.h>
+#include <core/option.h>
+
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+#include <subdev/bar.h>
+#include <subdev/timer.h>
+
+#include <engine/graph.h>
+
 #define GPC_MAX 4
 #define TPC_MAX 32
 
@@ -53,7 +65,7 @@
 };
 
 struct nvc0_graph_priv {
-	struct nouveau_exec_engine base;
+	struct nouveau_graph base;
 
 	struct nvc0_graph_fuc fuc409c;
 	struct nvc0_graph_fuc fuc409d;
@@ -78,11 +90,10 @@
 };
 
 struct nvc0_graph_chan {
-	struct nouveau_gpuobj *grctx;
-	struct nouveau_vma     grctx_vma;
+	struct nouveau_graph_chan base;
 
 	struct nouveau_gpuobj *mmio;
-	struct nouveau_vma     mmio_vma;
+	struct nouveau_vma mmio_vma;
 	int mmio_nr;
 	struct {
 		struct nouveau_gpuobj *mem;
@@ -91,11 +102,11 @@
 };
 
 static inline u32
-nvc0_graph_class(struct drm_device *priv)
+nvc0_graph_class(void *obj)
 {
-	struct drm_nouveau_private *dev_priv = priv->dev_private;
+	struct nouveau_device *device = nv_device(obj);
 
-	switch (dev_priv->chipset) {
+	switch (device->chipset) {
 	case 0xc0:
 	case 0xc3:
 	case 0xc4:
@@ -115,17 +126,16 @@
 	}
 }
 
-void nv_icmd(struct drm_device *priv, u32 icmd, u32 data);
+void nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data);
 
 static inline void
-nv_mthd(struct drm_device *priv, u32 class, u32 mthd, u32 data)
+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 drm_device *dev;
 	struct nvc0_graph_priv *priv;
 	struct nvc0_graph_data *data;
 	struct nvc0_graph_mmio *mmio;
@@ -135,18 +145,18 @@
 	u64 addr;
 };
 
-int  nvc0_grctx_generate(struct drm_device *);
-int  nvc0_grctx_init(struct drm_device *, struct nvc0_graph_priv *,
-		     struct nvc0_grctx *);
+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 drm_device *);
+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 *);
@@ -157,9 +167,4 @@
 			     struct nouveau_object **);
 void nvc0_graph_context_dtor(struct nouveau_object *);
 
-void nvc0_graph_ctxctl_debug(struct drm_device *);
-
-int  nvc0_graph_context_new(struct nouveau_channel *, int);
-void nvc0_graph_context_del(struct nouveau_channel *, int);
-
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
index a3a4ee7..c79748a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2010 Red Hat Inc.
+ * 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"),
@@ -22,586 +22,213 @@
  * Authors: Ben Skeggs
  */
 
-#include <linux/firmware.h>
-#include <linux/module.h>
-
-#include "drmP.h"
-
-#include "nouveau_drv.h"
-#include <core/mm.h>
-#include <engine/fifo.h>
-
 #include "nvc0.h"
 
-static void
-nve0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base)
-{
-	NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base,
-		nv_rd32(dev, base + 0x400));
-	NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804),
-		nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c));
-	NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
-		nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814),
-		nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c));
-}
+/*******************************************************************************
+ * 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_debug(struct drm_device *dev)
+nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
 {
-	u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff;
-	u32 gpc;
-
-	nve0_graph_ctxctl_debug_unit(dev, 0x409000);
-	for (gpc = 0; gpc < gpcnr; gpc++)
-		nve0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000));
-}
-
-static int
-nve0_graph_object_new(struct nouveau_channel *chan, int engine,
-		      u32 handle, u16 class)
-{
-	return 0;
-}
-
-static int
-nve0_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-	return 0;
-}
-
-static void
-nve0_graph_init_obj418880(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int i;
-
-	nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
-	nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000);
-	for (i = 0; i < 4; i++)
-		nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
-	nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
-	nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-}
-
-static void
-nve0_graph_init_regs(struct drm_device *dev)
-{
-	nv_wr32(dev, 0x400080, 0x003083c2);
-	nv_wr32(dev, 0x400088, 0x0001ffe7);
-	nv_wr32(dev, 0x40008c, 0x00000000);
-	nv_wr32(dev, 0x400090, 0x00000030);
-	nv_wr32(dev, 0x40013c, 0x003901f7);
-	nv_wr32(dev, 0x400140, 0x00000100);
-	nv_wr32(dev, 0x400144, 0x00000000);
-	nv_wr32(dev, 0x400148, 0x00000110);
-	nv_wr32(dev, 0x400138, 0x00000000);
-	nv_wr32(dev, 0x400130, 0x00000000);
-	nv_wr32(dev, 0x400134, 0x00000000);
-	nv_wr32(dev, 0x400124, 0x00000002);
-}
-
-static void
-nve0_graph_init_units(struct drm_device *dev)
-{
-	nv_wr32(dev, 0x409ffc, 0x00000000);
-	nv_wr32(dev, 0x409c14, 0x00003e3e);
-	nv_wr32(dev, 0x409c24, 0x000f0000);
-
-	nv_wr32(dev, 0x404000, 0xc0000000);
-	nv_wr32(dev, 0x404600, 0xc0000000);
-	nv_wr32(dev, 0x408030, 0xc0000000);
-	nv_wr32(dev, 0x404490, 0xc0000000);
-	nv_wr32(dev, 0x406018, 0xc0000000);
-	nv_wr32(dev, 0x407020, 0xc0000000);
-	nv_wr32(dev, 0x405840, 0xc0000000);
-	nv_wr32(dev, 0x405844, 0x00ffffff);
-
-	nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008);
-	nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000);
-
-}
-
-static void
-nve0_graph_init_gpc_0(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	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(dev, 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(dev, GPC_BCAST(0x0980), data[0]);
-	nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
-	nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
-	nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
-						  priv->tpc_nr[gpc]);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0918), magicgpc918);
-	}
-
-	nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918);
-	nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800));
-}
-
-static void
-nve0_graph_init_gpc_1(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int gpc, tpc;
-
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		nv_wr32(dev, GPC_UNIT(gpc, 0x3038), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000);
-		for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
-			nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
-		}
-		nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
-		nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
-	}
-}
-
-static void
-nve0_graph_init_rop(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	int rop;
-
-	for (rop = 0; rop < priv->rop_nr; rop++) {
-		nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
-		nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
-		nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff);
-		nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff);
-	}
-}
-
-static void
-nve0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
-		    struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
-{
-	int i;
-
-	nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
-	for (i = 0; i < data->size / 4; i++)
-		nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
-
-	nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
-	for (i = 0; i < code->size / 4; i++) {
-		if ((i & 0x3f) == 0)
-			nv_wr32(dev, fuc_base + 0x0188, i >> 6);
-		nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
-	}
-}
-
-static int
-nve0_graph_init_ctxctl(struct drm_device *dev)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	u32 r000260;
-
-	/* load fuc microcode */
-	r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-	nve0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
-	nve0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
-	nv_wr32(dev, 0x000260, r000260);
-
-	/* start both of them running */
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x41a10c, 0x00000000);
-	nv_wr32(dev, 0x40910c, 0x00000000);
-	nv_wr32(dev, 0x41a100, 0x00000002);
-	nv_wr32(dev, 0x409100, 0x00000002);
-	if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001))
-		NV_INFO(dev, "0x409800 wait failed\n");
-
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x409500, 0x7fffffff);
-	nv_wr32(dev, 0x409504, 0x00000021);
-
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x409500, 0x00000000);
-	nv_wr32(dev, 0x409504, 0x00000010);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x10 timeout\n");
-		return -EBUSY;
-	}
-	priv->size = nv_rd32(dev, 0x409800);
-
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x409500, 0x00000000);
-	nv_wr32(dev, 0x409504, 0x00000016);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x16 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409840, 0xffffffff);
-	nv_wr32(dev, 0x409500, 0x00000000);
-	nv_wr32(dev, 0x409504, 0x00000025);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x25 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409800, 0x00000000);
-	nv_wr32(dev, 0x409500, 0x00000001);
-	nv_wr32(dev, 0x409504, 0x00000030);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x30 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409810, 0xb00095c8);
-	nv_wr32(dev, 0x409800, 0x00000000);
-	nv_wr32(dev, 0x409500, 0x00000001);
-	nv_wr32(dev, 0x409504, 0x00000031);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x31 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409810, 0x00080420);
-	nv_wr32(dev, 0x409800, 0x00000000);
-	nv_wr32(dev, 0x409500, 0x00000001);
-	nv_wr32(dev, 0x409504, 0x00000032);
-	if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
-		NV_ERROR(dev, "fuc09 req 0x32 timeout\n");
-		return -EBUSY;
-	}
-
-	nv_wr32(dev, 0x409614, 0x00000070);
-	nv_wr32(dev, 0x409614, 0x00000770);
-	nv_wr32(dev, 0x40802c, 0x00000001);
-
-	if (priv->data == NULL) {
-		int ret = nve0_grctx_generate(dev);
-		if (ret) {
-			NV_ERROR(dev, "PGRAPH: failed to construct context\n");
-			return ret;
-		}
-
-		return 1;
-	}
-
-	return 0;
-}
-
-static int
-nve0_graph_init(struct drm_device *dev, int engine)
-{
-	int ret;
-
-reset:
-	nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
-	nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
-
-	nve0_graph_init_obj418880(dev);
-	nve0_graph_init_regs(dev);
-	nve0_graph_init_gpc_0(dev);
-
-	nv_wr32(dev, 0x400500, 0x00010001);
-	nv_wr32(dev, 0x400100, 0xffffffff);
-	nv_wr32(dev, 0x40013c, 0xffffffff);
-
-	nve0_graph_init_units(dev);
-	nve0_graph_init_gpc_1(dev);
-	nve0_graph_init_rop(dev);
-
-	nv_wr32(dev, 0x400108, 0xffffffff);
-	nv_wr32(dev, 0x400138, 0xffffffff);
-	nv_wr32(dev, 0x400118, 0xffffffff);
-	nv_wr32(dev, 0x400130, 0xffffffff);
-	nv_wr32(dev, 0x40011c, 0xffffffff);
-	nv_wr32(dev, 0x400134, 0xffffffff);
-	nv_wr32(dev, 0x400054, 0x34ce3464);
-
-	ret = nve0_graph_init_ctxctl(dev);
-	if (ret) {
-		if (ret == 1)
-			goto reset;
-		return ret;
-	}
-
-	return 0;
-}
-
-int
-nve0_graph_isr_chid(struct drm_device *dev, u64 inst)
-{
-	struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nouveau_channel *chan;
-	unsigned long flags;
-	int i;
-
-	spin_lock_irqsave(&dev_priv->channels.lock, flags);
-	for (i = 0; i < pfifo->channels; i++) {
-		chan = dev_priv->channels.ptr[i];
-		if (!chan || !chan->ramin)
-			continue;
-
-		if (inst == chan->ramin->addr)
-			break;
-	}
-	spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
-	return i;
-}
-
-static void
-nve0_graph_ctxctl_isr(struct drm_device *dev)
-{
-	u32 ustat = nv_rd32(dev, 0x409c18);
+	u32 ustat = nv_rd32(priv, 0x409c18);
 
 	if (ustat & 0x00000001)
-		NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n");
+		nv_error(priv, "CTXCTRL ucode error\n");
 	if (ustat & 0x00080000)
-		NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n");
+		nv_error(priv, "CTXCTRL watchdog timeout\n");
 	if (ustat & ~0x00080001)
-		NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat);
+		nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
 
-	nve0_graph_ctxctl_debug(dev);
-	nv_wr32(dev, 0x409c20, ustat);
+	nvc0_graph_ctxctl_debug(priv);
+	nv_wr32(priv, 0x409c20, ustat);
 }
 
 static void
-nve0_graph_trap_isr(struct drm_device *dev, int chid)
+nve0_graph_trap_isr(struct nvc0_graph_priv *priv, u64 inst)
 {
-	struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
-	u32 trap = nv_rd32(dev, 0x400108);
+	u32 trap = nv_rd32(priv, 0x400108);
 	int rop;
 
 	if (trap & 0x00000001) {
-		u32 stat = nv_rd32(dev, 0x404000);
-		NV_INFO(dev, "PGRAPH: DISPATCH ch %d 0x%08x\n", chid, stat);
-		nv_wr32(dev, 0x404000, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x00000001);
+		u32 stat = nv_rd32(priv, 0x404000);
+		nv_error(priv, "DISPATCH ch 0x%010llx 0x%08x\n", inst, stat);
+		nv_wr32(priv, 0x404000, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000001);
 		trap &= ~0x00000001;
 	}
 
 	if (trap & 0x00000010) {
-		u32 stat = nv_rd32(dev, 0x405840);
-		NV_INFO(dev, "PGRAPH: SHADER ch %d 0x%08x\n", chid, stat);
-		nv_wr32(dev, 0x405840, 0xc0000000);
-		nv_wr32(dev, 0x400108, 0x00000010);
+		u32 stat = nv_rd32(priv, 0x405840);
+		nv_error(priv, "SHADER ch 0x%010llx 0x%08x\n", inst, stat);
+		nv_wr32(priv, 0x405840, 0xc0000000);
+		nv_wr32(priv, 0x400108, 0x00000010);
 		trap &= ~0x00000010;
 	}
 
 	if (trap & 0x02000000) {
 		for (rop = 0; rop < priv->rop_nr; rop++) {
-			u32 statz = nv_rd32(dev, ROP_UNIT(rop, 0x070));
-			u32 statc = nv_rd32(dev, ROP_UNIT(rop, 0x144));
-			NV_INFO(dev, "PGRAPH: ROP%d ch %d 0x%08x 0x%08x\n",
-				     rop, chid, statz, statc);
-			nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
-			nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
+			u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
+			u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
+			nv_error(priv, "ROP%d ch 0x%010llx 0x%08x 0x%08x\n",
+				     rop, inst, statz, statc);
+			nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+			nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
 		}
-		nv_wr32(dev, 0x400108, 0x02000000);
+		nv_wr32(priv, 0x400108, 0x02000000);
 		trap &= ~0x02000000;
 	}
 
 	if (trap) {
-		NV_INFO(dev, "PGRAPH: TRAP ch %d 0x%08x\n", chid, trap);
-		nv_wr32(dev, 0x400108, trap);
+		nv_error(priv, "TRAP ch 0x%010llx 0x%08x\n", inst, trap);
+		nv_wr32(priv, 0x400108, trap);
 	}
 }
 
 static void
-nve0_graph_isr(struct drm_device *dev)
+nve0_graph_intr(struct nouveau_subdev *subdev)
 {
-	u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
-	u32 chid = nve0_graph_isr_chid(dev, inst);
-	u32 stat = nv_rd32(dev, 0x400100);
-	u32 addr = nv_rd32(dev, 0x400704);
+	struct nvc0_graph_priv *priv = (void *)subdev;
+	struct nouveau_engine *engine = nv_engine(subdev);
+	struct nouveau_handle *handle = NULL;
+	u64 inst = (u64)(nv_rd32(priv, 0x409b00) & 0x0fffffff) << 12;
+	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(dev, 0x400708);
-	u32 code = nv_rd32(dev, 0x400110);
-	u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
+	u32 data = nv_rd32(priv, 0x400708);
+	u32 code = nv_rd32(priv, 0x400110);
+	u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
 
 	if (stat & 0x00000010) {
-		if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) {
-			NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] "
+		handle = nouveau_engctx_lookup_class(engine, inst, class);
+		if (!handle || nv_call(handle->object, mthd, data)) {
+			nv_error(priv, "ILLEGAL_MTHD ch 0x%010llx "
 				     "subc %d class 0x%04x mthd 0x%04x "
 				     "data 0x%08x\n",
-				chid, inst, subc, class, mthd, data);
+				 inst, subc, class, mthd, data);
 		}
-		nv_wr32(dev, 0x400100, 0x00000010);
+		nouveau_engctx_handle_put(handle);
+		nv_wr32(priv, 0x400100, 0x00000010);
 		stat &= ~0x00000010;
 	}
 
 	if (stat & 0x00000020) {
-		NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
+		nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d "
 			     "class 0x%04x mthd 0x%04x data 0x%08x\n",
-			chid, inst, subc, class, mthd, data);
-		nv_wr32(dev, 0x400100, 0x00000020);
+			 inst, subc, class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00000020);
 		stat &= ~0x00000020;
 	}
 
 	if (stat & 0x00100000) {
-		NV_INFO(dev, "PGRAPH: DATA_ERROR [");
+		nv_error(priv, "DATA_ERROR [");
 		nouveau_enum_print(nv50_data_error_names, code);
-		printk("] ch %d [0x%010llx] subc %d class 0x%04x "
+		printk("] ch 0x%010llx subc %d class 0x%04x "
 		       "mthd 0x%04x data 0x%08x\n",
-		       chid, inst, subc, class, mthd, data);
-		nv_wr32(dev, 0x400100, 0x00100000);
+		       inst, subc, class, mthd, data);
+		nv_wr32(priv, 0x400100, 0x00100000);
 		stat &= ~0x00100000;
 	}
 
 	if (stat & 0x00200000) {
-		nve0_graph_trap_isr(dev, chid);
-		nv_wr32(dev, 0x400100, 0x00200000);
+		nve0_graph_trap_isr(priv, inst);
+		nv_wr32(priv, 0x400100, 0x00200000);
 		stat &= ~0x00200000;
 	}
 
 	if (stat & 0x00080000) {
-		nve0_graph_ctxctl_isr(dev);
-		nv_wr32(dev, 0x400100, 0x00080000);
+		nve0_graph_ctxctl_isr(priv);
+		nv_wr32(priv, 0x400100, 0x00080000);
 		stat &= ~0x00080000;
 	}
 
 	if (stat) {
-		NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat);
-		nv_wr32(dev, 0x400100, stat);
+		nv_error(priv, "unknown stat 0x%08x\n", stat);
+		nv_wr32(priv, 0x400100, stat);
 	}
 
-	nv_wr32(dev, 0x400500, 0x00010001);
+	nv_wr32(priv, 0x400500, 0x00010001);
 }
 
 static int
-nve0_graph_create_fw(struct drm_device *dev, const char *fwname,
-		     struct nvc0_graph_fuc *fuc)
+nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+	       struct nouveau_oclass *oclass, void *data, u32 size,
+	       struct nouveau_object **pobject)
 {
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	const struct firmware *fw;
-	char f[32];
-	int ret;
+	struct nvc0_graph_priv *priv;
+	int ret, i;
 
-	snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
-	ret = request_firmware(&fw, f, &dev->pdev->dev);
+	ret = nouveau_graph_create(parent, engine, oclass, false, &priv);
+	*pobject = nv_object(priv);
 	if (ret)
 		return ret;
 
-	fuc->size = fw->size;
-	fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
-	release_firmware(fw);
-	return (fuc->data != NULL) ? 0 : -ENOMEM;
-}
+	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;
 
-static void
-nve0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
-{
-	if (fuc->data) {
-		kfree(fuc->data);
-		fuc->data = NULL;
-	}
-}
-
-static void
-nve0_graph_destroy(struct drm_device *dev, int engine)
-{
-	struct nvc0_graph_priv *priv = nv_engine(dev, engine);
-
-	nve0_graph_destroy_fw(&priv->fuc409c);
-	nve0_graph_destroy_fw(&priv->fuc409d);
-	nve0_graph_destroy_fw(&priv->fuc41ac);
-	nve0_graph_destroy_fw(&priv->fuc41ad);
-
-	nouveau_irq_unregister(dev, 12);
-
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-	nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
-	if (priv->data)
-		kfree(priv->data);
-
-	NVOBJ_ENGINE_DEL(dev, GR);
-	kfree(priv);
-}
-
-int
-nve0_graph_create(struct drm_device *dev)
-{
-	struct drm_nouveau_private *dev_priv = dev->dev_private;
-	struct nvc0_graph_priv *priv;
-	int ret, gpc, i;
-	u32 kepler;
-
-	kepler = nvc0_graph_class(dev);
-	if (!kepler) {
-		NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
-		return 0;
-	}
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv->base.destroy = nve0_graph_destroy;
-	priv->base.init = nve0_graph_init;
-	priv->base.fini = nve0_graph_fini;
-	priv->base.context_new = nvc0_graph_context_new;
-	priv->base.context_del = nvc0_graph_context_del;
-	priv->base.object_new = nve0_graph_object_new;
-
-	NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
-	nouveau_irq_register(dev, 12, nve0_graph_isr);
-
-	NV_INFO(dev, "PGRAPH: using external firmware\n");
-	if (nve0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
-	    nve0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
-	    nve0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
-	    nve0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
-		ret = 0;
-		goto error;
-	}
+	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(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4);
 	if (ret)
-		goto error;
+		return ret;
 
-	ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+	ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8);
 	if (ret)
-		goto error;
+		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(dev, 0x409604) & 0x0000001f;
-	priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
-	for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-		priv->tpc_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
-		priv->tpc_total += priv->tpc_nr[gpc];
+	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 (dev_priv->chipset) {
+	switch (nv_device(priv)->chipset) {
 	case 0xe4:
 		if (priv->tpc_total == 8)
 			priv->magic_not_rop_nr = 3;
@@ -616,21 +243,275 @@
 		break;
 	}
 
-	if (!priv->magic_not_rop_nr) {
-		NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
-			 priv->tpc_nr[0], priv->tpc_nr[1], priv->tpc_nr[2],
-			 priv->tpc_nr[3], priv->rop_nr);
-		priv->magic_not_rop_nr = 0x00;
+	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);
 	}
 
-	NVOBJ_CLASS(dev, 0xa097, GR); /* subc 0: 3D */
-	NVOBJ_CLASS(dev, 0xa0c0, GR); /* subc 1: COMPUTE */
-	NVOBJ_CLASS(dev, 0xa040, GR); /* subc 2: P2MF */
-	NVOBJ_CLASS(dev, 0x902d, GR); /* subc 3: 2D */
-	NVOBJ_CLASS(dev, 0xa0b5, GR); /* subc 4: COPY */
-	return 0;
+	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]);
 
-error:
-	nve0_graph_destroy(dev, NVOBJ_ENGINE_GR);
-	return ret;
+	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
+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;
+
+	/* 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 1;
+	}
+
+	return 0;
+}
+
+static int
+nve0_graph_init(struct nouveau_object *object)
+{
+	struct nvc0_graph_priv *priv = (void *)object;
+	int ret;
+
+reset:
+	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) {
+		if (ret == 1)
+			goto reset;
+		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/regs.h b/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
new file mode 100644
index 0000000..9c715a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
@@ -0,0 +1,269 @@
+#ifndef __NOUVEAU_GRAPH_REGS_H__
+#define __NOUVEAU_GRAPH_REGS_H__
+
+#define NV04_PGRAPH_DEBUG_0                                0x00400080
+#define NV04_PGRAPH_DEBUG_1                                0x00400084
+#define NV04_PGRAPH_DEBUG_2                                0x00400088
+#define NV04_PGRAPH_DEBUG_3                                0x0040008c
+#define NV10_PGRAPH_DEBUG_4                                0x00400090
+#define NV03_PGRAPH_INTR                                   0x00400100
+#define NV03_PGRAPH_NSTATUS                                0x00400104
+#    define NV04_PGRAPH_NSTATUS_STATE_IN_USE                  (1<<11)
+#    define NV04_PGRAPH_NSTATUS_INVALID_STATE                 (1<<12)
+#    define NV04_PGRAPH_NSTATUS_BAD_ARGUMENT                  (1<<13)
+#    define NV04_PGRAPH_NSTATUS_PROTECTION_FAULT              (1<<14)
+#    define NV10_PGRAPH_NSTATUS_STATE_IN_USE                  (1<<23)
+#    define NV10_PGRAPH_NSTATUS_INVALID_STATE                 (1<<24)
+#    define NV10_PGRAPH_NSTATUS_BAD_ARGUMENT                  (1<<25)
+#    define NV10_PGRAPH_NSTATUS_PROTECTION_FAULT              (1<<26)
+#define NV03_PGRAPH_NSOURCE                                0x00400108
+#    define NV03_PGRAPH_NSOURCE_NOTIFICATION                   (1<<0)
+#    define NV03_PGRAPH_NSOURCE_DATA_ERROR                     (1<<1)
+#    define NV03_PGRAPH_NSOURCE_PROTECTION_ERROR               (1<<2)
+#    define NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION                (1<<3)
+#    define NV03_PGRAPH_NSOURCE_LIMIT_COLOR                    (1<<4)
+#    define NV03_PGRAPH_NSOURCE_LIMIT_ZETA                     (1<<5)
+#    define NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD                   (1<<6)
+#    define NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION               (1<<7)
+#    define NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION               (1<<8)
+#    define NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION               (1<<9)
+#    define NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION               (1<<10)
+#    define NV03_PGRAPH_NSOURCE_STATE_INVALID                 (1<<11)
+#    define NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY                 (1<<12)
+#    define NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE                 (1<<13)
+#    define NV03_PGRAPH_NSOURCE_METHOD_CNT                    (1<<14)
+#    define NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION              (1<<15)
+#    define NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION            (1<<16)
+#    define NV03_PGRAPH_NSOURCE_DMA_WIDTH_A                   (1<<17)
+#    define NV03_PGRAPH_NSOURCE_DMA_WIDTH_B                   (1<<18)
+#define NV03_PGRAPH_INTR_EN                                0x00400140
+#define NV40_PGRAPH_INTR_EN                                0x0040013C
+#    define NV_PGRAPH_INTR_NOTIFY                              (1<<0)
+#    define NV_PGRAPH_INTR_MISSING_HW                          (1<<4)
+#    define NV_PGRAPH_INTR_CONTEXT_SWITCH                     (1<<12)
+#    define NV_PGRAPH_INTR_BUFFER_NOTIFY                      (1<<16)
+#    define NV_PGRAPH_INTR_ERROR                              (1<<20)
+#define NV10_PGRAPH_CTX_CONTROL                            0x00400144
+#define NV10_PGRAPH_CTX_USER                               0x00400148
+#define NV10_PGRAPH_CTX_SWITCH(i)                         (0x0040014C + 0x4*(i))
+#define NV04_PGRAPH_CTX_SWITCH1                            0x00400160
+#define NV10_PGRAPH_CTX_CACHE(i, j)                       (0x00400160	\
+							   + 0x4*(i) + 0x20*(j))
+#define NV04_PGRAPH_CTX_SWITCH2                            0x00400164
+#define NV04_PGRAPH_CTX_SWITCH3                            0x00400168
+#define NV04_PGRAPH_CTX_SWITCH4                            0x0040016C
+#define NV04_PGRAPH_CTX_CONTROL                            0x00400170
+#define NV04_PGRAPH_CTX_USER                               0x00400174
+#define NV04_PGRAPH_CTX_CACHE1                             0x00400180
+#define NV03_PGRAPH_CTX_CONTROL                            0x00400190
+#define NV03_PGRAPH_CTX_USER                               0x00400194
+#define NV04_PGRAPH_CTX_CACHE2                             0x004001A0
+#define NV04_PGRAPH_CTX_CACHE3                             0x004001C0
+#define NV04_PGRAPH_CTX_CACHE4                             0x004001E0
+#define NV40_PGRAPH_CTXCTL_0304                            0x00400304
+#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX                   0x00000001
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT                      0x00400308
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_MASK              0xff000000
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT                     24
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK              0x00ffffff
+#define NV40_PGRAPH_CTXCTL_0310                            0x00400310
+#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE                  0x00000020
+#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD                  0x00000040
+#define NV40_PGRAPH_CTXCTL_030C                            0x0040030c
+#define NV40_PGRAPH_CTXCTL_UCODE_INDEX                     0x00400324
+#define NV40_PGRAPH_CTXCTL_UCODE_DATA                      0x00400328
+#define NV40_PGRAPH_CTXCTL_CUR                             0x0040032c
+#define NV40_PGRAPH_CTXCTL_CUR_LOADED                      0x01000000
+#define NV40_PGRAPH_CTXCTL_CUR_INSTANCE                    0x000FFFFF
+#define NV40_PGRAPH_CTXCTL_NEXT                            0x00400330
+#define NV40_PGRAPH_CTXCTL_NEXT_INSTANCE                   0x000fffff
+#define NV50_PGRAPH_CTXCTL_CUR                             0x0040032c
+#define NV50_PGRAPH_CTXCTL_CUR_LOADED                      0x80000000
+#define NV50_PGRAPH_CTXCTL_CUR_INSTANCE                    0x00ffffff
+#define NV50_PGRAPH_CTXCTL_NEXT                            0x00400330
+#define NV50_PGRAPH_CTXCTL_NEXT_INSTANCE                   0x00ffffff
+#define NV03_PGRAPH_ABS_X_RAM                              0x00400400
+#define NV03_PGRAPH_ABS_Y_RAM                              0x00400480
+#define NV03_PGRAPH_X_MISC                                 0x00400500
+#define NV03_PGRAPH_Y_MISC                                 0x00400504
+#define NV04_PGRAPH_VALID1                                 0x00400508
+#define NV04_PGRAPH_SOURCE_COLOR                           0x0040050C
+#define NV04_PGRAPH_MISC24_0                               0x00400510
+#define NV03_PGRAPH_XY_LOGIC_MISC0                         0x00400514
+#define NV03_PGRAPH_XY_LOGIC_MISC1                         0x00400518
+#define NV03_PGRAPH_XY_LOGIC_MISC2                         0x0040051C
+#define NV03_PGRAPH_XY_LOGIC_MISC3                         0x00400520
+#define NV03_PGRAPH_CLIPX_0                                0x00400524
+#define NV03_PGRAPH_CLIPX_1                                0x00400528
+#define NV03_PGRAPH_CLIPY_0                                0x0040052C
+#define NV03_PGRAPH_CLIPY_1                                0x00400530
+#define NV03_PGRAPH_ABS_ICLIP_XMAX                         0x00400534
+#define NV03_PGRAPH_ABS_ICLIP_YMAX                         0x00400538
+#define NV03_PGRAPH_ABS_UCLIP_XMIN                         0x0040053C
+#define NV03_PGRAPH_ABS_UCLIP_YMIN                         0x00400540
+#define NV03_PGRAPH_ABS_UCLIP_XMAX                         0x00400544
+#define NV03_PGRAPH_ABS_UCLIP_YMAX                         0x00400548
+#define NV03_PGRAPH_ABS_UCLIPA_XMIN                        0x00400560
+#define NV03_PGRAPH_ABS_UCLIPA_YMIN                        0x00400564
+#define NV03_PGRAPH_ABS_UCLIPA_XMAX                        0x00400568
+#define NV03_PGRAPH_ABS_UCLIPA_YMAX                        0x0040056C
+#define NV04_PGRAPH_MISC24_1                               0x00400570
+#define NV04_PGRAPH_MISC24_2                               0x00400574
+#define NV04_PGRAPH_VALID2                                 0x00400578
+#define NV04_PGRAPH_PASSTHRU_0                             0x0040057C
+#define NV04_PGRAPH_PASSTHRU_1                             0x00400580
+#define NV04_PGRAPH_PASSTHRU_2                             0x00400584
+#define NV10_PGRAPH_DIMX_TEXTURE                           0x00400588
+#define NV10_PGRAPH_WDIMX_TEXTURE                          0x0040058C
+#define NV04_PGRAPH_COMBINE_0_ALPHA                        0x00400590
+#define NV04_PGRAPH_COMBINE_0_COLOR                        0x00400594
+#define NV04_PGRAPH_COMBINE_1_ALPHA                        0x00400598
+#define NV04_PGRAPH_COMBINE_1_COLOR                        0x0040059C
+#define NV04_PGRAPH_FORMAT_0                               0x004005A8
+#define NV04_PGRAPH_FORMAT_1                               0x004005AC
+#define NV04_PGRAPH_FILTER_0                               0x004005B0
+#define NV04_PGRAPH_FILTER_1                               0x004005B4
+#define NV03_PGRAPH_MONO_COLOR0                            0x00400600
+#define NV04_PGRAPH_ROP3                                   0x00400604
+#define NV04_PGRAPH_BETA_AND                               0x00400608
+#define NV04_PGRAPH_BETA_PREMULT                           0x0040060C
+#define NV04_PGRAPH_LIMIT_VIOL_PIX                         0x00400610
+#define NV04_PGRAPH_FORMATS                                0x00400618
+#define NV10_PGRAPH_DEBUG_2                                0x00400620
+#define NV04_PGRAPH_BOFFSET0                               0x00400640
+#define NV04_PGRAPH_BOFFSET1                               0x00400644
+#define NV04_PGRAPH_BOFFSET2                               0x00400648
+#define NV04_PGRAPH_BOFFSET3                               0x0040064C
+#define NV04_PGRAPH_BOFFSET4                               0x00400650
+#define NV04_PGRAPH_BOFFSET5                               0x00400654
+#define NV04_PGRAPH_BBASE0                                 0x00400658
+#define NV04_PGRAPH_BBASE1                                 0x0040065C
+#define NV04_PGRAPH_BBASE2                                 0x00400660
+#define NV04_PGRAPH_BBASE3                                 0x00400664
+#define NV04_PGRAPH_BBASE4                                 0x00400668
+#define NV04_PGRAPH_BBASE5                                 0x0040066C
+#define NV04_PGRAPH_BPITCH0                                0x00400670
+#define NV04_PGRAPH_BPITCH1                                0x00400674
+#define NV04_PGRAPH_BPITCH2                                0x00400678
+#define NV04_PGRAPH_BPITCH3                                0x0040067C
+#define NV04_PGRAPH_BPITCH4                                0x00400680
+#define NV04_PGRAPH_BLIMIT0                                0x00400684
+#define NV04_PGRAPH_BLIMIT1                                0x00400688
+#define NV04_PGRAPH_BLIMIT2                                0x0040068C
+#define NV04_PGRAPH_BLIMIT3                                0x00400690
+#define NV04_PGRAPH_BLIMIT4                                0x00400694
+#define NV04_PGRAPH_BLIMIT5                                0x00400698
+#define NV04_PGRAPH_BSWIZZLE2                              0x0040069C
+#define NV04_PGRAPH_BSWIZZLE5                              0x004006A0
+#define NV03_PGRAPH_STATUS                                 0x004006B0
+#define NV04_PGRAPH_STATUS                                 0x00400700
+#    define NV40_PGRAPH_STATUS_SYNC_STALL                  0x00004000
+#define NV04_PGRAPH_TRAPPED_ADDR                           0x00400704
+#define NV04_PGRAPH_TRAPPED_DATA                           0x00400708
+#define NV04_PGRAPH_SURFACE                                0x0040070C
+#define NV10_PGRAPH_TRAPPED_DATA_HIGH                      0x0040070C
+#define NV04_PGRAPH_STATE                                  0x00400710
+#define NV10_PGRAPH_SURFACE                                0x00400710
+#define NV04_PGRAPH_NOTIFY                                 0x00400714
+#define NV10_PGRAPH_STATE                                  0x00400714
+#define NV10_PGRAPH_NOTIFY                                 0x00400718
+
+#define NV04_PGRAPH_FIFO                                   0x00400720
+
+#define NV04_PGRAPH_BPIXEL                                 0x00400724
+#define NV10_PGRAPH_RDI_INDEX                              0x00400750
+#define NV04_PGRAPH_FFINTFC_ST2                            0x00400754
+#define NV10_PGRAPH_RDI_DATA                               0x00400754
+#define NV04_PGRAPH_DMA_PITCH                              0x00400760
+#define NV10_PGRAPH_FFINTFC_FIFO_PTR                       0x00400760
+#define NV04_PGRAPH_DVD_COLORFMT                           0x00400764
+#define NV10_PGRAPH_FFINTFC_ST2                            0x00400764
+#define NV04_PGRAPH_SCALED_FORMAT                          0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DL                         0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DH                         0x0040076c
+#define NV10_PGRAPH_DMA_PITCH                              0x00400770
+#define NV10_PGRAPH_DVD_COLORFMT                           0x00400774
+#define NV10_PGRAPH_SCALED_FORMAT                          0x00400778
+#define NV20_PGRAPH_CHANNEL_CTX_TABLE                      0x00400780
+#define NV20_PGRAPH_CHANNEL_CTX_POINTER                    0x00400784
+#define NV20_PGRAPH_CHANNEL_CTX_XFER                       0x00400788
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD                  0x00000001
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE                  0x00000002
+#define NV04_PGRAPH_PATT_COLOR0                            0x00400800
+#define NV04_PGRAPH_PATT_COLOR1                            0x00400804
+#define NV04_PGRAPH_PATTERN                                0x00400808
+#define NV04_PGRAPH_PATTERN_SHAPE                          0x00400810
+#define NV04_PGRAPH_CHROMA                                 0x00400814
+#define NV04_PGRAPH_CONTROL0                               0x00400818
+#define NV04_PGRAPH_CONTROL1                               0x0040081C
+#define NV04_PGRAPH_CONTROL2                               0x00400820
+#define NV04_PGRAPH_BLEND                                  0x00400824
+#define NV04_PGRAPH_STORED_FMT                             0x00400830
+#define NV04_PGRAPH_PATT_COLORRAM                          0x00400900
+#define NV20_PGRAPH_TILE(i)                                (0x00400900 + (i*16))
+#define NV20_PGRAPH_TLIMIT(i)                              (0x00400904 + (i*16))
+#define NV20_PGRAPH_TSIZE(i)                               (0x00400908 + (i*16))
+#define NV20_PGRAPH_TSTATUS(i)                             (0x0040090C + (i*16))
+#define NV20_PGRAPH_ZCOMP(i)                               (0x00400980 + 4*(i))
+#define NV10_PGRAPH_TILE(i)                                (0x00400B00 + (i*16))
+#define NV10_PGRAPH_TLIMIT(i)                              (0x00400B04 + (i*16))
+#define NV10_PGRAPH_TSIZE(i)                               (0x00400B08 + (i*16))
+#define NV10_PGRAPH_TSTATUS(i)                             (0x00400B0C + (i*16))
+#define NV04_PGRAPH_U_RAM                                  0x00400D00
+#define NV47_PGRAPH_TILE(i)                                (0x00400D00 + (i*16))
+#define NV47_PGRAPH_TLIMIT(i)                              (0x00400D04 + (i*16))
+#define NV47_PGRAPH_TSIZE(i)                               (0x00400D08 + (i*16))
+#define NV47_PGRAPH_TSTATUS(i)                             (0x00400D0C + (i*16))
+#define NV04_PGRAPH_V_RAM                                  0x00400D40
+#define NV04_PGRAPH_W_RAM                                  0x00400D80
+#define NV10_PGRAPH_COMBINER0_IN_ALPHA                     0x00400E40
+#define NV10_PGRAPH_COMBINER1_IN_ALPHA                     0x00400E44
+#define NV10_PGRAPH_COMBINER0_IN_RGB                       0x00400E48
+#define NV10_PGRAPH_COMBINER1_IN_RGB                       0x00400E4C
+#define NV10_PGRAPH_COMBINER_COLOR0                        0x00400E50
+#define NV10_PGRAPH_COMBINER_COLOR1                        0x00400E54
+#define NV10_PGRAPH_COMBINER0_OUT_ALPHA                    0x00400E58
+#define NV10_PGRAPH_COMBINER1_OUT_ALPHA                    0x00400E5C
+#define NV10_PGRAPH_COMBINER0_OUT_RGB                      0x00400E60
+#define NV10_PGRAPH_COMBINER1_OUT_RGB                      0x00400E64
+#define NV10_PGRAPH_COMBINER_FINAL0                        0x00400E68
+#define NV10_PGRAPH_COMBINER_FINAL1                        0x00400E6C
+#define NV10_PGRAPH_WINDOWCLIP_HORIZONTAL                  0x00400F00
+#define NV10_PGRAPH_WINDOWCLIP_VERTICAL                    0x00400F20
+#define NV10_PGRAPH_XFMODE0                                0x00400F40
+#define NV10_PGRAPH_XFMODE1                                0x00400F44
+#define NV10_PGRAPH_GLOBALSTATE0                           0x00400F48
+#define NV10_PGRAPH_GLOBALSTATE1                           0x00400F4C
+#define NV10_PGRAPH_PIPE_ADDRESS                           0x00400F50
+#define NV10_PGRAPH_PIPE_DATA                              0x00400F54
+#define NV04_PGRAPH_DMA_START_0                            0x00401000
+#define NV04_PGRAPH_DMA_START_1                            0x00401004
+#define NV04_PGRAPH_DMA_LENGTH                             0x00401008
+#define NV04_PGRAPH_DMA_MISC                               0x0040100C
+#define NV04_PGRAPH_DMA_DATA_0                             0x00401020
+#define NV04_PGRAPH_DMA_DATA_1                             0x00401024
+#define NV04_PGRAPH_DMA_RM                                 0x00401030
+#define NV04_PGRAPH_DMA_A_XLATE_INST                       0x00401040
+#define NV04_PGRAPH_DMA_A_CONTROL                          0x00401044
+#define NV04_PGRAPH_DMA_A_LIMIT                            0x00401048
+#define NV04_PGRAPH_DMA_A_TLB_PTE                          0x0040104C
+#define NV04_PGRAPH_DMA_A_TLB_TAG                          0x00401050
+#define NV04_PGRAPH_DMA_A_ADJ_OFFSET                       0x00401054
+#define NV04_PGRAPH_DMA_A_OFFSET                           0x00401058
+#define NV04_PGRAPH_DMA_A_SIZE                             0x0040105C
+#define NV04_PGRAPH_DMA_A_Y_SIZE                           0x00401060
+#define NV04_PGRAPH_DMA_B_XLATE_INST                       0x00401080
+#define NV04_PGRAPH_DMA_B_CONTROL                          0x00401084
+#define NV04_PGRAPH_DMA_B_LIMIT                            0x00401088
+#define NV04_PGRAPH_DMA_B_TLB_PTE                          0x0040108C
+#define NV04_PGRAPH_DMA_B_TLB_TAG                          0x00401090
+#define NV04_PGRAPH_DMA_B_ADJ_OFFSET                       0x00401094
+#define NV04_PGRAPH_DMA_B_OFFSET                           0x00401098
+#define NV04_PGRAPH_DMA_B_SIZE                             0x0040109C
+#define NV04_PGRAPH_DMA_B_Y_SIZE                           0x004010A0
+#define NV40_PGRAPH_TILE1(i)                               (0x00406900 + (i*16))
+#define NV40_PGRAPH_TLIMIT1(i)                             (0x00406904 + (i*16))
+#define NV40_PGRAPH_TSIZE1(i)                              (0x00406908 + (i*16))
+#define NV40_PGRAPH_TSTATUS1(i)                            (0x0040690C + (i*16))
+
+#endif