From c85ee6ca79590cd51356bf24fb8936bc352138cf Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Thu, 20 Aug 2015 14:54:22 +1000
Subject: [PATCH] drm/nouveau/gr: convert to new-style nvkm_engine

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
---
 .../drm/nouveau/include/nvkm/core/engine.h    |   4 +-
 .../gpu/drm/nouveau/include/nvkm/engine/gr.h  |  94 ++--
 drivers/gpu/drm/nouveau/nouveau_abi16.c       |   2 +-
 drivers/gpu/drm/nouveau/nouveau_bo.c          |   3 +-
 drivers/gpu/drm/nouveau/nvkm/core/engine.c    |  15 +-
 .../gpu/drm/nouveau/nvkm/engine/device/base.c | 138 +++---
 .../drm/nouveau/nvkm/engine/device/gf100.c    |   9 -
 .../drm/nouveau/nvkm/engine/device/gk104.c    |   8 -
 .../drm/nouveau/nvkm/engine/device/gm100.c    |   4 -
 .../gpu/drm/nouveau/nvkm/engine/device/nv04.c |   2 -
 .../gpu/drm/nouveau/nvkm/engine/device/nv10.c |   8 -
 .../gpu/drm/nouveau/nvkm/engine/device/nv20.c |   4 -
 .../gpu/drm/nouveau/nvkm/engine/device/nv30.c |   5 -
 .../gpu/drm/nouveau/nvkm/engine/device/nv40.c |  16 -
 .../gpu/drm/nouveau/nvkm/engine/device/nv50.c |  14 -
 drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild |  16 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c |  82 +++-
 .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c |   3 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c  | 196 ++++++++
 .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c    | 455 +++++++++---------
 .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h    |  71 ++-
 .../gpu/drm/nouveau/nvkm/engine/gr/gf104.c    |  23 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gf108.c    |  23 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gf110.c    |  23 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gf117.c    |  25 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gf119.c    |  23 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gk104.c    |  67 +--
 .../gpu/drm/nouveau/nvkm/engine/gr/gk110.c    |  25 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gk110b.c   |  25 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gk208.c    |  25 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c    | 165 +++----
 .../gpu/drm/nouveau/nvkm/engine/gr/gm107.c    |  37 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gm204.c    |  36 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gm206.c    |  21 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gm20b.c    |  28 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/gt200.c    |  47 ++
 .../gpu/drm/nouveau/nvkm/engine/gr/gt215.c    |  48 ++
 .../nvkm/engine/gr/{gk20a.h => mcp79.c}       |  43 +-
 .../gpu/drm/nouveau/nvkm/engine/gr/mcp89.c    |  48 ++
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 122 ++---
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 221 +++------
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h |  13 +
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c |  59 +++
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c |  59 +++
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 159 +++---
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h |  22 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c |  43 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c |  43 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 115 ++---
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c |  43 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c |  43 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 210 +++-----
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h |  13 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c | 108 +++++
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 372 +++-----------
 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h |  16 +-
 drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h |  23 +
 drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c |  12 +-
 .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c    |  14 +-
 59 files changed, 1744 insertions(+), 1847 deletions(-)
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c
 rename drivers/gpu/drm/nouveau/nvkm/engine/gr/{gk20a.h => mcp79.c} (50%)
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c
 create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c

diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
index 9d9c0e779f3fe..9c8c393247155 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
@@ -3,6 +3,7 @@
 #include <core/subdev.h>
 struct nvkm_device_oclass; /*XXX: DEV!ENG */
 struct nvkm_fifo_chan;
+struct nvkm_fb_tile;
 
 #define NV_ENGINE_(eng,var) (((var) << 8) | (eng))
 #define NV_ENGINE(name,var)  NV_ENGINE_(NVDEV_ENGINE_##name, (var))
@@ -20,7 +21,6 @@ struct nvkm_engine {
 	spinlock_t lock;
 
 	void (*tile_prog)(struct nvkm_engine *, int region);
-	int  (*tlb_flush)(struct nvkm_engine *);
 };
 
 struct nvkm_engine_func {
@@ -29,6 +29,7 @@ struct nvkm_engine_func {
 	int (*init)(struct nvkm_engine *);
 	int (*fini)(struct nvkm_engine *, bool suspend);
 	void (*intr)(struct nvkm_engine *);
+	void (*tile)(struct nvkm_engine *, int region, struct nvkm_fb_tile *);
 
 	struct {
 		int (*sclass)(struct nvkm_oclass *, int index,
@@ -54,6 +55,7 @@ int nvkm_engine_new_(const struct nvkm_engine_func *, struct nvkm_device *,
 		     struct nvkm_engine **);
 struct nvkm_engine *nvkm_engine_ref(struct nvkm_engine *);
 void nvkm_engine_unref(struct nvkm_engine **);
+void nvkm_engine_tile(struct nvkm_engine *, int region);
 
 static inline struct nvkm_engine *
 nv_engine(void *obj)
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
index f09f1521e6ad4..f126e54d2e30b 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
@@ -3,64 +3,44 @@
 #include <core/engine.h>
 
 struct nvkm_gr {
-	struct nvkm_engine engine;
 	const struct nvkm_gr_func *func;
-
-	/* Returns chipset-specific counts of units packed into an u64.
-	 */
-	u64 (*units)(struct nvkm_gr *);
+	struct nvkm_engine engine;
 };
 
-#define nvkm_gr_create(p,e,c,y,d)                                        \
-	nvkm_gr_create_((p), (e), (c), (y), sizeof(**d), (void **)(d))
-int
-nvkm_gr_create_(struct nvkm_object *parent, struct nvkm_object *engine,
-		struct nvkm_oclass *oclass, bool enable,
-		int length, void **pobject);
-#define nvkm_gr_destroy(d)                                               \
-	nvkm_engine_destroy(&(d)->engine)
-#define nvkm_gr_init(d)                                                  \
-	nvkm_engine_init_old(&(d)->engine)
-#define nvkm_gr_fini(d,s)                                                \
-	nvkm_engine_fini_old(&(d)->engine, (s))
-
-#define _nvkm_gr_dtor _nvkm_engine_dtor
-#define _nvkm_gr_init _nvkm_engine_init
-#define _nvkm_gr_fini _nvkm_engine_fini
-
-extern struct nvkm_oclass nv04_gr_oclass;
-extern struct nvkm_oclass nv10_gr_oclass;
-extern struct nvkm_oclass nv20_gr_oclass;
-extern struct nvkm_oclass nv25_gr_oclass;
-extern struct nvkm_oclass nv2a_gr_oclass;
-extern struct nvkm_oclass nv30_gr_oclass;
-extern struct nvkm_oclass nv34_gr_oclass;
-extern struct nvkm_oclass nv35_gr_oclass;
-extern struct nvkm_oclass nv40_gr_oclass;
-extern struct nvkm_oclass nv50_gr_oclass;
-extern struct nvkm_oclass *gf100_gr_oclass;
-extern struct nvkm_oclass *gf108_gr_oclass;
-extern struct nvkm_oclass *gf104_gr_oclass;
-extern struct nvkm_oclass *gf110_gr_oclass;
-extern struct nvkm_oclass *gf117_gr_oclass;
-extern struct nvkm_oclass *gf119_gr_oclass;
-extern struct nvkm_oclass *gk104_gr_oclass;
-extern struct nvkm_oclass *gk20a_gr_oclass;
-extern struct nvkm_oclass *gk110_gr_oclass;
-extern struct nvkm_oclass *gk110b_gr_oclass;
-extern struct nvkm_oclass *gk208_gr_oclass;
-extern struct nvkm_oclass *gm107_gr_oclass;
-extern struct nvkm_oclass *gm204_gr_oclass;
-extern struct nvkm_oclass *gm206_gr_oclass;
-extern struct nvkm_oclass *gm20b_gr_oclass;
-
-#include <core/enum.h>
-
-extern const struct nvkm_bitfield nv04_gr_nsource[];
-bool nv04_gr_idle(struct nvkm_gr *);
-
-extern const struct nvkm_bitfield nv10_gr_intr_name[];
-extern const struct nvkm_bitfield nv10_gr_nstatus[];
-
-extern const struct nvkm_enum nv50_data_error_names[];
+u64 nvkm_gr_units(struct nvkm_gr *);
+int nvkm_gr_tlb_flush(struct nvkm_gr *);
+
+int nv04_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv10_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv15_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv17_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv20_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv25_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv2a_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv30_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv34_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv35_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv40_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv44_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int nv50_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int g84_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gt200_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int mcp79_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gt215_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int mcp89_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gf100_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gf104_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gf108_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gf110_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gf117_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gf119_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gk104_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gk110_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gk110b_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gk208_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gk20a_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gm107_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gm204_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gm206_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
+int gm20b_gr_new(struct nvkm_device *, int, struct nvkm_gr **);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 98c74985e27de..6634f420ded32 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -215,7 +215,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
 		getparam->value = 1;
 		break;
 	case NOUVEAU_GETPARAM_GRAPH_UNITS:
-		getparam->value = gr->units ? gr->units(gr) : 0;
+		getparam->value = nvkm_gr_units(gr);
 		break;
 	default:
 		NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 140a1eb9c49e5..bd33d547d5740 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -48,7 +48,8 @@ nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg,
 {
 	struct nouveau_drm *drm = nouveau_drm(dev);
 	int i = reg - drm->tile.reg;
-	struct nvkm_fb *fb = nvxx_fb(&drm->device);
+	struct nvkm_device *device = nvxx_device(&drm->device);
+	struct nvkm_fb *fb = device->fb;
 	struct nvkm_fb_tile *tile = &fb->tile.region[i];
 
 	nouveau_fence_unref(&reg->fence);
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c
index eabd271f68b39..3fef9cc34345f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c
+++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c
@@ -25,6 +25,8 @@
 #include <core/device.h>
 #include <core/option.h>
 
+#include <subdev/fb.h>
+
 void
 nvkm_engine_unref(struct nvkm_engine **pengine)
 {
@@ -56,6 +58,14 @@ nvkm_engine_ref(struct nvkm_engine *engine)
 	return engine;
 }
 
+void
+nvkm_engine_tile(struct nvkm_engine *engine, int region)
+{
+	struct nvkm_fb *fb = engine->subdev.device->fb;
+	if (engine->func->tile)
+		engine->func->tile(engine, region, &fb->tile.region[region]);
+}
+
 static void
 nvkm_engine_intr(struct nvkm_subdev *obj)
 {
@@ -80,7 +90,8 @@ nvkm_engine_init(struct nvkm_subdev *obj)
 {
 	struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev);
 	struct nvkm_subdev *subdev = &engine->subdev;
-	int ret = 0;
+	struct nvkm_fb *fb = subdev->device->fb;
+	int ret = 0, i;
 	s64 time;
 
 	if (!engine->usecount) {
@@ -108,6 +119,8 @@ nvkm_engine_init(struct nvkm_subdev *obj)
 	if (engine->func->init)
 		ret = engine->func->init(engine);
 
+	for (i = 0; fb && i < fb->tile.regions; i++)
+		nvkm_engine_tile(engine, i);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
index 62395ab742c5f..3cf15d46f9d23 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -89,7 +89,7 @@ nv4_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv04_fifo_new,
-//	.gr = nv04_gr_new,
+	.gr = nv04_gr_new,
 //	.sw = nv04_sw_new,
 };
 
@@ -109,7 +109,7 @@ nv5_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv04_fifo_new,
-//	.gr = nv04_gr_new,
+	.gr = nv04_gr_new,
 //	.sw = nv04_sw_new,
 };
 
@@ -129,7 +129,7 @@ nv10_chipset = {
 	.timer = nv04_timer_new,
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
-//	.gr = nv10_gr_new,
+	.gr = nv10_gr_new,
 };
 
 static const struct nvkm_device_chip
@@ -149,7 +149,7 @@ nv11_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv10_fifo_new,
-//	.gr = nv10_gr_new,
+	.gr = nv15_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -170,7 +170,7 @@ nv15_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv10_fifo_new,
-//	.gr = nv10_gr_new,
+	.gr = nv15_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -191,7 +191,7 @@ nv17_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv10_gr_new,
+	.gr = nv17_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -212,7 +212,7 @@ nv18_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv10_gr_new,
+	.gr = nv17_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -233,7 +233,7 @@ nv1a_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv10_fifo_new,
-//	.gr = nv10_gr_new,
+	.gr = nv15_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -254,7 +254,7 @@ nv1f_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv10_gr_new,
+	.gr = nv17_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -275,7 +275,7 @@ nv20_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv20_gr_new,
+	.gr = nv20_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -296,7 +296,7 @@ nv25_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv25_gr_new,
+	.gr = nv25_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -317,7 +317,7 @@ nv28_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv25_gr_new,
+	.gr = nv25_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -338,7 +338,7 @@ nv2a_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv2a_gr_new,
+	.gr = nv2a_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -359,7 +359,7 @@ nv30_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv30_gr_new,
+	.gr = nv30_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -380,7 +380,7 @@ nv31_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv30_gr_new,
+	.gr = nv30_gr_new,
 //	.mpeg = nv31_mpeg_new,
 //	.sw = nv10_sw_new,
 };
@@ -402,7 +402,7 @@ nv34_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv34_gr_new,
+	.gr = nv34_gr_new,
 //	.mpeg = nv31_mpeg_new,
 //	.sw = nv10_sw_new,
 };
@@ -424,7 +424,7 @@ nv35_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv35_gr_new,
+	.gr = nv35_gr_new,
 //	.sw = nv10_sw_new,
 };
 
@@ -445,7 +445,7 @@ nv36_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv17_fifo_new,
-//	.gr = nv35_gr_new,
+	.gr = nv35_gr_new,
 //	.mpeg = nv31_mpeg_new,
 //	.sw = nv10_sw_new,
 };
@@ -469,7 +469,7 @@ nv40_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv40_gr_new,
 //	.mpeg = nv40_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -494,7 +494,7 @@ nv41_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv40_gr_new,
 //	.mpeg = nv40_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -519,7 +519,7 @@ nv42_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv40_gr_new,
 //	.mpeg = nv40_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -544,7 +544,7 @@ nv43_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv40_gr_new,
 //	.mpeg = nv40_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -569,7 +569,7 @@ nv44_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv44_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -594,7 +594,7 @@ nv45_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv40_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -619,7 +619,7 @@ nv46_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv44_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -644,7 +644,7 @@ nv47_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv40_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -669,7 +669,7 @@ nv49_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv40_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -694,7 +694,7 @@ nv4a_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv44_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -719,7 +719,7 @@ nv4b_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv40_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -744,7 +744,7 @@ nv4c_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv44_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -769,7 +769,7 @@ nv4e_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv44_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -797,7 +797,7 @@ nv50_chipset = {
 	.disp = nv50_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = nv50_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = nv50_gr_new,
 //	.mpeg = nv50_mpeg_new,
 //	.pm = nv50_pm_new,
 //	.sw = nv50_sw_new,
@@ -822,7 +822,7 @@ nv63_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv44_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -847,7 +847,7 @@ nv67_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv44_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -872,7 +872,7 @@ nv68_chipset = {
 	.disp = nv04_disp_new,
 	.dma = nv04_dma_new,
 	.fifo = nv40_fifo_new,
-//	.gr = nv40_gr_new,
+	.gr = nv44_gr_new,
 //	.mpeg = nv44_mpeg_new,
 //	.pm = nv40_pm_new,
 //	.sw = nv10_sw_new,
@@ -902,7 +902,7 @@ nv84_chipset = {
 	.disp = g84_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = g84_gr_new,
 //	.mpeg = g84_mpeg_new,
 //	.pm = g84_pm_new,
 //	.sw = nv50_sw_new,
@@ -933,7 +933,7 @@ nv86_chipset = {
 	.disp = g84_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = g84_gr_new,
 //	.mpeg = g84_mpeg_new,
 //	.pm = g84_pm_new,
 //	.sw = nv50_sw_new,
@@ -964,7 +964,7 @@ nv92_chipset = {
 	.disp = g84_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = g84_gr_new,
 //	.mpeg = g84_mpeg_new,
 //	.pm = g84_pm_new,
 //	.sw = nv50_sw_new,
@@ -995,7 +995,7 @@ nv94_chipset = {
 	.disp = g94_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = g84_gr_new,
 //	.mpeg = g84_mpeg_new,
 //	.pm = g84_pm_new,
 //	.sw = nv50_sw_new,
@@ -1024,7 +1024,7 @@ nv96_chipset = {
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
 //	.sw = nv50_sw_new,
-//	.gr = nv50_gr_new,
+	.gr = g84_gr_new,
 //	.mpeg = g84_mpeg_new,
 	.vp = g84_vp_new,
 	.cipher = g84_cipher_new,
@@ -1055,7 +1055,7 @@ nv98_chipset = {
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
 //	.sw = nv50_sw_new,
-//	.gr = nv50_gr_new,
+	.gr = g84_gr_new,
 	.mspdec = g98_mspdec_new,
 	.sec = g98_sec_new,
 	.msvld = g98_msvld_new,
@@ -1088,7 +1088,7 @@ nva0_chipset = {
 	.disp = gt200_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = gt200_gr_new,
 //	.mpeg = g84_mpeg_new,
 //	.pm = gt200_pm_new,
 //	.sw = nv50_sw_new,
@@ -1119,7 +1119,7 @@ nva3_chipset = {
 	.disp = gt215_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = gt215_gr_new,
 //	.mpeg = g84_mpeg_new,
 	.mspdec = gt215_mspdec_new,
 	.msppp = gt215_msppp_new,
@@ -1152,7 +1152,7 @@ nva5_chipset = {
 	.disp = gt215_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = gt215_gr_new,
 	.mspdec = gt215_mspdec_new,
 	.msppp = gt215_msppp_new,
 	.msvld = gt215_msvld_new,
@@ -1184,7 +1184,7 @@ nva8_chipset = {
 	.disp = gt215_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = gt215_gr_new,
 	.mspdec = gt215_mspdec_new,
 	.msppp = gt215_msppp_new,
 	.msvld = gt215_msvld_new,
@@ -1214,7 +1214,7 @@ nvaa_chipset = {
 	.disp = g94_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = gt200_gr_new,
 	.mspdec = g98_mspdec_new,
 	.msppp = g98_msppp_new,
 	.msvld = g98_msvld_new,
@@ -1245,7 +1245,7 @@ nvac_chipset = {
 	.disp = g94_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = mcp79_gr_new,
 	.mspdec = g98_mspdec_new,
 	.msppp = g98_msppp_new,
 	.msvld = g98_msvld_new,
@@ -1278,7 +1278,7 @@ nvaf_chipset = {
 	.disp = gt215_disp_new,
 	.dma = nv50_dma_new,
 	.fifo = g84_fifo_new,
-//	.gr = nv50_gr_new,
+	.gr = mcp89_gr_new,
 	.mspdec = gt215_mspdec_new,
 	.msppp = gt215_msppp_new,
 	.msvld = mcp89_msvld_new,
@@ -1313,7 +1313,7 @@ nvc0_chipset = {
 	.disp = gt215_disp_new,
 	.dma = gf100_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf100_gr_new,
+	.gr = gf100_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1347,7 +1347,7 @@ nvc1_chipset = {
 	.disp = gt215_disp_new,
 	.dma = gf100_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf108_gr_new,
+	.gr = gf108_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1381,7 +1381,7 @@ nvc3_chipset = {
 	.disp = gt215_disp_new,
 	.dma = gf100_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf104_gr_new,
+	.gr = gf104_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1416,7 +1416,7 @@ nvc4_chipset = {
 	.disp = gt215_disp_new,
 	.dma = gf100_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf104_gr_new,
+	.gr = gf104_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1451,7 +1451,7 @@ nvc8_chipset = {
 	.disp = gt215_disp_new,
 	.dma = gf100_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf110_gr_new,
+	.gr = gf110_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1486,7 +1486,7 @@ nvce_chipset = {
 	.disp = gt215_disp_new,
 	.dma = gf100_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf104_gr_new,
+	.gr = gf104_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1520,7 +1520,7 @@ nvcf_chipset = {
 	.disp = gt215_disp_new,
 	.dma = gf100_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf104_gr_new,
+	.gr = gf104_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1552,7 +1552,7 @@ nvd7_chipset = {
 	.disp = gf119_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf117_gr_new,
+	.gr = gf117_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1586,7 +1586,7 @@ nvd9_chipset = {
 	.disp = gf119_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gf100_fifo_new,
-//	.gr = gf119_gr_new,
+	.gr = gf119_gr_new,
 	.mspdec = gf100_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gf100_msvld_new,
@@ -1622,7 +1622,7 @@ nve4_chipset = {
 	.disp = gk104_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gk104_fifo_new,
-//	.gr = gk104_gr_new,
+	.gr = gk104_gr_new,
 	.mspdec = gk104_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gk104_msvld_new,
@@ -1658,7 +1658,7 @@ nve6_chipset = {
 	.disp = gk104_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gk104_fifo_new,
-//	.gr = gk104_gr_new,
+	.gr = gk104_gr_new,
 	.mspdec = gk104_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gk104_msvld_new,
@@ -1694,7 +1694,7 @@ nve7_chipset = {
 	.disp = gk104_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gk104_fifo_new,
-//	.gr = gk104_gr_new,
+	.gr = gk104_gr_new,
 	.mspdec = gk104_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gk104_msvld_new,
@@ -1721,7 +1721,7 @@ nvea_chipset = {
 	.ce[2] = gk104_ce_new,
 	.dma = gf119_dma_new,
 	.fifo = gk20a_fifo_new,
-//	.gr = gk20a_gr_new,
+	.gr = gk20a_gr_new,
 //	.pm = gk104_pm_new,
 //	.sw = gf100_sw_new,
 };
@@ -1754,7 +1754,7 @@ nvf0_chipset = {
 	.disp = gk110_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gk104_fifo_new,
-//	.gr = gk110_gr_new,
+	.gr = gk110_gr_new,
 	.mspdec = gk104_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gk104_msvld_new,
@@ -1790,7 +1790,7 @@ nvf1_chipset = {
 	.disp = gk110_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gk104_fifo_new,
-//	.gr = gk110b_gr_new,
+	.gr = gk110b_gr_new,
 	.mspdec = gk104_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gk104_msvld_new,
@@ -1826,7 +1826,7 @@ nv106_chipset = {
 	.disp = gk110_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gk208_fifo_new,
-//	.gr = gk208_gr_new,
+	.gr = gk208_gr_new,
 	.mspdec = gk104_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gk104_msvld_new,
@@ -1861,7 +1861,7 @@ nv108_chipset = {
 	.disp = gk110_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gk208_fifo_new,
-//	.gr = gk208_gr_new,
+	.gr = gk208_gr_new,
 	.mspdec = gk104_mspdec_new,
 	.msppp = gf100_msppp_new,
 	.msvld = gk104_msvld_new,
@@ -1894,7 +1894,7 @@ nv117_chipset = {
 	.disp = gm107_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gk208_fifo_new,
-//	.gr = gm107_gr_new,
+	.gr = gm107_gr_new,
 //	.sw = gf100_sw_new,
 };
 
@@ -1923,7 +1923,7 @@ nv124_chipset = {
 	.disp = gm204_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gm204_fifo_new,
-//	.gr = gm204_gr_new,
+	.gr = gm204_gr_new,
 //	.sw = gf100_sw_new,
 };
 
@@ -1952,7 +1952,7 @@ nv126_chipset = {
 	.disp = gm204_disp_new,
 	.dma = gf119_dma_new,
 	.fifo = gm204_fifo_new,
-//	.gr = gm206_gr_new,
+	.gr = gm206_gr_new,
 //	.sw = gf100_sw_new,
 };
 
@@ -1973,7 +1973,7 @@ nv12b_chipset = {
 	.ce[2] = gm204_ce_new,
 	.dma = gf119_dma_new,
 	.fifo = gm20b_fifo_new,
-//	.gr = gm20b_gr_new,
+	.gr = gm20b_gr_new,
 //	.sw = gf100_sw_new,
 };
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c
index d319f5680f440..b88aceb343c8a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c
@@ -29,47 +29,38 @@ gf100_identify(struct nvkm_device *device)
 	switch (device->chipset) {
 	case 0xc0:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf100_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf100_pm_oclass;
 		break;
 	case 0xc4:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf104_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf100_pm_oclass;
 		break;
 	case 0xc3:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf104_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf100_pm_oclass;
 		break;
 	case 0xce:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf104_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf100_pm_oclass;
 		break;
 	case 0xcf:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf104_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf100_pm_oclass;
 		break;
 	case 0xc1:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf108_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf108_pm_oclass;
 		break;
 	case 0xc8:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf110_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf100_pm_oclass;
 		break;
 	case 0xd9:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf119_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf117_pm_oclass;
 		break;
 	case 0xd7:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gf117_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gf117_pm_oclass;
 		break;
 	default:
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c
index fe8298e02e9f3..1ad7b217e2b86 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c
@@ -29,41 +29,33 @@ gk104_identify(struct nvkm_device *device)
 	switch (device->chipset) {
 	case 0xe4:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk104_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gk104_pm_oclass;
 		break;
 	case 0xe7:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk104_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gk104_pm_oclass;
 		break;
 	case 0xe6:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk104_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gk104_pm_oclass;
 		break;
 	case 0xea:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk20a_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = gk104_pm_oclass;
 		break;
 	case 0xf0:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk110_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = &gk110_pm_oclass;
 		break;
 	case 0xf1:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk110b_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] = &gk110_pm_oclass;
 		break;
 	case 0x106:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk208_gr_oclass;
 		break;
 	case 0x108:
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gk208_gr_oclass;
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
index 2362a634462c3..71e088abb620b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
@@ -32,7 +32,6 @@ gm100_identify(struct nvkm_device *device)
 #if 0
 #endif
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gm107_gr_oclass;
 #if 0
 #endif
 #if 0
@@ -46,7 +45,6 @@ gm100_identify(struct nvkm_device *device)
 #if 0
 #endif
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gm204_gr_oclass;
 #if 0
 #endif
 		break;
@@ -58,14 +56,12 @@ gm100_identify(struct nvkm_device *device)
 #if 0
 #endif
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gm206_gr_oclass;
 #if 0
 #endif
 		break;
 	case 0x12b:
 
 		device->oclass[NVDEV_ENGINE_SW     ] =  gf100_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] =  gm20b_gr_oclass;
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c
index edddbaa41b43d..7a8071be7ed0d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c
@@ -29,11 +29,9 @@ nv04_identify(struct nvkm_device *device)
 	switch (device->chipset) {
 	case 0x04:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv04_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv04_gr_oclass;
 		break;
 	case 0x05:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv04_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv04_gr_oclass;
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c
index f1ebb9bcda3b6..15dbd71ebabf0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c
@@ -28,35 +28,27 @@ nv10_identify(struct nvkm_device *device)
 {
 	switch (device->chipset) {
 	case 0x10:
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
 		break;
 	case 0x15:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
 		break;
 	case 0x16:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
 		break;
 	case 0x1a:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
 		break;
 	case 0x11:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
 		break;
 	case 0x17:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
 		break;
 	case 0x1f:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
 		break;
 	case 0x18:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv10_gr_oclass;
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c
index f9c4dad1f8ff0..158efa44054f5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c
@@ -29,19 +29,15 @@ nv20_identify(struct nvkm_device *device)
 	switch (device->chipset) {
 	case 0x20:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv20_gr_oclass;
 		break;
 	case 0x25:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv25_gr_oclass;
 		break;
 	case 0x28:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv25_gr_oclass;
 		break;
 	case 0x2a:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv2a_gr_oclass;
 		break;
 	default:
 		return -EINVAL;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c
index b8e1e43723a3f..5a8fd485467a5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c
@@ -29,25 +29,20 @@ nv30_identify(struct nvkm_device *device)
 	switch (device->chipset) {
 	case 0x30:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv30_gr_oclass;
 		break;
 	case 0x35:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv35_gr_oclass;
 		break;
 	case 0x31:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv30_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
 		break;
 	case 0x36:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv35_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
 		break;
 	case 0x34:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv34_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
 		break;
 	default:
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c
index 158ed5e395df4..e3fdbf6ba8713 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c
@@ -29,97 +29,81 @@ nv40_identify(struct nvkm_device *device)
 	switch (device->chipset) {
 	case 0x40:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x41:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x42:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x43:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x45:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x47:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x49:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x4b:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x44:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x46:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x4a:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x4c:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x4e:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x63:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x67:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
 	case 0x68:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv10_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv40_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv40_pm_oclass;
 		break;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c
index 688b3e2d61ff9..912bd8070db76 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c
@@ -29,80 +29,66 @@ nv50_identify(struct nvkm_device *device)
 	switch (device->chipset) {
 	case 0x50:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &nv50_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  nv50_pm_oclass;
 		break;
 	case 0x84:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
 		break;
 	case 0x86:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
 		break;
 	case 0x92:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
 		break;
 	case 0x94:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
 		break;
 	case 0x96:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
 		break;
 	case 0x98:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
 		break;
 	case 0xa0:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  gt200_pm_oclass;
 		break;
 	case 0xaa:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
 		break;
 	case 0xac:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  g84_pm_oclass;
 		break;
 	case 0xa3:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_MPEG   ] = &g84_mpeg_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  gt215_pm_oclass;
 		break;
 	case 0xa5:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  gt215_pm_oclass;
 		break;
 	case 0xa8:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  gt215_pm_oclass;
 		break;
 	case 0xaf:
 		device->oclass[NVDEV_ENGINE_SW     ] =  nv50_sw_oclass;
-		device->oclass[NVDEV_ENGINE_GR     ] = &nv50_gr_oclass;
 		device->oclass[NVDEV_ENGINE_PM     ] =  gt215_pm_oclass;
 		break;
 	default:
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
index 79eceaac3c1d5..9ad0d0e78a96e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
@@ -1,6 +1,8 @@
 nvkm-y += nvkm/engine/gr/base.o
 nvkm-y += nvkm/engine/gr/nv04.o
 nvkm-y += nvkm/engine/gr/nv10.o
+nvkm-y += nvkm/engine/gr/nv15.o
+nvkm-y += nvkm/engine/gr/nv17.o
 nvkm-y += nvkm/engine/gr/nv20.o
 nvkm-y += nvkm/engine/gr/nv25.o
 nvkm-y += nvkm/engine/gr/nv2a.o
@@ -8,18 +10,24 @@ nvkm-y += nvkm/engine/gr/nv30.o
 nvkm-y += nvkm/engine/gr/nv34.o
 nvkm-y += nvkm/engine/gr/nv35.o
 nvkm-y += nvkm/engine/gr/nv40.o
+nvkm-y += nvkm/engine/gr/nv44.o
 nvkm-y += nvkm/engine/gr/nv50.o
+nvkm-y += nvkm/engine/gr/g84.o
+nvkm-y += nvkm/engine/gr/gt200.o
+nvkm-y += nvkm/engine/gr/mcp79.o
+nvkm-y += nvkm/engine/gr/gt215.o
+nvkm-y += nvkm/engine/gr/mcp89.o
 nvkm-y += nvkm/engine/gr/gf100.o
-nvkm-y += nvkm/engine/gr/gf108.o
 nvkm-y += nvkm/engine/gr/gf104.o
+nvkm-y += nvkm/engine/gr/gf108.o
 nvkm-y += nvkm/engine/gr/gf110.o
 nvkm-y += nvkm/engine/gr/gf117.o
 nvkm-y += nvkm/engine/gr/gf119.o
 nvkm-y += nvkm/engine/gr/gk104.o
-nvkm-y += nvkm/engine/gr/gk20a.o
 nvkm-y += nvkm/engine/gr/gk110.o
 nvkm-y += nvkm/engine/gr/gk110b.o
 nvkm-y += nvkm/engine/gr/gk208.o
+nvkm-y += nvkm/engine/gr/gk20a.o
 nvkm-y += nvkm/engine/gr/gm107.o
 nvkm-y += nvkm/engine/gr/gm204.o
 nvkm-y += nvkm/engine/gr/gm206.o
@@ -28,16 +36,16 @@ nvkm-y += nvkm/engine/gr/gm20b.o
 nvkm-y += nvkm/engine/gr/ctxnv40.o
 nvkm-y += nvkm/engine/gr/ctxnv50.o
 nvkm-y += nvkm/engine/gr/ctxgf100.o
-nvkm-y += nvkm/engine/gr/ctxgf108.o
 nvkm-y += nvkm/engine/gr/ctxgf104.o
+nvkm-y += nvkm/engine/gr/ctxgf108.o
 nvkm-y += nvkm/engine/gr/ctxgf110.o
 nvkm-y += nvkm/engine/gr/ctxgf117.o
 nvkm-y += nvkm/engine/gr/ctxgf119.o
 nvkm-y += nvkm/engine/gr/ctxgk104.o
-nvkm-y += nvkm/engine/gr/ctxgk20a.o
 nvkm-y += nvkm/engine/gr/ctxgk110.o
 nvkm-y += nvkm/engine/gr/ctxgk110b.o
 nvkm-y += nvkm/engine/gr/ctxgk208.o
+nvkm-y += nvkm/engine/gr/ctxgk20a.o
 nvkm-y += nvkm/engine/gr/ctxgm107.o
 nvkm-y += nvkm/engine/gr/ctxgm204.o
 nvkm-y += nvkm/engine/gr/ctxgm206.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
index c6fb25847b89d..090765ff070de 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c
@@ -25,6 +25,30 @@
 
 #include <engine/fifo.h>
 
+static void
+nvkm_gr_tile(struct nvkm_engine *engine, int region, struct nvkm_fb_tile *tile)
+{
+	struct nvkm_gr *gr = nvkm_gr(engine);
+	if (gr->func->tile)
+		gr->func->tile(gr, region, tile);
+}
+
+u64
+nvkm_gr_units(struct nvkm_gr *gr)
+{
+	if (gr->func->units)
+		return gr->func->units(gr);
+	return 0;
+}
+
+int
+nvkm_gr_tlb_flush(struct nvkm_gr *gr)
+{
+	if (gr->func->tlb_flush)
+		return gr->func->tlb_flush(gr);
+	return -ENODEV;
+}
+
 static int
 nvkm_gr_oclass_get(struct nvkm_oclass *oclass, int index)
 {
@@ -59,26 +83,54 @@ nvkm_gr_cclass_new(struct nvkm_fifo_chan *chan,
 	return 0;
 }
 
-struct nvkm_engine_func
+static void
+nvkm_gr_intr(struct nvkm_engine *engine)
+{
+	struct nvkm_gr *gr = nvkm_gr(engine);
+	gr->func->intr(gr);
+}
+
+static int
+nvkm_gr_oneinit(struct nvkm_engine *engine)
+{
+	struct nvkm_gr *gr = nvkm_gr(engine);
+	if (gr->func->oneinit)
+		return gr->func->oneinit(gr);
+	return 0;
+}
+
+static int
+nvkm_gr_init(struct nvkm_engine *engine)
+{
+	struct nvkm_gr *gr = nvkm_gr(engine);
+	return gr->func->init(gr);
+}
+
+static void *
+nvkm_gr_dtor(struct nvkm_engine *engine)
+{
+	struct nvkm_gr *gr = nvkm_gr(engine);
+	if (gr->func->dtor)
+		return gr->func->dtor(gr);
+	return gr;
+}
+
+static const struct nvkm_engine_func
 nvkm_gr = {
+	.dtor = nvkm_gr_dtor,
+	.oneinit = nvkm_gr_oneinit,
+	.init = nvkm_gr_init,
+	.intr = nvkm_gr_intr,
+	.tile = nvkm_gr_tile,
 	.fifo.cclass = nvkm_gr_cclass_new,
 	.fifo.sclass = nvkm_gr_oclass_get,
 };
 
 int
-nvkm_gr_create_(struct nvkm_object *parent, struct nvkm_object *engine,
-		struct nvkm_oclass *oclass, bool enable,
-		int length, void **pobject)
+nvkm_gr_ctor(const struct nvkm_gr_func *func, struct nvkm_device *device,
+	     int index, u32 pmc_enable, bool enable, struct nvkm_gr *gr)
 {
-	struct nvkm_gr *gr;
-	int ret;
-
-	ret = nvkm_engine_create_(parent, engine, oclass, enable,
-				  "gr", "gr", length, pobject);
-	gr = *pobject;
-	if (ret)
-		return ret;
-
-	gr->engine.func = &nvkm_gr;
-	return 0;
+	gr->func = func;
+	return nvkm_engine_ctor(&nvkm_gr, device, index, pmc_enable,
+				enable, &gr->engine);
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
index 43d9ce2276685..ddaa16a71c84d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
@@ -19,9 +19,8 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-
 #include "ctxgf100.h"
-#include "gk20a.h"
+#include "gf100.h"
 
 #include <subdev/mc.h>
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c
new file mode 100644
index 0000000000000..ce913300539fe
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/timer.h>
+
+static const struct nvkm_bitfield nv50_gr_status[] = {
+	{ 0x00000001, "BUSY" }, /* set when any bit is set */
+	{ 0x00000002, "DISPATCH" },
+	{ 0x00000004, "UNK2" },
+	{ 0x00000008, "UNK3" },
+	{ 0x00000010, "UNK4" },
+	{ 0x00000020, "UNK5" },
+	{ 0x00000040, "M2MF" },
+	{ 0x00000080, "UNK7" },
+	{ 0x00000100, "CTXPROG" },
+	{ 0x00000200, "VFETCH" },
+	{ 0x00000400, "CCACHE_PREGEOM" },
+	{ 0x00000800, "STRMOUT_VATTR_POSTGEOM" },
+	{ 0x00001000, "VCLIP" },
+	{ 0x00002000, "RATTR_APLANE" },
+	{ 0x00004000, "TRAST" },
+	{ 0x00008000, "CLIPID" },
+	{ 0x00010000, "ZCULL" },
+	{ 0x00020000, "ENG2D" },
+	{ 0x00040000, "RMASK" },
+	{ 0x00080000, "TPC_RAST" },
+	{ 0x00100000, "TPC_PROP" },
+	{ 0x00200000, "TPC_TEX" },
+	{ 0x00400000, "TPC_GEOM" },
+	{ 0x00800000, "TPC_MP" },
+	{ 0x01000000, "ROP" },
+	{}
+};
+
+static const struct nvkm_bitfield
+nv50_gr_vstatus_0[] = {
+	{ 0x01, "VFETCH" },
+	{ 0x02, "CCACHE" },
+	{ 0x04, "PREGEOM" },
+	{ 0x08, "POSTGEOM" },
+	{ 0x10, "VATTR" },
+	{ 0x20, "STRMOUT" },
+	{ 0x40, "VCLIP" },
+	{}
+};
+
+static const struct nvkm_bitfield
+nv50_gr_vstatus_1[] = {
+	{ 0x01, "TPC_RAST" },
+	{ 0x02, "TPC_PROP" },
+	{ 0x04, "TPC_TEX" },
+	{ 0x08, "TPC_GEOM" },
+	{ 0x10, "TPC_MP" },
+	{}
+};
+
+static const struct nvkm_bitfield
+nv50_gr_vstatus_2[] = {
+	{ 0x01, "RATTR" },
+	{ 0x02, "APLANE" },
+	{ 0x04, "TRAST" },
+	{ 0x08, "CLIPID" },
+	{ 0x10, "ZCULL" },
+	{ 0x20, "ENG2D" },
+	{ 0x40, "RMASK" },
+	{ 0x80, "ROP" },
+	{}
+};
+
+static void
+nvkm_gr_vstatus_print(struct nv50_gr *gr, int r,
+		      const struct nvkm_bitfield *units, u32 status)
+{
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	u32 stat = status;
+	u8  mask = 0x00;
+	char msg[64];
+	int i;
+
+	for (i = 0; units[i].name && status; i++) {
+		if ((status & 7) == 1)
+			mask |= (1 << i);
+		status >>= 3;
+	}
+
+	nvkm_snprintbf(msg, sizeof(msg), units, mask);
+	nvkm_error(subdev, "PGRAPH_VSTATUS%d: %08x [%s]\n", r, stat, msg);
+}
+
+int
+g84_gr_tlb_flush(struct nvkm_gr *base)
+{
+	struct nv50_gr *gr = nv50_gr(base);
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
+	struct nvkm_timer *tmr = device->timer;
+	bool idle, timeout = false;
+	unsigned long flags;
+	char status[128];
+	u64 start;
+	u32 tmp;
+
+	spin_lock_irqsave(&gr->lock, flags);
+	nvkm_mask(device, 0x400500, 0x00000001, 0x00000000);
+
+	start = nvkm_timer_read(tmr);
+	do {
+		idle = true;
+
+		for (tmp = nvkm_rd32(device, 0x400380); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+
+		for (tmp = nvkm_rd32(device, 0x400384); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+
+		for (tmp = nvkm_rd32(device, 0x400388); tmp && idle; tmp >>= 3) {
+			if ((tmp & 7) == 1)
+				idle = false;
+		}
+	} while (!idle &&
+		 !(timeout = nvkm_timer_read(tmr) - start > 2000000000));
+
+	if (timeout) {
+		nvkm_error(subdev, "PGRAPH TLB flush idle timeout fail\n");
+
+		tmp = nvkm_rd32(device, 0x400700);
+		nvkm_snprintbf(status, sizeof(status), nv50_gr_status, tmp);
+		nvkm_error(subdev, "PGRAPH_STATUS %08x [%s]\n", tmp, status);
+
+		nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0,
+				       nvkm_rd32(device, 0x400380));
+		nvkm_gr_vstatus_print(gr, 1, nv50_gr_vstatus_1,
+				       nvkm_rd32(device, 0x400384));
+		nvkm_gr_vstatus_print(gr, 2, nv50_gr_vstatus_2,
+				       nvkm_rd32(device, 0x400388));
+	}
+
+
+	nvkm_wr32(device, 0x100c80, 0x00000001);
+	nvkm_msec(device, 2000,
+		if (!(nvkm_rd32(device, 0x100c80) & 0x00000001))
+			break;
+	);
+	nvkm_mask(device, 0x400500, 0x00000001, 0x00000001);
+	spin_unlock_irqrestore(&gr->lock, flags);
+	return timeout ? -EBUSY : 0;
+}
+
+static const struct nvkm_gr_func
+g84_gr = {
+	.init = nv50_gr_init,
+	.intr = nv50_gr_intr,
+	.chan_new = nv50_gr_chan_new,
+	.tlb_flush = g84_gr_tlb_flush,
+	.units = nv50_gr_units,
+	.sclass = {
+		{ -1, -1, 0x0030, &nv50_gr_object },
+		{ -1, -1, 0x502d, &nv50_gr_object },
+		{ -1, -1, 0x5039, &nv50_gr_object },
+		{ -1, -1, 0x50c0, &nv50_gr_object },
+		{ -1, -1, 0x8297, &nv50_gr_object },
+		{}
+	}
+};
+
+int
+g84_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv50_gr_new_(&g84_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
index 8fd26fa03c2e7..1ad6785683f2c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -29,6 +29,7 @@
 #include <core/option.h>
 #include <subdev/fb.h>
 #include <subdev/mc.h>
+#include <subdev/pmu.h>
 #include <subdev/timer.h>
 #include <engine/fifo.h>
 
@@ -813,9 +814,9 @@ gf100_gr_mthd(struct gf100_gr *gr, const struct gf100_gr_pack *p)
 }
 
 u64
-gf100_gr_units(struct nvkm_gr *obj)
+gf100_gr_units(struct nvkm_gr *base)
 {
-	struct gf100_gr *gr = container_of(obj, typeof(*gr), base);
+	struct gf100_gr *gr = gf100_gr(base);
 	u64 cfg;
 
 	cfg  = (u32)gr->gpc_nr;
@@ -1173,10 +1174,11 @@ gf100_gr_ctxctl_isr(struct gf100_gr *gr)
 }
 
 static void
-gf100_gr_intr(struct nvkm_subdev *subdev)
+gf100_gr_intr(struct nvkm_gr *base)
 {
-	struct gf100_gr *gr = (void *)subdev;
-	struct nvkm_device *device = gr->base.engine.subdev.device;
+	struct gf100_gr *gr = gf100_gr(base);
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
 	struct nvkm_fifo_chan *chan;
 	unsigned long flags;
 	u64 inst = nvkm_rd32(device, 0x409b00) & 0x0fffffff;
@@ -1196,7 +1198,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev)
 		chid = chan->chid;
 	}
 
-	if (nv_device(gr)->card_type < NV_E0 || subc < 4)
+	if (device->card_type < NV_E0 || subc < 4)
 		class = nvkm_rd32(device, 0x404200 + (subc * 4));
 	else
 		class = 0x0000;
@@ -1334,16 +1336,13 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr)
 	const struct gf100_grctx_func *grctx = gr->func->grctx;
 	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
 	struct nvkm_device *device = subdev->device;
-	struct gf100_gr_oclass *oclass = (void *)nv_object(gr)->oclass;
 	int i;
 
 	if (gr->firmware) {
 		/* load fuc microcode */
 		nvkm_mc_unk260(device->mc, 0);
-		gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c,
-						 &gr->fuc409d);
-		gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac,
-						 &gr->fuc41ad);
+		gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, &gr->fuc409d);
+		gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, &gr->fuc41ad);
 		nvkm_mc_unk260(device->mc, 1);
 
 		/* start both of them running */
@@ -1389,7 +1388,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr)
 		) < 0)
 			return -EBUSY;
 
-		if (nv_device(gr)->chipset >= 0xe0) {
+		if (device->chipset >= 0xe0) {
 			nvkm_wr32(device, 0x409800, 0x00000000);
 			nvkm_wr32(device, 0x409500, 0x00000001);
 			nvkm_wr32(device, 0x409504, 0x00000030);
@@ -1434,33 +1433,33 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr)
 
 		return 0;
 	} else
-	if (!oclass->fecs.ucode) {
+	if (!gr->func->fecs.ucode) {
 		return -ENOSYS;
 	}
 
 	/* load HUB microcode */
 	nvkm_mc_unk260(device->mc, 0);
 	nvkm_wr32(device, 0x4091c0, 0x01000000);
-	for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++)
-		nvkm_wr32(device, 0x4091c4, oclass->fecs.ucode->data.data[i]);
+	for (i = 0; i < gr->func->fecs.ucode->data.size / 4; i++)
+		nvkm_wr32(device, 0x4091c4, gr->func->fecs.ucode->data.data[i]);
 
 	nvkm_wr32(device, 0x409180, 0x01000000);
-	for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) {
+	for (i = 0; i < gr->func->fecs.ucode->code.size / 4; i++) {
 		if ((i & 0x3f) == 0)
 			nvkm_wr32(device, 0x409188, i >> 6);
-		nvkm_wr32(device, 0x409184, oclass->fecs.ucode->code.data[i]);
+		nvkm_wr32(device, 0x409184, gr->func->fecs.ucode->code.data[i]);
 	}
 
 	/* load GPC microcode */
 	nvkm_wr32(device, 0x41a1c0, 0x01000000);
-	for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++)
-		nvkm_wr32(device, 0x41a1c4, oclass->gpccs.ucode->data.data[i]);
+	for (i = 0; i < gr->func->gpccs.ucode->data.size / 4; i++)
+		nvkm_wr32(device, 0x41a1c4, gr->func->gpccs.ucode->data.data[i]);
 
 	nvkm_wr32(device, 0x41a180, 0x01000000);
-	for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) {
+	for (i = 0; i < gr->func->gpccs.ucode->code.size / 4; i++) {
 		if ((i & 0x3f) == 0)
 			nvkm_wr32(device, 0x41a188, i >> 6);
-		nvkm_wr32(device, 0x41a184, oclass->gpccs.ucode->code.data[i]);
+		nvkm_wr32(device, 0x41a184, gr->func->gpccs.ucode->code.data[i]);
 	}
 	nvkm_mc_unk260(device->mc, 1);
 
@@ -1493,21 +1492,216 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr)
 	return 0;
 }
 
+static int
+gf100_gr_oneinit(struct nvkm_gr *base)
+{
+	struct gf100_gr *gr = gf100_gr(base);
+	struct nvkm_device *device = gr->base.engine.subdev.device;
+	int ret, i, j;
+
+	nvkm_pmu_pgob(device->pmu, false);
+
+	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false,
+			      &gr->unk4188b4);
+	if (ret)
+		return ret;
+
+	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false,
+			      &gr->unk4188b8);
+	if (ret)
+		return ret;
+
+	nvkm_kmap(gr->unk4188b4);
+	for (i = 0; i < 0x1000; i += 4)
+		nvkm_wo32(gr->unk4188b4, i, 0x00000010);
+	nvkm_done(gr->unk4188b4);
+
+	nvkm_kmap(gr->unk4188b8);
+	for (i = 0; i < 0x1000; i += 4)
+		nvkm_wo32(gr->unk4188b8, i, 0x00000010);
+	nvkm_done(gr->unk4188b8);
+
+	gr->rop_nr = (nvkm_rd32(device, 0x409604) & 0x001f0000) >> 16;
+	gr->gpc_nr =  nvkm_rd32(device, 0x409604) & 0x0000001f;
+	for (i = 0; i < gr->gpc_nr; i++) {
+		gr->tpc_nr[i]  = nvkm_rd32(device, GPC_UNIT(i, 0x2608));
+		gr->tpc_total += gr->tpc_nr[i];
+		gr->ppc_nr[i]  = gr->func->ppc_nr;
+		for (j = 0; j < gr->ppc_nr[i]; j++) {
+			u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4)));
+			gr->ppc_tpc_nr[i][j] = hweight8(mask);
+		}
+	}
+
+	/*XXX: these need figuring out... though it might not even matter */
+	switch (device->chipset) {
+	case 0xc0:
+		if (gr->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
+			gr->magic_not_rop_nr = 0x07;
+		} else
+		if (gr->tpc_total == 14) { /* 470, 3/3/4/4, 5 */
+			gr->magic_not_rop_nr = 0x05;
+		} else
+		if (gr->tpc_total == 15) { /* 480, 3/4/4/4, 6 */
+			gr->magic_not_rop_nr = 0x06;
+		}
+		break;
+	case 0xc3: /* 450, 4/0/0/0, 2 */
+		gr->magic_not_rop_nr = 0x03;
+		break;
+	case 0xc4: /* 460, 3/4/0/0, 4 */
+		gr->magic_not_rop_nr = 0x01;
+		break;
+	case 0xc1: /* 2/0/0/0, 1 */
+		gr->magic_not_rop_nr = 0x01;
+		break;
+	case 0xc8: /* 4/4/3/4, 5 */
+		gr->magic_not_rop_nr = 0x06;
+		break;
+	case 0xce: /* 4/4/0/0, 4 */
+		gr->magic_not_rop_nr = 0x03;
+		break;
+	case 0xcf: /* 4/0/0/0, 3 */
+		gr->magic_not_rop_nr = 0x03;
+		break;
+	case 0xd7:
+	case 0xd9: /* 1/0/0/0, 1 */
+	case 0xea: /* gk20a */
+	case 0x12b: /* gm20b */
+		gr->magic_not_rop_nr = 0x01;
+		break;
+	}
+
+	return 0;
+}
+
+int
+gf100_gr_init_(struct nvkm_gr *base)
+{
+	struct gf100_gr *gr = gf100_gr(base);
+	nvkm_pmu_pgob(gr->base.engine.subdev.device->pmu, false);
+	return gr->func->init(gr);
+}
+
+void
+gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc)
+{
+	kfree(fuc->data);
+	fuc->data = NULL;
+}
+
+void *
+gf100_gr_dtor(struct nvkm_gr *base)
+{
+	struct gf100_gr *gr = gf100_gr(base);
+
+	if (gr->func->dtor)
+		gr->func->dtor(gr);
+	kfree(gr->data);
+
+	gf100_gr_dtor_fw(&gr->fuc409c);
+	gf100_gr_dtor_fw(&gr->fuc409d);
+	gf100_gr_dtor_fw(&gr->fuc41ac);
+	gf100_gr_dtor_fw(&gr->fuc41ad);
+
+	nvkm_memory_del(&gr->unk4188b8);
+	nvkm_memory_del(&gr->unk4188b4);
+	return gr;
+}
+
+static const struct nvkm_gr_func
+gf100_gr_ = {
+	.dtor = gf100_gr_dtor,
+	.oneinit = gf100_gr_oneinit,
+	.init = gf100_gr_init_,
+	.intr = gf100_gr_intr,
+	.units = gf100_gr_units,
+	.chan_new = gf100_gr_chan_new,
+	.object_get = gf100_gr_object_get,
+};
+
+int
+gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname,
+		 struct gf100_gr_fuc *fuc)
+{
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
+	const struct firmware *fw;
+	char f[64];
+	char cname[16];
+	int ret;
+	int i;
+
+	/* Convert device name to lowercase */
+	strncpy(cname, device->chip->name, sizeof(cname));
+	cname[sizeof(cname) - 1] = '\0';
+	i = strlen(cname);
+	while (i) {
+		--i;
+		cname[i] = tolower(cname[i]);
+	}
+
+	snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname);
+	ret = request_firmware(&fw, f, nv_device_base(device));
+	if (ret) {
+		nvkm_error(subdev, "failed to load %s\n", fwname);
+		return ret;
+	}
+
+	fuc->size = fw->size;
+	fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+	release_firmware(fw);
+	return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+int
+gf100_gr_ctor(const struct gf100_gr_func *func, struct nvkm_device *device,
+	      int index, struct gf100_gr *gr)
+{
+	int ret;
+
+	gr->func = func;
+	gr->firmware = nvkm_boolopt(device->cfgopt, "NvGrUseFW",
+				    func->fecs.ucode == NULL);
+
+	ret = nvkm_gr_ctor(&gf100_gr_, device, index, 0x08001000,
+			   gr->firmware || func->fecs.ucode != NULL,
+			   &gr->base);
+	if (ret)
+		return ret;
+
+	if (gr->firmware) {
+		nvkm_info(&gr->base.engine.subdev, "using external firmware\n");
+		if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) ||
+		    gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) ||
+		    gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) ||
+		    gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad))
+			return -ENODEV;
+	}
+
+	return 0;
+}
+
 int
-gf100_gr_init(struct nvkm_object *object)
+gf100_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
+	      int index, struct nvkm_gr **pgr)
+{
+	struct gf100_gr *gr;
+	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+		return -ENOMEM;
+	*pgr = &gr->base;
+	return gf100_gr_ctor(func, device, index, gr);
+}
+
+int
+gf100_gr_init(struct gf100_gr *gr)
 {
-	struct gf100_gr *gr = (void *)object;
 	struct nvkm_device *device = gr->base.engine.subdev.device;
-	struct gf100_gr_oclass *oclass = (void *)object->oclass;
 	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total);
 	u32 data[TPC_MAX / 8] = {};
 	u8  tpcnr[GPC_MAX];
 	int gpc, tpc, rop;
-	int ret, i;
-
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
+	int i;
 
 	nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000);
 	nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000);
@@ -1518,7 +1712,7 @@ gf100_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8);
 	nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8);
 
-	gf100_gr_mmio(gr, oclass->mmio);
+	gf100_gr_mmio(gr, gr->func->mmio);
 
 	memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr));
 	for (i = 0, gpc = -1; i < gr->tpc_total; i++) {
@@ -1543,7 +1737,7 @@ gf100_gr_init(struct nvkm_object *object)
 		nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918);
 	}
 
-	if (nv_device(gr)->chipset != 0xd7)
+	if (device->chipset != 0xd7)
 		nvkm_wr32(device, GPC_BCAST(0x1bd4), magicgpc918);
 	else
 		nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918);
@@ -1606,182 +1800,6 @@ gf100_gr_init(struct nvkm_object *object)
 	return gf100_gr_init_ctxctl(gr);
 }
 
-void
-gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc)
-{
-	kfree(fuc->data);
-	fuc->data = NULL;
-}
-
-int
-gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname,
-		 struct gf100_gr_fuc *fuc)
-{
-	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
-	struct nvkm_device *device = subdev->device;
-	const struct firmware *fw;
-	char f[64];
-	char cname[16];
-	int ret;
-	int i;
-
-	/* Convert device name to lowercase */
-	strncpy(cname, device->chip->name, sizeof(cname));
-	cname[sizeof(cname) - 1] = '\0';
-	i = strlen(cname);
-	while (i) {
-		--i;
-		cname[i] = tolower(cname[i]);
-	}
-
-	snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname);
-	ret = request_firmware(&fw, f, nv_device_base(device));
-	if (ret) {
-		nvkm_error(subdev, "failed to load %s\n", fwname);
-		return ret;
-	}
-
-	fuc->size = fw->size;
-	fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
-	release_firmware(fw);
-	return (fuc->data != NULL) ? 0 : -ENOMEM;
-}
-
-void
-gf100_gr_dtor(struct nvkm_object *object)
-{
-	struct gf100_gr *gr = (void *)object;
-
-	kfree(gr->data);
-
-	gf100_gr_dtor_fw(&gr->fuc409c);
-	gf100_gr_dtor_fw(&gr->fuc409d);
-	gf100_gr_dtor_fw(&gr->fuc41ac);
-	gf100_gr_dtor_fw(&gr->fuc41ad);
-
-	nvkm_memory_del(&gr->unk4188b8);
-	nvkm_memory_del(&gr->unk4188b4);
-
-	nvkm_gr_destroy(&gr->base);
-}
-
-static const struct nvkm_gr_func
-gf100_gr_ = {
-	.chan_new = gf100_gr_chan_new,
-	.object_get = gf100_gr_object_get,
-};
-
-int
-gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	      struct nvkm_oclass *bclass, void *data, u32 size,
-	      struct nvkm_object **pobject)
-{
-	struct gf100_gr_oclass *oclass = (void *)bclass;
-	struct nvkm_device *device = (void *)parent;
-	struct gf100_gr *gr;
-	bool use_ext_fw, enable;
-	int ret, i, j;
-
-	use_ext_fw = nvkm_boolopt(device->cfgopt, "NvGrUseFW",
-				  oclass->fecs.ucode == NULL);
-	enable = use_ext_fw || oclass->fecs.ucode != NULL;
-
-	ret = nvkm_gr_create(parent, engine, bclass, enable, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	gr->func = oclass->func;
-	gr->base.func = &gf100_gr_;
-	nv_subdev(gr)->unit = 0x08001000;
-	nv_subdev(gr)->intr = gf100_gr_intr;
-
-	gr->base.units = gf100_gr_units;
-
-	if (use_ext_fw) {
-		nvkm_info(&gr->base.engine.subdev, "using external firmware\n");
-		if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) ||
-		    gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) ||
-		    gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) ||
-		    gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad))
-			return -ENODEV;
-		gr->firmware = true;
-	}
-
-	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false,
-			      &gr->unk4188b4);
-	if (ret)
-		return ret;
-
-	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false,
-			      &gr->unk4188b8);
-	if (ret)
-		return ret;
-
-	nvkm_kmap(gr->unk4188b4);
-	for (i = 0; i < 0x1000; i += 4)
-		nvkm_wo32(gr->unk4188b4, i, 0x00000010);
-	nvkm_done(gr->unk4188b4);
-
-	nvkm_kmap(gr->unk4188b8);
-	for (i = 0; i < 0x1000; i += 4)
-		nvkm_wo32(gr->unk4188b8, i, 0x00000010);
-	nvkm_done(gr->unk4188b8);
-
-	gr->rop_nr = (nvkm_rd32(device, 0x409604) & 0x001f0000) >> 16;
-	gr->gpc_nr =  nvkm_rd32(device, 0x409604) & 0x0000001f;
-	for (i = 0; i < gr->gpc_nr; i++) {
-		gr->tpc_nr[i]  = nvkm_rd32(device, GPC_UNIT(i, 0x2608));
-		gr->tpc_total += gr->tpc_nr[i];
-		gr->ppc_nr[i]  = oclass->ppc_nr;
-		for (j = 0; j < gr->ppc_nr[i]; j++) {
-			u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4)));
-			gr->ppc_tpc_nr[i][j] = hweight8(mask);
-		}
-	}
-
-	/*XXX: these need figuring out... though it might not even matter */
-	switch (nv_device(gr)->chipset) {
-	case 0xc0:
-		if (gr->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
-			gr->magic_not_rop_nr = 0x07;
-		} else
-		if (gr->tpc_total == 14) { /* 470, 3/3/4/4, 5 */
-			gr->magic_not_rop_nr = 0x05;
-		} else
-		if (gr->tpc_total == 15) { /* 480, 3/4/4/4, 6 */
-			gr->magic_not_rop_nr = 0x06;
-		}
-		break;
-	case 0xc3: /* 450, 4/0/0/0, 2 */
-		gr->magic_not_rop_nr = 0x03;
-		break;
-	case 0xc4: /* 460, 3/4/0/0, 4 */
-		gr->magic_not_rop_nr = 0x01;
-		break;
-	case 0xc1: /* 2/0/0/0, 1 */
-		gr->magic_not_rop_nr = 0x01;
-		break;
-	case 0xc8: /* 4/4/3/4, 5 */
-		gr->magic_not_rop_nr = 0x06;
-		break;
-	case 0xce: /* 4/4/0/0, 4 */
-		gr->magic_not_rop_nr = 0x03;
-		break;
-	case 0xcf: /* 4/0/0/0, 3 */
-		gr->magic_not_rop_nr = 0x03;
-		break;
-	case 0xd7:
-	case 0xd9: /* 1/0/0/0, 1 */
-	case 0xea: /* gk20a */
-	case 0x12b: /* gm20b */
-		gr->magic_not_rop_nr = 0x01;
-		break;
-	}
-
-	return 0;
-}
-
 #include "fuc/hubgf100.fuc3.h"
 
 struct gf100_gr_ucode
@@ -1804,6 +1822,10 @@ gf100_gr_gpccs_ucode = {
 
 static const struct gf100_gr_func
 gf100_gr = {
+	.init = gf100_gr_init,
+	.mmio = gf100_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
 	.grctx = &gf100_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -1814,17 +1836,8 @@ gf100_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gf100_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xc0),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gf100_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gf100_gr,
-	.mmio = gf100_gr_pack_mmio,
-	.fecs.ucode = &gf100_gr_fecs_ucode,
-	.gpccs.ucode = &gf100_gr_gpccs_ucode,
-}.base;
+int
+gf100_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gf100_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
index 43e9897ac8838..4611961b11874 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
@@ -21,8 +21,8 @@
  *
  * Authors: Ben Skeggs
  */
-#ifndef __NVC0_GR_H__
-#define __NVC0_GR_H__
+#ifndef __GF100_GR_H__
+#define __GF100_GR_H__
 #define gf100_gr(p) container_of((p), struct gf100_gr, base)
 #include "priv.h"
 
@@ -71,8 +71,8 @@ struct gf100_gr_zbc_depth {
 };
 
 struct gf100_gr {
-	struct nvkm_gr base;
 	const struct gf100_gr_func *func;
+	struct nvkm_gr base;
 
 	struct gf100_gr_fuc fuc409c;
 	struct gf100_gr_fuc fuc409d;
@@ -110,11 +110,40 @@ struct gf100_gr {
 	u8 magic_not_rop_nr;
 };
 
+int gf100_gr_ctor(const struct gf100_gr_func *, struct nvkm_device *,
+		  int, struct gf100_gr *);
+int gf100_gr_new_(const struct gf100_gr_func *, struct nvkm_device *,
+		  int, struct nvkm_gr **);
+void *gf100_gr_dtor(struct nvkm_gr *);
+
 struct gf100_gr_func {
+	void (*dtor)(struct gf100_gr *);
+	int (*init)(struct gf100_gr *);
+	void (*init_gpc_mmu)(struct gf100_gr *);
+	void (*set_hww_esr_report_mask)(struct gf100_gr *);
+	const struct gf100_gr_pack *mmio;
+	struct {
+		struct gf100_gr_ucode *ucode;
+	} fecs;
+	struct {
+		struct gf100_gr_ucode *ucode;
+	} gpccs;
+	int ppc_nr;
 	const struct gf100_grctx_func *grctx;
 	struct nvkm_sclass sclass[];
 };
 
+int gf100_gr_init(struct gf100_gr *);
+
+int gk104_gr_init(struct gf100_gr *);
+
+int gk20a_gr_new_(const struct gf100_gr_func *, struct nvkm_device *,
+		  int, struct nvkm_gr **);
+void gk20a_gr_dtor(struct gf100_gr *);
+int gk20a_gr_init(struct gf100_gr *);
+
+int gm204_gr_init(struct gf100_gr *);
+
 #define gf100_gr_chan(p) container_of((p), struct gf100_gr_chan, object)
 
 struct gf100_gr_chan {
@@ -137,33 +166,10 @@ void gf100_gr_dtor_fw(struct gf100_gr_fuc *);
 int  gf100_gr_ctor_fw(struct gf100_gr *, const char *,
 		      struct gf100_gr_fuc *);
 u64  gf100_gr_units(struct nvkm_gr *);
-int  gf100_gr_ctor(struct nvkm_object *, struct nvkm_object *,
-		     struct nvkm_oclass *, void *data, u32 size,
-		     struct nvkm_object **);
-void gf100_gr_dtor(struct nvkm_object *);
-int  gf100_gr_init(struct nvkm_object *);
 void gf100_gr_zbc_init(struct gf100_gr *);
 
-int  gk104_gr_ctor(struct nvkm_object *, struct nvkm_object *,
-		     struct nvkm_oclass *, void *data, u32 size,
-		     struct nvkm_object **);
-int  gk104_gr_init(struct nvkm_object *);
-
-int  gk20a_gr_ctor(struct nvkm_object *, struct nvkm_object *,
-		     struct nvkm_oclass *, void *data, u32 size,
-		     struct nvkm_object **);
-void gk20a_gr_dtor(struct nvkm_object *);
-int  gk20a_gr_init(struct nvkm_object *);
-
-int  gm204_gr_init(struct nvkm_object *);
-
 extern const struct nvkm_object_func gf100_fermi;
 
-extern struct nvkm_oclass gf100_gr_sclass[];
-extern struct nvkm_oclass gf110_gr_sclass[];
-extern struct nvkm_oclass gk110_gr_sclass[];
-extern struct nvkm_oclass gm204_gr_sclass[];
-
 struct gf100_gr_init {
 	u32 addr;
 	u8  count;
@@ -191,19 +197,6 @@ extern struct gf100_gr_ucode gf100_gr_gpccs_ucode;
 extern struct gf100_gr_ucode gk110_gr_fecs_ucode;
 extern struct gf100_gr_ucode gk110_gr_gpccs_ucode;
 
-struct gf100_gr_oclass {
-	struct nvkm_oclass base;
-	const struct gf100_gr_func *func;
-	const struct gf100_gr_pack *mmio;
-	struct {
-		struct gf100_gr_ucode *ucode;
-	} fecs;
-	struct {
-		struct gf100_gr_ucode *ucode;
-	} gpccs;
-	int ppc_nr;
-};
-
 int  gf100_gr_wait_idle(struct gf100_gr *);
 void gf100_gr_mmio(struct gf100_gr *, const struct gf100_gr_pack *);
 void gf100_gr_icmd(struct gf100_gr *, const struct gf100_gr_pack *);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
index aa529b5c0daaf..8f253e0a22f40 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
@@ -114,6 +114,10 @@ gf104_gr_pack_mmio[] = {
 
 static const struct gf100_gr_func
 gf104_gr = {
+	.init = gf100_gr_init,
+	.mmio = gf104_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
 	.grctx = &gf104_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -124,17 +128,8 @@ gf104_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gf104_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xc3),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gf100_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gf104_gr,
-	.mmio = gf104_gr_pack_mmio,
-	.fecs.ucode = &gf100_gr_fecs_ucode,
-	.gpccs.ucode = &gf100_gr_gpccs_ucode,
-}.base;
+int
+gf104_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gf104_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
index 971c897d59be9..815a5aafa2457 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
@@ -105,6 +105,10 @@ gf108_gr_pack_mmio[] = {
 
 static const struct gf100_gr_func
 gf108_gr = {
+	.init = gf100_gr_init,
+	.mmio = gf108_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
 	.grctx = &gf108_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -116,17 +120,8 @@ gf108_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gf108_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xc1),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gf100_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gf108_gr,
-	.mmio = gf108_gr_pack_mmio,
-	.fecs.ucode = &gf100_gr_fecs_ucode,
-	.gpccs.ucode = &gf100_gr_gpccs_ucode,
-}.base;
+int
+gf108_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gf108_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
index f832a8bd454ce..d13187409d685 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
@@ -86,6 +86,10 @@ gf110_gr_pack_mmio[] = {
 
 static const struct gf100_gr_func
 gf110_gr = {
+	.init = gf100_gr_init,
+	.mmio = gf110_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
 	.grctx = &gf110_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -98,17 +102,8 @@ gf110_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gf110_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xc8),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gf100_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gf110_gr,
-	.mmio = gf110_gr_pack_mmio,
-	.fecs.ucode = &gf100_gr_fecs_ucode,
-	.gpccs.ucode = &gf100_gr_gpccs_ucode,
-}.base;
+int
+gf110_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gf110_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
index 909b5a6fa8d2d..28483d8bf3d2e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
@@ -122,6 +122,11 @@ gf117_gr_gpccs_ucode = {
 
 static const struct gf100_gr_func
 gf117_gr = {
+	.init = gf100_gr_init,
+	.mmio = gf117_gr_pack_mmio,
+	.fecs.ucode = &gf117_gr_fecs_ucode,
+	.gpccs.ucode = &gf117_gr_gpccs_ucode,
+	.ppc_nr = 1,
 	.grctx = &gf117_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -134,18 +139,8 @@ gf117_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gf117_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xd7),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gf100_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gf117_gr,
-	.mmio = gf117_gr_pack_mmio,
-	.fecs.ucode = &gf117_gr_fecs_ucode,
-	.gpccs.ucode = &gf117_gr_gpccs_ucode,
-	.ppc_nr = 1,
-}.base;
+int
+gf117_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gf117_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
index 01c2dcc4e8733..9811a72e03133 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
@@ -177,6 +177,10 @@ gf119_gr_pack_mmio[] = {
 
 static const struct gf100_gr_func
 gf119_gr = {
+	.init = gf100_gr_init,
+	.mmio = gf119_gr_pack_mmio,
+	.fecs.ucode = &gf100_gr_fecs_ucode,
+	.gpccs.ucode = &gf100_gr_gpccs_ucode,
 	.grctx = &gf119_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -189,17 +193,8 @@ gf119_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gf119_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xd9),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gf100_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gf119_gr,
-	.mmio = gf119_gr_pack_mmio,
-	.fecs.ucode = &gf100_gr_fecs_ucode,
-	.gpccs.ucode = &gf100_gr_gpccs_ucode,
-}.base;
+int
+gf119_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gf119_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
index efd5ebd1fa046..abf54928a1a44 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
@@ -24,8 +24,6 @@
 #include "gf100.h"
 #include "ctxgf100.h"
 
-#include <subdev/pmu.h>
-
 #include <nvif/class.h>
 
 /*******************************************************************************
@@ -180,22 +178,14 @@ gk104_gr_pack_mmio[] = {
  ******************************************************************************/
 
 int
-gk104_gr_init(struct nvkm_object *object)
+gk104_gr_init(struct gf100_gr *gr)
 {
-	struct gf100_gr_oclass *oclass = (void *)object->oclass;
-	struct gf100_gr *gr = (void *)object;
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total);
 	u32 data[TPC_MAX / 8] = {};
 	u8  tpcnr[GPC_MAX];
 	int gpc, tpc, rop;
-	int ret, i;
-
-	nvkm_pmu_pgob(device->pmu, false);
-
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
+	int i;
 
 	nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000);
 	nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000);
@@ -206,7 +196,7 @@ gk104_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8);
 	nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8);
 
-	gf100_gr_mmio(gr, oclass->mmio);
+	gf100_gr_mmio(gr, gr->func->mmio);
 
 	nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001);
 
@@ -296,28 +286,6 @@ gk104_gr_init(struct nvkm_object *object)
 	return gf100_gr_init_ctxctl(gr);
 }
 
-static const struct gf100_gr_func
-gk104_gr = {
-	.grctx = &gk104_grctx,
-	.sclass = {
-		{ -1, -1, FERMI_TWOD_A },
-		{ -1, -1, KEPLER_INLINE_TO_MEMORY_A },
-		{ -1, -1, KEPLER_A, &gf100_fermi },
-		{ -1, -1, KEPLER_COMPUTE_A },
-		{}
-	}
-};
-
-int
-gk104_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	      struct nvkm_oclass *oclass, void *data, u32 size,
-	      struct nvkm_object **pobject)
-{
-	struct nvkm_device *device = (void *)parent;
-	nvkm_pmu_pgob(device->pmu, false);
-	return gf100_gr_ctor(parent, engine, oclass, data, size, pobject);
-}
-
 #include "fuc/hubgk104.fuc3.h"
 
 static struct gf100_gr_ucode
@@ -338,18 +306,25 @@ gk104_gr_gpccs_ucode = {
 	.data.size = sizeof(gk104_grgpc_data),
 };
 
-struct nvkm_oclass *
-gk104_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xe4),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gk104_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gk104_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gk104_gr,
+static const struct gf100_gr_func
+gk104_gr = {
+	.init = gk104_gr_init,
 	.mmio = gk104_gr_pack_mmio,
 	.fecs.ucode = &gk104_gr_fecs_ucode,
 	.gpccs.ucode = &gk104_gr_gpccs_ucode,
 	.ppc_nr = 1,
-}.base;
+	.grctx = &gk104_grctx,
+	.sclass = {
+		{ -1, -1, FERMI_TWOD_A },
+		{ -1, -1, KEPLER_INLINE_TO_MEMORY_A },
+		{ -1, -1, KEPLER_A, &gf100_fermi },
+		{ -1, -1, KEPLER_COMPUTE_A },
+		{}
+	}
+};
+
+int
+gk104_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gk104_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
index fb513ea8bbd2a..32aa2946e7b70 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
@@ -182,6 +182,11 @@ gk110_gr_gpccs_ucode = {
 
 static const struct gf100_gr_func
 gk110_gr = {
+	.init = gk104_gr_init,
+	.mmio = gk110_gr_pack_mmio,
+	.fecs.ucode = &gk110_gr_fecs_ucode,
+	.gpccs.ucode = &gk110_gr_gpccs_ucode,
+	.ppc_nr = 2,
 	.grctx = &gk110_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -192,18 +197,8 @@ gk110_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gk110_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xf0),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gk104_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gk104_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gk110_gr,
-	.mmio = gk110_gr_pack_mmio,
-	.fecs.ucode = &gk110_gr_fecs_ucode,
-	.gpccs.ucode = &gk110_gr_gpccs_ucode,
-	.ppc_nr = 2,
-}.base;
+int
+gk110_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gk110_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
index b3da907b2b70e..22f88afbf35fd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
@@ -102,6 +102,11 @@ gk110b_gr_pack_mmio[] = {
 
 static const struct gf100_gr_func
 gk110b_gr = {
+	.init = gk104_gr_init,
+	.mmio = gk110b_gr_pack_mmio,
+	.fecs.ucode = &gk110_gr_fecs_ucode,
+	.gpccs.ucode = &gk110_gr_gpccs_ucode,
+	.ppc_nr = 2,
 	.grctx = &gk110b_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -112,18 +117,8 @@ gk110b_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gk110b_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0xf1),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gk104_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gk104_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gk110b_gr,
-	.mmio = gk110b_gr_pack_mmio,
-	.fecs.ucode = &gk110_gr_fecs_ucode,
-	.gpccs.ucode = &gk110_gr_gpccs_ucode,
-	.ppc_nr = 2,
-}.base;
+int
+gk110b_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gk110b_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
index 243b0a3f67c25..ee7554fc87dc7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
@@ -161,6 +161,11 @@ gk208_gr_gpccs_ucode = {
 
 static const struct gf100_gr_func
 gk208_gr = {
+	.init = gk104_gr_init,
+	.mmio = gk208_gr_pack_mmio,
+	.fecs.ucode = &gk208_gr_fecs_ucode,
+	.gpccs.ucode = &gk208_gr_gpccs_ucode,
+	.ppc_nr = 1,
 	.grctx = &gk208_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -171,18 +176,8 @@ gk208_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gk208_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0x08),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gk104_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gk104_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gk208_gr,
-	.mmio = gk208_gr_pack_mmio,
-	.fecs.ucode = &gk208_gr_fecs_ucode,
-	.gpccs.ucode = &gk208_gr_gpccs_ucode,
-	.ppc_nr = 1,
-}.base;
+int
+gk208_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gk208_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
index a8100c4f5785d..b8758d3b8b51b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
@@ -19,7 +19,7 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-#include "gk20a.h"
+#include "gf100.h"
 #include "ctxgf100.h"
 
 #include <subdev/timer.h>
@@ -146,69 +146,6 @@ gk20a_gr_av_to_method(struct gf100_gr_fuc *fuc)
 	return pack;
 }
 
-int
-gk20a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	      struct nvkm_oclass *oclass, void *data, u32 size,
-	      struct nvkm_object **pobject)
-{
-	int err;
-	struct gf100_gr *gr;
-	struct gf100_gr_fuc fuc;
-
-	err = gf100_gr_ctor(parent, engine, oclass, data, size, pobject);
-	if (err)
-		return err;
-
-	gr = (void *)*pobject;
-
-	err = gf100_gr_ctor_fw(gr, "sw_nonctx", &fuc);
-	if (err)
-		return err;
-	gr->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc);
-	gf100_gr_dtor_fw(&fuc);
-	if (IS_ERR(gr->fuc_sw_nonctx))
-		return PTR_ERR(gr->fuc_sw_nonctx);
-
-	err = gf100_gr_ctor_fw(gr, "sw_ctx", &fuc);
-	if (err)
-		return err;
-	gr->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc);
-	gf100_gr_dtor_fw(&fuc);
-	if (IS_ERR(gr->fuc_sw_ctx))
-		return PTR_ERR(gr->fuc_sw_ctx);
-
-	err = gf100_gr_ctor_fw(gr, "sw_bundle_init", &fuc);
-	if (err)
-		return err;
-	gr->fuc_bundle = gk20a_gr_av_to_init(&fuc);
-	gf100_gr_dtor_fw(&fuc);
-	if (IS_ERR(gr->fuc_bundle))
-		return PTR_ERR(gr->fuc_bundle);
-
-	err = gf100_gr_ctor_fw(gr, "sw_method_init", &fuc);
-	if (err)
-		return err;
-	gr->fuc_method = gk20a_gr_av_to_method(&fuc);
-	gf100_gr_dtor_fw(&fuc);
-	if (IS_ERR(gr->fuc_method))
-		return PTR_ERR(gr->fuc_method);
-
-	return 0;
-}
-
-void
-gk20a_gr_dtor(struct nvkm_object *object)
-{
-	struct gf100_gr *gr = (void *)object;
-
-	gk20a_gr_init_dtor(gr->fuc_method);
-	gk20a_gr_init_dtor(gr->fuc_bundle);
-	gk20a_gr_init_dtor(gr->fuc_sw_ctx);
-	gk20a_gr_init_dtor(gr->fuc_sw_nonctx);
-
-	gf100_gr_dtor(object);
-}
-
 static int
 gk20a_gr_wait_mem_scrubbing(struct gf100_gr *gr)
 {
@@ -243,10 +180,8 @@ gk20a_gr_set_hww_esr_report_mask(struct gf100_gr *gr)
 }
 
 int
-gk20a_gr_init(struct nvkm_object *object)
+gk20a_gr_init(struct gf100_gr *gr)
 {
-	struct gk20a_gr_oclass *oclass = (void *)object->oclass;
-	struct gf100_gr *gr = (void *)object;
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total);
 	u32 data[TPC_MAX / 8] = {};
@@ -254,10 +189,6 @@ gk20a_gr_init(struct nvkm_object *object)
 	int gpc, tpc;
 	int ret, i;
 
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
-
 	/* Clear SCC RAM */
 	nvkm_wr32(device, 0x40802c, 0x1);
 
@@ -275,8 +206,8 @@ gk20a_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(gr->unk4188b4) >> 8);
 	nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(gr->unk4188b8) >> 8);
 
-	if (oclass->init_gpc_mmu)
-		oclass->init_gpc_mmu(gr);
+	if (gr->func->init_gpc_mmu)
+		gr->func->init_gpc_mmu(gr);
 
 	/* Set the PE as stream master */
 	nvkm_mask(device, 0x503018, 0x1, 0x1);
@@ -322,8 +253,8 @@ gk20a_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, 0x404000, 0xc0000000);
 	nvkm_wr32(device, 0x404600, 0xc0000000);
 
-	if (oclass->set_hww_esr_report_mask)
-		oclass->set_hww_esr_report_mask(gr);
+	if (gr->func->set_hww_esr_report_mask)
+		gr->func->set_hww_esr_report_mask(gr);
 
 	/* Enable TPC exceptions per GPC */
 	nvkm_wr32(device, 0x419d0c, 0x2);
@@ -342,8 +273,72 @@ gk20a_gr_init(struct nvkm_object *object)
 	return gf100_gr_init_ctxctl(gr);
 }
 
+void
+gk20a_gr_dtor(struct gf100_gr *gr)
+{
+	gk20a_gr_init_dtor(gr->fuc_method);
+	gk20a_gr_init_dtor(gr->fuc_bundle);
+	gk20a_gr_init_dtor(gr->fuc_sw_ctx);
+	gk20a_gr_init_dtor(gr->fuc_sw_nonctx);
+}
+
+int
+gk20a_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device,
+	      int index, struct nvkm_gr **pgr)
+{
+	struct gf100_gr_fuc fuc;
+	struct gf100_gr *gr;
+	int ret;
+
+	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+		return -ENOMEM;
+	*pgr = &gr->base;
+
+	ret = gf100_gr_ctor(func, device, index, gr);
+	if (ret)
+		return ret;
+
+	ret = gf100_gr_ctor_fw(gr, "sw_nonctx", &fuc);
+	if (ret)
+		return ret;
+	gr->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc);
+	gf100_gr_dtor_fw(&fuc);
+	if (IS_ERR(gr->fuc_sw_nonctx))
+		return PTR_ERR(gr->fuc_sw_nonctx);
+
+	ret = gf100_gr_ctor_fw(gr, "sw_ctx", &fuc);
+	if (ret)
+		return ret;
+	gr->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc);
+	gf100_gr_dtor_fw(&fuc);
+	if (IS_ERR(gr->fuc_sw_ctx))
+		return PTR_ERR(gr->fuc_sw_ctx);
+
+	ret = gf100_gr_ctor_fw(gr, "sw_bundle_init", &fuc);
+	if (ret)
+		return ret;
+	gr->fuc_bundle = gk20a_gr_av_to_init(&fuc);
+	gf100_gr_dtor_fw(&fuc);
+	if (IS_ERR(gr->fuc_bundle))
+		return PTR_ERR(gr->fuc_bundle);
+
+	ret = gf100_gr_ctor_fw(gr, "sw_method_init", &fuc);
+	if (ret)
+		return ret;
+	gr->fuc_method = gk20a_gr_av_to_method(&fuc);
+	gf100_gr_dtor_fw(&fuc);
+	if (IS_ERR(gr->fuc_method))
+		return PTR_ERR(gr->fuc_method);
+
+	return 0;
+}
+
 static const struct gf100_gr_func
 gk20a_gr = {
+	.dtor = gk20a_gr_dtor,
+	.init = gk20a_gr_init,
+	.set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask,
+	.ppc_nr = 1,
 	.grctx = &gk20a_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -354,18 +349,8 @@ gk20a_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gk20a_gr_oclass = &(struct gk20a_gr_oclass) {
-	.gf100 = {
-		.base.handle = NV_ENGINE(GR, 0xea),
-		.base.ofuncs = &(struct nvkm_ofuncs) {
-			.ctor = gk20a_gr_ctor,
-			.dtor = gk20a_gr_dtor,
-			.init = gk20a_gr_init,
-			.fini = _nvkm_gr_fini,
-		},
-		.func = &gk20a_gr,
-		.ppc_nr = 1,
-	},
-	.set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask,
-}.gf100.base;
+int
+gk20a_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gk20a_gr_new_(&gk20a_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
index b3036cb610804..56e960212e5df 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
@@ -308,20 +308,14 @@ gm107_gr_init_bios(struct gf100_gr *gr)
 }
 
 int
-gm107_gr_init(struct nvkm_object *object)
+gm107_gr_init(struct gf100_gr *gr)
 {
-	struct gf100_gr_oclass *oclass = (void *)object->oclass;
-	struct gf100_gr *gr = (void *)object;
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total);
 	u32 data[TPC_MAX / 8] = {};
 	u8  tpcnr[GPC_MAX];
 	int gpc, tpc, ppc, rop;
-	int ret, i;
-
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
+	int i;
 
 	nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000);
 	nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000);
@@ -329,7 +323,7 @@ gm107_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8);
 	nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8);
 
-	gf100_gr_mmio(gr, oclass->mmio);
+	gf100_gr_mmio(gr, gr->func->mmio);
 
 	gm107_gr_init_bios(gr);
 
@@ -443,6 +437,11 @@ gm107_gr_gpccs_ucode = {
 
 static const struct gf100_gr_func
 gm107_gr = {
+	.init = gm107_gr_init,
+	.mmio = gm107_gr_pack_mmio,
+	.fecs.ucode = &gm107_gr_fecs_ucode,
+	.gpccs.ucode = &gm107_gr_gpccs_ucode,
+	.ppc_nr = 2,
 	.grctx = &gm107_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -453,18 +452,8 @@ gm107_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gm107_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0x07),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gm107_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gm107_gr,
-	.mmio = gm107_gr_pack_mmio,
-	.fecs.ucode = &gm107_gr_fecs_ucode,
-	.gpccs.ucode = &gm107_gr_gpccs_ucode,
-	.ppc_nr = 2,
-}.base;
+int
+gm107_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gm107_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c
index ff41232a8a536..90381dde451aa 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c
@@ -236,21 +236,14 @@ gm204_gr_init_ctxctl(struct gf100_gr *gr)
 }
 
 int
-gm204_gr_init(struct nvkm_object *object)
+gm204_gr_init(struct gf100_gr *gr)
 {
-	struct gf100_gr_oclass *oclass = (void *)object->oclass;
-	struct gf100_gr *gr = (void *)object;
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total);
-	u32 data[TPC_MAX / 8] = {};
+	u32 data[TPC_MAX / 8] = {}, tmp;
 	u8  tpcnr[GPC_MAX];
 	int gpc, tpc, ppc, rop;
-	int ret, i;
-	u32 tmp;
-
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
+	int i;
 
 	tmp = nvkm_rd32(device, 0x100c80); /*XXX: mask? */
 	nvkm_wr32(device, 0x418880, 0x00001000 | (tmp & 0x00000fff));
@@ -265,7 +258,7 @@ gm204_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(gr->unk4188b8) >> 8);
 	nvkm_mask(device, 0x100cc4, 0x00040000, 0x00040000);
 
-	gf100_gr_mmio(gr, oclass->mmio);
+	gf100_gr_mmio(gr, gr->func->mmio);
 
 	gm107_gr_init_bios(gr);
 
@@ -360,6 +353,9 @@ gm204_gr_init(struct nvkm_object *object)
 
 static const struct gf100_gr_func
 gm204_gr = {
+	.init = gm204_gr_init,
+	.mmio = gm204_gr_pack_mmio,
+	.ppc_nr = 2,
 	.grctx = &gm204_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -370,16 +366,8 @@ gm204_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gm204_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0x24),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gm204_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gm204_gr,
-	.mmio = gm204_gr_pack_mmio,
-	.ppc_nr = 2,
-}.base;
+int
+gm204_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gm204_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c
index 4350b08f8dd22..341dc560acbbf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c
@@ -28,6 +28,9 @@
 
 static const struct gf100_gr_func
 gm206_gr = {
+	.init = gm204_gr_init,
+	.mmio = gm204_gr_pack_mmio,
+	.ppc_nr = 2,
 	.grctx = &gm206_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -38,16 +41,8 @@ gm206_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gm206_gr_oclass = &(struct gf100_gr_oclass) {
-	.base.handle = NV_ENGINE(GR, 0x26),
-	.base.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = gf100_gr_ctor,
-		.dtor = gf100_gr_dtor,
-		.init = gm204_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-	.func = &gm206_gr,
-	.mmio = gm204_gr_pack_mmio,
-	.ppc_nr = 2,
-}.base;
+int
+gm206_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gf100_gr_new_(&gm206_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c
index 7a663654543bd..65b6e3d1e90dc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c
@@ -19,7 +19,7 @@
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-#include "gk20a.h"
+#include "gf100.h"
 #include "ctxgf100.h"
 
 #include <subdev/timer.h>
@@ -61,6 +61,11 @@ gm20b_gr_set_hww_esr_report_mask(struct gf100_gr *gr)
 
 static const struct gf100_gr_func
 gm20b_gr = {
+	.dtor = gk20a_gr_dtor,
+	.init = gk20a_gr_init,
+	.init_gpc_mmu = gm20b_gr_init_gpc_mmu,
+	.set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask,
+	.ppc_nr = 1,
 	.grctx = &gm20b_grctx,
 	.sclass = {
 		{ -1, -1, FERMI_TWOD_A },
@@ -71,19 +76,8 @@ gm20b_gr = {
 	}
 };
 
-struct nvkm_oclass *
-gm20b_gr_oclass = &(struct gk20a_gr_oclass) {
-	.gf100 = {
-		.base.handle = NV_ENGINE(GR, 0x2b),
-		.base.ofuncs = &(struct nvkm_ofuncs) {
-			.ctor = gk20a_gr_ctor,
-			.dtor = gf100_gr_dtor,
-			.init = gk20a_gr_init,
-			.fini = _nvkm_gr_fini,
-		},
-		.func = &gm20b_gr,
-		.ppc_nr = 1,
-	},
-	.init_gpc_mmu = gm20b_gr_init_gpc_mmu,
-	.set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask,
-}.gf100.base;
+int
+gm20b_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return gk20a_gr_new_(&gm20b_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c
new file mode 100644
index 0000000000000..2e68919f00b20
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+static const struct nvkm_gr_func
+gt200_gr = {
+	.init = nv50_gr_init,
+	.intr = nv50_gr_intr,
+	.chan_new = nv50_gr_chan_new,
+	.tlb_flush = g84_gr_tlb_flush,
+	.units = nv50_gr_units,
+	.sclass = {
+		{ -1, -1, 0x0030, &nv50_gr_object },
+		{ -1, -1, 0x502d, &nv50_gr_object },
+		{ -1, -1, 0x5039, &nv50_gr_object },
+		{ -1, -1, 0x50c0, &nv50_gr_object },
+		{ -1, -1, 0x8397, &nv50_gr_object },
+		{}
+	}
+};
+
+int
+gt200_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv50_gr_new_(&gt200_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c
new file mode 100644
index 0000000000000..2bf7aac360cc5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+static const struct nvkm_gr_func
+gt215_gr = {
+	.init = nv50_gr_init,
+	.intr = nv50_gr_intr,
+	.chan_new = nv50_gr_chan_new,
+	.tlb_flush = g84_gr_tlb_flush,
+	.units = nv50_gr_units,
+	.sclass = {
+		{ -1, -1, 0x0030, &nv50_gr_object },
+		{ -1, -1, 0x502d, &nv50_gr_object },
+		{ -1, -1, 0x5039, &nv50_gr_object },
+		{ -1, -1, 0x50c0, &nv50_gr_object },
+		{ -1, -1, 0x8597, &nv50_gr_object },
+		{ -1, -1, 0x85c0, &nv50_gr_object },
+		{}
+	}
+};
+
+int
+gt215_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv50_gr_new_(&gt215_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c
similarity index 50%
rename from drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h
rename to drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c
index 411099d222d43..95d5219faf936 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, NVIDIA CORPORATION. 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"),
@@ -14,22 +14,33 @@
  * 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 AUTHORS OR COPYRIGHT HOLDERS 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 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 "nv50.h"
 
-#ifndef __GK20A_GR_H__
-#define __GK20A_GR_H__
-
-#include "gf100.h"
-
-struct gk20a_gr_oclass {
-	struct gf100_gr_oclass gf100;
-
-	void (*init_gpc_mmu)(struct gf100_gr *);
-	void (*set_hww_esr_report_mask)(struct gf100_gr *);
+static const struct nvkm_gr_func
+mcp79_gr = {
+	.init = nv50_gr_init,
+	.intr = nv50_gr_intr,
+	.chan_new = nv50_gr_chan_new,
+	.units = nv50_gr_units,
+	.sclass = {
+		{ -1, -1, 0x0030, &nv50_gr_object },
+		{ -1, -1, 0x502d, &nv50_gr_object },
+		{ -1, -1, 0x5039, &nv50_gr_object },
+		{ -1, -1, 0x50c0, &nv50_gr_object },
+		{ -1, -1, 0x8397, &nv50_gr_object },
+		{}
+	}
 };
 
-#endif
+int
+mcp79_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv50_gr_new_(&mcp79_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c
new file mode 100644
index 0000000000000..027b58e5976b3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+static const struct nvkm_gr_func
+mcp89_gr = {
+	.init = nv50_gr_init,
+	.intr = nv50_gr_intr,
+	.chan_new = nv50_gr_chan_new,
+	.tlb_flush = g84_gr_tlb_flush,
+	.units = nv50_gr_units,
+	.sclass = {
+		{ -1, -1, 0x0030, &nv50_gr_object },
+		{ -1, -1, 0x502d, &nv50_gr_object },
+		{ -1, -1, 0x5039, &nv50_gr_object },
+		{ -1, -1, 0x50c0, &nv50_gr_object },
+		{ -1, -1, 0x85c0, &nv50_gr_object },
+		{ -1, -1, 0x8697, &nv50_gr_object },
+		{}
+	}
+};
+
+int
+mcp89_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv50_gr_new_(&mcp89_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
index a5a4bdd9863e7..7b4317ab8f02f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
@@ -1269,11 +1269,11 @@ nv04_gr_nsource[] = {
 };
 
 static void
-nv04_gr_intr(struct nvkm_subdev *subdev)
+nv04_gr_intr(struct nvkm_gr *base)
 {
-	struct nv04_gr *gr = (void *)subdev;
-	struct nv04_gr_chan *chan = NULL;
-	struct nvkm_device *device = gr->base.engine.subdev.device;
+	struct nv04_gr *gr = nv04_gr(base);
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
 	u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR);
 	u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE);
 	u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS);
@@ -1286,6 +1286,7 @@ nv04_gr_intr(struct nvkm_subdev *subdev)
 	u32 inst = (nvkm_rd32(device, 0x40016c) & 0xffff) << 4;
 	u32 show = stat;
 	char msg[128], src[128], sta[128];
+	struct nv04_gr_chan *chan;
 	unsigned long flags;
 
 	spin_lock_irqsave(&gr->lock, flags);
@@ -1323,8 +1324,47 @@ nv04_gr_intr(struct nvkm_subdev *subdev)
 	spin_unlock_irqrestore(&gr->lock, flags);
 }
 
+static int
+nv04_gr_init(struct nvkm_gr *base)
+{
+	struct nv04_gr *gr = nv04_gr(base);
+	struct nvkm_device *device = gr->base.engine.subdev.device;
+
+	/* Enable PGRAPH interrupts */
+	nvkm_wr32(device, NV03_PGRAPH_INTR, 0xFFFFFFFF);
+	nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+	nvkm_wr32(device, NV04_PGRAPH_VALID1, 0);
+	nvkm_wr32(device, NV04_PGRAPH_VALID2, 0);
+	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x000001FF);
+	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
+	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x1231c000);
+	/*1231C000 blob, 001 haiku*/
+	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+	nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x72111100);
+	/*0x72111100 blob , 01 haiku*/
+	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
+	nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
+	/*haiku same*/
+
+	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
+	nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
+	/*haiku and blob 10d4*/
+
+	nvkm_wr32(device, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
+	nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
+	nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+
+	/* These don't belong here, they're part of a per-channel context */
+	nvkm_wr32(device, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
+	nvkm_wr32(device, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
+	return 0;
+}
+
 static const struct nvkm_gr_func
 nv04_gr = {
+	.init = nv04_gr_init,
+	.intr = nv04_gr_intr,
 	.chan_new = nv04_gr_chan_new,
 	.sclass = {
 		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
@@ -1372,76 +1412,16 @@ nv04_gr = {
 	}
 };
 
-static int
-nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
+int
+nv04_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
 {
 	struct nv04_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
 
-	gr->base.func = &nv04_gr;
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv04_gr_intr;
+	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+		return -ENOMEM;
 	spin_lock_init(&gr->lock);
-	return 0;
-}
+	*pgr = &gr->base;
 
-static int
-nv04_gr_init(struct nvkm_object *object)
-{
-	struct nvkm_engine *engine = nv_engine(object);
-	struct nv04_gr *gr = (void *)engine;
-	struct nvkm_device *device = gr->base.engine.subdev.device;
-	int ret;
-
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
-
-	/* Enable PGRAPH interrupts */
-	nvkm_wr32(device, NV03_PGRAPH_INTR, 0xFFFFFFFF);
-	nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-	nvkm_wr32(device, NV04_PGRAPH_VALID1, 0);
-	nvkm_wr32(device, NV04_PGRAPH_VALID2, 0);
-	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x000001FF);
-	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
-	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x1231c000);
-	/*1231C000 blob, 001 haiku*/
-	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
-	nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x72111100);
-	/*0x72111100 blob , 01 haiku*/
-	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
-	nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
-	/*haiku same*/
-
-	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
-	nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
-	/*haiku and blob 10d4*/
-
-	nvkm_wr32(device, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
-	nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
-	nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
-
-	/* These don't belong here, they're part of a per-channel context */
-	nvkm_wr32(device, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
-	nvkm_wr32(device, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
-	return 0;
+	return nvkm_gr_ctor(&nv04_gr, device, index, 0x00001000,
+			    true, &gr->base);
 }
-
-struct nvkm_oclass
-nv04_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x04),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv04_gr_ctor,
-		.dtor = _nvkm_gr_dtor,
-		.init = nv04_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
index d5e44a7332ebb..9436ada62cbab 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
@@ -21,7 +21,7 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
-#include "priv.h"
+#include "nv10.h"
 #include "regs.h"
 
 #include <core/client.h>
@@ -890,8 +890,7 @@ nv10_gr_load_context(struct nv10_gr_chan *chan, int chid)
 	for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++)
 		nvkm_wr32(device, nv10_gr_ctx_regs[i], chan->nv10[i]);
 
-	if (nv_device(gr)->card_type >= NV_11 &&
-	    nv_device(gr)->chipset >= 0x17) {
+	if (device->card_type >= NV_11 && device->chipset >= 0x17) {
 		for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++)
 			nvkm_wr32(device, nv17_gr_ctx_regs[i], chan->nv17[i]);
 	}
@@ -917,8 +916,7 @@ nv10_gr_unload_context(struct nv10_gr_chan *chan)
 	for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++)
 		chan->nv10[i] = nvkm_rd32(device, nv10_gr_ctx_regs[i]);
 
-	if (nv_device(gr)->card_type >= NV_11 &&
-	    nv_device(gr)->chipset >= 0x17) {
+	if (device->card_type >= NV_11 && device->chipset >= 0x17) {
 		for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++)
 			chan->nv17[i] = nvkm_rd32(device, nv17_gr_ctx_regs[i]);
 	}
@@ -1000,7 +998,7 @@ nv10_gr_chan = {
 		chan->nv17[offset] = val; \
 	} while (0)
 
-static int
+int
 nv10_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
 		 const struct nvkm_oclass *oclass, struct nvkm_object **pobject)
 {
@@ -1047,13 +1045,12 @@ nv10_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static void
-nv10_gr_tile_prog(struct nvkm_engine *engine, int i)
+void
+nv10_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile)
 {
-	struct nv10_gr *gr = (void *)engine;
+	struct nv10_gr *gr = nv10_gr(base);
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	struct nvkm_fifo *fifo = device->fifo;
-	struct nvkm_fb_tile *tile = &device->fb->tile.region[i];
 	unsigned long flags;
 
 	nvkm_fifo_pause(fifo, &flags);
@@ -1080,12 +1077,12 @@ const struct nvkm_bitfield nv10_gr_nstatus[] = {
 	{}
 };
 
-static void
-nv10_gr_intr(struct nvkm_subdev *subdev)
+void
+nv10_gr_intr(struct nvkm_gr *base)
 {
-	struct nv10_gr *gr = (void *)subdev;
-	struct nv10_gr_chan *chan = NULL;
-	struct nvkm_device *device = gr->base.engine.subdev.device;
+	struct nv10_gr *gr = nv10_gr(base);
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
 	u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR);
 	u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE);
 	u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS);
@@ -1097,6 +1094,7 @@ nv10_gr_intr(struct nvkm_subdev *subdev)
 	u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff;
 	u32 show = stat;
 	char msg[128], src[128], sta[128];
+	struct nv10_gr_chan *chan;
 	unsigned long flags;
 
 	spin_lock_irqsave(&gr->lock, flags);
@@ -1134,134 +1132,11 @@ nv10_gr_intr(struct nvkm_subdev *subdev)
 	spin_unlock_irqrestore(&gr->lock, flags);
 }
 
-static const struct nvkm_gr_func
-nv10_gr = {
-	.chan_new = nv10_gr_chan_new,
-	.sclass = {
-		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
-		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
-		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
-		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
-		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
-		{ -1, -1, 0x0044, &nv04_gr_object }, /* pattern */
-		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
-		{ -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */
-		{ -1, -1, 0x005f, &nv04_gr_object }, /* blit */
-		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
-		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
-		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
-		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
-		{ -1, -1, 0x009f, &nv04_gr_object }, /* blit */
-		{ -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */
-		{ -1, -1, 0x0094, &nv04_gr_object }, /* ttri */
-		{ -1, -1, 0x0095, &nv04_gr_object }, /* mtri */
-		{ -1, -1, 0x0056, &nv04_gr_object }, /* celcius */
-		{}
-	}
-};
-
-static const struct nvkm_gr_func
-nv15_gr = {
-	.chan_new = nv10_gr_chan_new,
-	.sclass = {
-		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
-		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
-		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
-		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
-		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
-		{ -1, -1, 0x0044, &nv04_gr_object }, /* pattern */
-		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
-		{ -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */
-		{ -1, -1, 0x005f, &nv04_gr_object }, /* blit */
-		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
-		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
-		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
-		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
-		{ -1, -1, 0x009f, &nv04_gr_object }, /* blit */
-		{ -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */
-		{ -1, -1, 0x0094, &nv04_gr_object }, /* ttri */
-		{ -1, -1, 0x0095, &nv04_gr_object }, /* mtri */
-		{ -1, -1, 0x0096, &nv04_gr_object }, /* celcius */
-		{}
-	}
-};
-
-
-static const struct nvkm_gr_func
-nv17_gr = {
-	.chan_new = nv10_gr_chan_new,
-	.sclass = {
-		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
-		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
-		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
-		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
-		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
-		{ -1, -1, 0x0044, &nv04_gr_object }, /* pattern */
-		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
-		{ -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */
-		{ -1, -1, 0x005f, &nv04_gr_object }, /* blit */
-		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
-		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
-		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
-		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
-		{ -1, -1, 0x009f, &nv04_gr_object }, /* blit */
-		{ -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */
-		{ -1, -1, 0x0094, &nv04_gr_object }, /* ttri */
-		{ -1, -1, 0x0095, &nv04_gr_object }, /* mtri */
-		{ -1, -1, 0x0099, &nv04_gr_object },
-		{}
-	}
-};
-
-static int
-nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
-{
-	struct nv10_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv10_gr_intr;
-
-	if (nv_device(gr)->chipset <= 0x10)
-		gr->base.func = &nv10_gr;
-	else
-	if (nv_device(gr)->chipset <  0x17 ||
-	    nv_device(gr)->card_type < NV_11)
-		gr->base.func = &nv15_gr;
-	else
-		gr->base.func = &nv17_gr;
-
-	nv_engine(gr)->tile_prog = nv10_gr_tile_prog;
-	spin_lock_init(&gr->lock);
-	return 0;
-}
-
-static void
-nv10_gr_dtor(struct nvkm_object *object)
+int
+nv10_gr_init(struct nvkm_gr *base)
 {
-	struct nv10_gr *gr = (void *)object;
-	nvkm_gr_destroy(&gr->base);
-}
-
-static int
-nv10_gr_init(struct nvkm_object *object)
-{
-	struct nvkm_engine *engine = nv_engine(object);
-	struct nv10_gr *gr = (void *)engine;
+	struct nv10_gr *gr = nv10_gr(base);
 	struct nvkm_device *device = gr->base.engine.subdev.device;
-	struct nvkm_fb *fb = device->fb;
-	int ret, i;
-
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
 
 	nvkm_wr32(device, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
 	nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -1273,8 +1148,7 @@ nv10_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
 
-	if (nv_device(gr)->card_type >= NV_11 &&
-	    nv_device(gr)->chipset >= 0x17) {
+	if (device->card_type >= NV_11 && device->chipset >= 0x17) {
 		nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x1f000000);
 		nvkm_wr32(device, 0x400a10, 0x03ff3fb6);
 		nvkm_wr32(device, 0x400838, 0x002f8684);
@@ -1284,10 +1158,6 @@ nv10_gr_init(struct nvkm_object *object)
 		nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000);
 	}
 
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < fb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
 	nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
 	nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
 	nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
@@ -1301,20 +1171,51 @@ nv10_gr_init(struct nvkm_object *object)
 	return 0;
 }
 
-static int
-nv10_gr_fini(struct nvkm_object *object, bool suspend)
+int
+nv10_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device,
+	     int index, struct nvkm_gr **pgr)
 {
-	struct nv10_gr *gr = (void *)object;
-	return nvkm_gr_fini(&gr->base, suspend);
+	struct nv10_gr *gr;
+
+	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+		return -ENOMEM;
+	spin_lock_init(&gr->lock);
+	*pgr = &gr->base;
+
+	return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base);
 }
 
-struct nvkm_oclass
-nv10_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x10),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv10_gr_ctor,
-		.dtor = nv10_gr_dtor,
-		.init = nv10_gr_init,
-		.fini = nv10_gr_fini,
-	},
+static const struct nvkm_gr_func
+nv10_gr = {
+	.init = nv10_gr_init,
+	.intr = nv10_gr_intr,
+	.tile = nv10_gr_tile,
+	.chan_new = nv10_gr_chan_new,
+	.sclass = {
+		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
+		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
+		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
+		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
+		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
+		{ -1, -1, 0x0044, &nv04_gr_object }, /* pattern */
+		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
+		{ -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */
+		{ -1, -1, 0x005f, &nv04_gr_object }, /* blit */
+		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
+		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
+		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
+		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
+		{ -1, -1, 0x009f, &nv04_gr_object }, /* blit */
+		{ -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */
+		{ -1, -1, 0x0094, &nv04_gr_object }, /* ttri */
+		{ -1, -1, 0x0095, &nv04_gr_object }, /* mtri */
+		{ -1, -1, 0x0056, &nv04_gr_object }, /* celcius */
+		{}
+	}
 };
+
+int
+nv10_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv10_gr_new_(&nv10_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h
new file mode 100644
index 0000000000000..d7c3d86cc99df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h
@@ -0,0 +1,13 @@
+#ifndef __NV10_GR_H__
+#define __NV10_GR_H__
+#include "priv.h"
+
+int nv10_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index,
+		 struct nvkm_gr **);
+int nv10_gr_init(struct nvkm_gr *);
+void nv10_gr_intr(struct nvkm_gr *);
+void nv10_gr_tile(struct nvkm_gr *, int, struct nvkm_fb_tile *);
+
+int nv10_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *,
+		     const struct nvkm_oclass *, struct nvkm_object **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c
new file mode 100644
index 0000000000000..3e2c6856b4c4e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr>
+ * All Rights Reserved.
+ *
+ * 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
+ * paragr) 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
+ * PRECISION INSIGHT 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.
+ */
+#include "nv10.h"
+
+static const struct nvkm_gr_func
+nv15_gr = {
+	.init = nv10_gr_init,
+	.intr = nv10_gr_intr,
+	.tile = nv10_gr_tile,
+	.chan_new = nv10_gr_chan_new,
+	.sclass = {
+		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
+		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
+		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
+		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
+		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
+		{ -1, -1, 0x0044, &nv04_gr_object }, /* pattern */
+		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
+		{ -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */
+		{ -1, -1, 0x005f, &nv04_gr_object }, /* blit */
+		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
+		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
+		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
+		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
+		{ -1, -1, 0x009f, &nv04_gr_object }, /* blit */
+		{ -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */
+		{ -1, -1, 0x0094, &nv04_gr_object }, /* ttri */
+		{ -1, -1, 0x0095, &nv04_gr_object }, /* mtri */
+		{ -1, -1, 0x0096, &nv04_gr_object }, /* celcius */
+		{}
+	}
+};
+
+int
+nv15_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv10_gr_new_(&nv15_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c
new file mode 100644
index 0000000000000..12437d085a738
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr>
+ * All Rights Reserved.
+ *
+ * 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
+ * paragr) 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
+ * PRECISION INSIGHT 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.
+ */
+#include "nv10.h"
+
+static const struct nvkm_gr_func
+nv17_gr = {
+	.init = nv10_gr_init,
+	.intr = nv10_gr_intr,
+	.tile = nv10_gr_tile,
+	.chan_new = nv10_gr_chan_new,
+	.sclass = {
+		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
+		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
+		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
+		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
+		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
+		{ -1, -1, 0x0044, &nv04_gr_object }, /* pattern */
+		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
+		{ -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */
+		{ -1, -1, 0x005f, &nv04_gr_object }, /* blit */
+		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
+		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
+		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
+		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
+		{ -1, -1, 0x009f, &nv04_gr_object }, /* blit */
+		{ -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */
+		{ -1, -1, 0x0094, &nv04_gr_object }, /* ttri */
+		{ -1, -1, 0x0095, &nv04_gr_object }, /* mtri */
+		{ -1, -1, 0x0099, &nv04_gr_object },
+		{}
+	}
+};
+
+int
+nv17_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv10_gr_new_(&nv17_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
index ce4f9925ea9b8..32ea28a71a412 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
@@ -145,12 +145,11 @@ nv20_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
  ******************************************************************************/
 
 void
-nv20_gr_tile_prog(struct nvkm_engine *engine, int i)
+nv20_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile)
 {
-	struct nv20_gr *gr = (void *)engine;
+	struct nv20_gr *gr = nv20_gr(base);
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	struct nvkm_fifo *fifo = device->fifo;
-	struct nvkm_fb_tile *tile = &device->fb->tile.region[i];
 	unsigned long flags;
 
 	nvkm_fifo_pause(fifo, &flags);
@@ -167,7 +166,7 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i)
 	nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
 	nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->addr);
 
-	if (nv_device(engine)->chipset != 0x34) {
+	if (device->chipset != 0x34) {
 		nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
 		nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
 		nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->zcomp);
@@ -177,10 +176,11 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i)
 }
 
 void
-nv20_gr_intr(struct nvkm_subdev *subdev)
+nv20_gr_intr(struct nvkm_gr *base)
 {
-	struct nv20_gr *gr = (void *)subdev;
-	struct nvkm_device *device = gr->base.engine.subdev.device;
+	struct nv20_gr *gr = nv20_gr(base);
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
 	struct nvkm_fifo_chan *chan;
 	u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR);
 	u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE);
@@ -215,82 +215,27 @@ nv20_gr_intr(struct nvkm_subdev *subdev)
 	nvkm_fifo_chan_put(device->fifo, flags, &chan);
 }
 
-static const struct nvkm_gr_func
-nv20_gr = {
-	.chan_new = nv20_gr_chan_new,
-	.sclass = {
-		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
-		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
-		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
-		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
-		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
-		{ -1, -1, 0x0044, &nv04_gr_object }, /* patt */
-		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
-		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
-		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
-		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
-		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
-		{ -1, -1, 0x0096, &nv04_gr_object }, /* celcius */
-		{ -1, -1, 0x0097, &nv04_gr_object }, /* kelvin */
-		{ -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */
-		{ -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */
-		{}
-	}
-};
-
-static int
-nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
-{
-	struct nvkm_device *device = (void *)parent;
-	struct nv20_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	gr->base.func = &nv20_gr;
-
-	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true,
-			      &gr->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv20_gr_intr;
-	nv_engine(gr)->tile_prog = nv20_gr_tile_prog;
-	return 0;
-}
-
-void
-nv20_gr_dtor(struct nvkm_object *object)
+int
+nv20_gr_oneinit(struct nvkm_gr *base)
 {
-	struct nv20_gr *gr = (void *)object;
-	nvkm_memory_del(&gr->ctxtab);
-	nvkm_gr_destroy(&gr->base);
+	struct nv20_gr *gr = nv20_gr(base);
+	return nvkm_memory_new(gr->base.engine.subdev.device,
+			       NVKM_MEM_TARGET_INST, 32 * 4, 16,
+			       true, &gr->ctxtab);
 }
 
 int
-nv20_gr_init(struct nvkm_object *object)
+nv20_gr_init(struct nvkm_gr *base)
 {
-	struct nvkm_engine *engine = nv_engine(object);
-	struct nv20_gr *gr = (void *)engine;
+	struct nv20_gr *gr = nv20_gr(base);
 	struct nvkm_device *device = gr->base.engine.subdev.device;
-	struct nvkm_fb *fb = device->fb;
 	u32 tmp, vramsz;
-	int ret, i;
-
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
+	int i;
 
 	nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE,
 			  nvkm_memory_addr(gr->ctxtab) >> 4);
 
-	if (nv_device(gr)->chipset == 0x20) {
+	if (device->chipset == 0x20) {
 		nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x003d0000);
 		for (i = 0; i < 15; i++)
 			nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, 0x00000000);
@@ -318,7 +263,7 @@ nv20_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000);
 	nvkm_wr32(device, 0x40009C           , 0x00000040);
 
-	if (nv_device(gr)->chipset >= 0x25) {
+	if (device->chipset >= 0x25) {
 		nvkm_wr32(device, 0x400890, 0x00a8cfff);
 		nvkm_wr32(device, 0x400610, 0x304B1FB6);
 		nvkm_wr32(device, 0x400B80, 0x1cbd3883);
@@ -338,10 +283,6 @@ nv20_gr_init(struct nvkm_object *object)
 		nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000030);
 	}
 
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < fb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
 	nvkm_wr32(device, 0x4009a0, nvkm_rd32(device, 0x100324));
 	nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
 	nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, nvkm_rd32(device, 0x100324));
@@ -355,7 +296,7 @@ nv20_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, NV10_PGRAPH_SURFACE, tmp);
 
 	/* begin RAM config */
-	vramsz = nv_device_resource_len(nv_device(gr), 1) - 1;
+	vramsz = nv_device_resource_len(device, 1) - 1;
 	nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200));
 	nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204));
 	nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
@@ -378,13 +319,57 @@ nv20_gr_init(struct nvkm_object *object)
 	return 0;
 }
 
-struct nvkm_oclass
-nv20_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x20),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv20_gr_ctor,
-		.dtor = nv20_gr_dtor,
-		.init = nv20_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
+void *
+nv20_gr_dtor(struct nvkm_gr *base)
+{
+	struct nv20_gr *gr = nv20_gr(base);
+	nvkm_memory_del(&gr->ctxtab);
+	return gr;
+}
+
+int
+nv20_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device,
+	     int index, struct nvkm_gr **pgr)
+{
+	struct nv20_gr *gr;
+
+	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+		return -ENOMEM;
+	*pgr = &gr->base;
+
+	return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base);
+}
+
+static const struct nvkm_gr_func
+nv20_gr = {
+	.dtor = nv20_gr_dtor,
+	.oneinit = nv20_gr_oneinit,
+	.init = nv20_gr_init,
+	.intr = nv20_gr_intr,
+	.tile = nv20_gr_tile,
+	.chan_new = nv20_gr_chan_new,
+	.sclass = {
+		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
+		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
+		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
+		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
+		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
+		{ -1, -1, 0x0044, &nv04_gr_object }, /* patt */
+		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
+		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
+		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
+		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
+		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
+		{ -1, -1, 0x0096, &nv04_gr_object }, /* celcius */
+		{ -1, -1, 0x0097, &nv04_gr_object }, /* kelvin */
+		{ -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */
+		{ -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */
+		{}
+	}
 };
+
+int
+nv20_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv20_gr_new_(&nv20_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h
index 1ae4f2acc612a..cdf4501e3798d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h
@@ -8,6 +8,16 @@ struct nv20_gr {
 	struct nvkm_memory *ctxtab;
 };
 
+int nv20_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *,
+		 int, struct nvkm_gr **);
+void *nv20_gr_dtor(struct nvkm_gr *);
+int nv20_gr_oneinit(struct nvkm_gr *);
+int nv20_gr_init(struct nvkm_gr *);
+void nv20_gr_intr(struct nvkm_gr *);
+void nv20_gr_tile(struct nvkm_gr *, int, struct nvkm_fb_tile *);
+
+int nv30_gr_init(struct nvkm_gr *);
+
 #define nv20_gr_chan(p) container_of((p), struct nv20_gr_chan, object)
 
 struct nv20_gr_chan {
@@ -18,14 +28,6 @@ struct nv20_gr_chan {
 };
 
 void *nv20_gr_chan_dtor(struct nvkm_object *);
-int  nv20_gr_chan_init(struct nvkm_object *);
-int  nv20_gr_chan_fini(struct nvkm_object *, bool);
-
-void nv20_gr_tile_prog(struct nvkm_engine *, int);
-void nv20_gr_intr(struct nvkm_subdev *);
-
-void nv20_gr_dtor(struct nvkm_object *);
-int  nv20_gr_init(struct nvkm_object *);
-
-int  nv30_gr_init(struct nvkm_object *);
+int nv20_gr_chan_init(struct nvkm_object *);
+int nv20_gr_chan_fini(struct nvkm_object *, bool);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
index cc56ca9505f4a..6c4a00819b4bd 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
@@ -101,6 +101,11 @@ nv25_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
 
 static const struct nvkm_gr_func
 nv25_gr = {
+	.dtor = nv20_gr_dtor,
+	.oneinit = nv20_gr_oneinit,
+	.init = nv20_gr_init,
+	.intr = nv20_gr_intr,
+	.tile = nv20_gr_tile,
 	.chan_new = nv25_gr_chan_new,
 	.sclass = {
 		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
@@ -122,40 +127,8 @@ nv25_gr = {
 	}
 };
 
-static int
-nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
+int
+nv25_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
 {
-	struct nvkm_device *device = (void *)parent;
-	struct nv20_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	gr->base.func = &nv25_gr;
-
-	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true,
-			      &gr->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv20_gr_intr;
-	nv_engine(gr)->tile_prog = nv20_gr_tile_prog;
-	return 0;
+	return nv20_gr_new_(&nv25_gr, device, index, pgr);
 }
-
-struct nvkm_oclass
-nv25_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x25),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv25_gr_ctor,
-		.dtor = nv20_gr_dtor,
-		.init = nv20_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
index 4e4cd93d686d3..3cad26dbc2b1a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
@@ -92,6 +92,11 @@ nv2a_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
 
 static const struct nvkm_gr_func
 nv2a_gr = {
+	.dtor = nv20_gr_dtor,
+	.oneinit = nv20_gr_oneinit,
+	.init = nv20_gr_init,
+	.intr = nv20_gr_intr,
+	.tile = nv20_gr_tile,
 	.chan_new = nv2a_gr_chan_new,
 	.sclass = {
 		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
@@ -113,40 +118,8 @@ nv2a_gr = {
 	}
 };
 
-static int
-nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
+int
+nv2a_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
 {
-	struct nvkm_device *device = (void *)parent;
-	struct nv20_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	gr->base.func = &nv2a_gr;
-
-	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true,
-			      &gr->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv20_gr_intr;
-	nv_engine(gr)->tile_prog = nv20_gr_tile_prog;
-	return 0;
+	return nv20_gr_new_(&nv2a_gr, device, index, pgr);
 }
-
-struct nvkm_oclass
-nv2a_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x2a),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv2a_gr_ctor,
-		.dtor = nv20_gr_dtor,
-		.init = nv20_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
index ea46b16c31e69..69de8c6259feb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
@@ -99,70 +99,11 @@ nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static const struct nvkm_gr_func
-nv30_gr = {
-	.chan_new = nv30_gr_chan_new,
-	.sclass = {
-		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
-		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
-		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
-		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
-		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
-		{ -1, -1, 0x0044, &nv04_gr_object }, /* patt */
-		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
-		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
-		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
-		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
-		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
-		{ -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */
-		{ -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */
-		{ -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */
-		{ -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
-		{ -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
-		{ -1, -1, 0x0397, &nv04_gr_object }, /* rankine */
-		{}
-	}
-};
-
-static int
-nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
-{
-	struct nvkm_device *device = (void *)parent;
-	struct nv20_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	gr->base.func = &nv30_gr;
-
-	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true,
-			      &gr->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv20_gr_intr;
-	nv_engine(gr)->tile_prog = nv20_gr_tile_prog;
-	return 0;
-}
-
 int
-nv30_gr_init(struct nvkm_object *object)
+nv30_gr_init(struct nvkm_gr *base)
 {
-	struct nvkm_engine *engine = nv_engine(object);
-	struct nv20_gr *gr = (void *)engine;
+	struct nv20_gr *gr = nv20_gr(base);
 	struct nvkm_device *device = gr->base.engine.subdev.device;
-	struct nvkm_fb *fb = device->fb;
-	int ret, i;
-
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
 
 	nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE,
 			  nvkm_memory_addr(gr->ctxtab) >> 4);
@@ -189,7 +130,7 @@ nv30_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, 0x400ba4, 0x00231f3f);
 	nvkm_wr32(device, 0x4008a4, 0x40000020);
 
-	if (nv_device(gr)->chipset == 0x34) {
+	if (device->chipset == 0x34) {
 		nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
 		nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00200201);
 		nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
@@ -202,10 +143,6 @@ nv30_gr_init(struct nvkm_object *object)
 
 	nvkm_wr32(device, 0x4000c0, 0x00000016);
 
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < fb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
 	nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
 	nvkm_wr32(device, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
 	nvkm_wr32(device, 0x0040075c             , 0x00000001);
@@ -214,22 +151,48 @@ nv30_gr_init(struct nvkm_object *object)
 	/* vramsz = pci_resource_len(gr->dev->pdev, 1) - 1; */
 	nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200));
 	nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204));
-	if (nv_device(gr)->chipset != 0x34) {
+	if (device->chipset != 0x34) {
 		nvkm_wr32(device, 0x400750, 0x00EA0000);
 		nvkm_wr32(device, 0x400754, nvkm_rd32(device, 0x100200));
 		nvkm_wr32(device, 0x400750, 0x00EA0004);
 		nvkm_wr32(device, 0x400754, nvkm_rd32(device, 0x100204));
 	}
+
 	return 0;
 }
 
-struct nvkm_oclass
-nv30_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x30),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv30_gr_ctor,
-		.dtor = nv20_gr_dtor,
-		.init = nv30_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
+static const struct nvkm_gr_func
+nv30_gr = {
+	.dtor = nv20_gr_dtor,
+	.oneinit = nv20_gr_oneinit,
+	.init = nv30_gr_init,
+	.intr = nv20_gr_intr,
+	.tile = nv20_gr_tile,
+	.chan_new = nv30_gr_chan_new,
+	.sclass = {
+		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
+		{ -1, -1, 0x0019, &nv04_gr_object }, /* clip */
+		{ -1, -1, 0x0030, &nv04_gr_object }, /* null */
+		{ -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */
+		{ -1, -1, 0x0043, &nv04_gr_object }, /* rop */
+		{ -1, -1, 0x0044, &nv04_gr_object }, /* patt */
+		{ -1, -1, 0x004a, &nv04_gr_object }, /* gdi */
+		{ -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */
+		{ -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */
+		{ -1, -1, 0x0089, &nv04_gr_object }, /* sifm */
+		{ -1, -1, 0x008a, &nv04_gr_object }, /* ifc */
+		{ -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */
+		{ -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */
+		{ -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */
+		{ -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */
+		{ -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */
+		{ -1, -1, 0x0397, &nv04_gr_object }, /* rankine */
+		{}
+	}
 };
+
+int
+nv30_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv20_gr_new_(&nv30_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
index 0667e9d14b42f..2207dac23981a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
@@ -100,6 +100,11 @@ nv34_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
 
 static const struct nvkm_gr_func
 nv34_gr = {
+	.dtor = nv20_gr_dtor,
+	.oneinit = nv20_gr_oneinit,
+	.init = nv30_gr_init,
+	.intr = nv20_gr_intr,
+	.tile = nv20_gr_tile,
 	.chan_new = nv34_gr_chan_new,
 	.sclass = {
 		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
@@ -123,40 +128,8 @@ nv34_gr = {
 	}
 };
 
-static int
-nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
+int
+nv34_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
 {
-	struct nvkm_device *device = (void *)parent;
-	struct nv20_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	gr->base.func = &nv34_gr;
-
-	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true,
-			      &gr->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv20_gr_intr;
-	nv_engine(gr)->tile_prog = nv20_gr_tile_prog;
-	return 0;
+	return nv20_gr_new_(&nv34_gr, device, index, pgr);
 }
-
-struct nvkm_oclass
-nv34_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x34),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv34_gr_ctor,
-		.dtor = nv20_gr_dtor,
-		.init = nv30_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
index 745d0e133d9a0..740df0f52c388 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
@@ -100,6 +100,11 @@ nv35_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
 
 static const struct nvkm_gr_func
 nv35_gr = {
+	.dtor = nv20_gr_dtor,
+	.oneinit = nv20_gr_oneinit,
+	.init = nv30_gr_init,
+	.intr = nv20_gr_intr,
+	.tile = nv20_gr_tile,
 	.chan_new = nv35_gr_chan_new,
 	.sclass = {
 		{ -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */
@@ -123,40 +128,8 @@ nv35_gr = {
 	}
 };
 
-static int
-nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
+int
+nv35_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
 {
-	struct nvkm_device *device = (void *)parent;
-	struct nv20_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	gr->base.func = &nv35_gr;
-
-	ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true,
-			      &gr->ctxtab);
-	if (ret)
-		return ret;
-
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv20_gr_intr;
-	nv_engine(gr)->tile_prog = nv20_gr_tile_prog;
-	return 0;
+	return nv20_gr_new_(&nv35_gr, device, index, pgr);
 }
-
-struct nvkm_oclass
-nv35_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x35),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv35_gr_ctor,
-		.dtor = nv20_gr_dtor,
-		.init = nv30_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
-};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
index be954500b4d8d..127a36f5859e6 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
@@ -30,7 +30,7 @@
 #include <subdev/timer.h>
 #include <engine/fifo.h>
 
-static u64
+u64
 nv40_gr_units(struct nvkm_gr *gr)
 {
 	return nvkm_rd32(gr->engine.subdev.device, 0x1540);
@@ -61,7 +61,7 @@ nv40_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent,
 	return ret;
 }
 
-static const struct nvkm_object_func
+const struct nvkm_object_func
 nv40_gr_object = {
 	.bind = nv40_gr_object_bind,
 };
@@ -144,7 +144,7 @@ nv40_gr_chan = {
 	.bind = nv40_gr_chan_bind,
 };
 
-static int
+int
 nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
 		 const struct nvkm_oclass *oclass, struct nvkm_object **pobject)
 {
@@ -169,31 +169,29 @@ nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
  ******************************************************************************/
 
 static void
-nv40_gr_tile_prog(struct nvkm_engine *engine, int i)
+nv40_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile)
 {
-	struct nv40_gr *gr = (void *)engine;
+	struct nv40_gr *gr = nv40_gr(base);
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	struct nvkm_fifo *fifo = device->fifo;
-	struct nvkm_fb_tile *tile = &device->fb->tile.region[i];
 	unsigned long flags;
 
 	nvkm_fifo_pause(fifo, &flags);
 	nv04_gr_idle(&gr->base);
 
-	switch (nv_device(gr)->chipset) {
+	switch (device->chipset) {
 	case 0x40:
 	case 0x41:
 	case 0x42:
 	case 0x43:
 	case 0x45:
-	case 0x4e:
 		nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch);
 		nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit);
 		nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr);
 		nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch);
 		nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit);
 		nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr);
-		switch (nv_device(gr)->chipset) {
+		switch (device->chipset) {
 		case 0x40:
 		case 0x45:
 			nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
@@ -209,50 +207,33 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i)
 			break;
 		}
 		break;
-	case 0x44:
-	case 0x4a:
-		nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch);
-		nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit);
-		nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr);
-		break;
-	case 0x46:
-	case 0x4c:
 	case 0x47:
 	case 0x49:
 	case 0x4b:
-	case 0x63:
-	case 0x67:
-	case 0x68:
 		nvkm_wr32(device, NV47_PGRAPH_TSIZE(i), tile->pitch);
 		nvkm_wr32(device, NV47_PGRAPH_TLIMIT(i), tile->limit);
 		nvkm_wr32(device, NV47_PGRAPH_TILE(i), tile->addr);
 		nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch);
 		nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit);
 		nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr);
-		switch (nv_device(gr)->chipset) {
-		case 0x47:
-		case 0x49:
-		case 0x4b:
-			nvkm_wr32(device, NV47_PGRAPH_ZCOMP0(i), tile->zcomp);
-			nvkm_wr32(device, NV47_PGRAPH_ZCOMP1(i), tile->zcomp);
-			break;
-		default:
-			break;
-		}
+		nvkm_wr32(device, NV47_PGRAPH_ZCOMP0(i), tile->zcomp);
+		nvkm_wr32(device, NV47_PGRAPH_ZCOMP1(i), tile->zcomp);
 		break;
 	default:
+		WARN_ON(1);
 		break;
 	}
 
 	nvkm_fifo_start(fifo, &flags);
 }
 
-static void
-nv40_gr_intr(struct nvkm_subdev *subdev)
+void
+nv40_gr_intr(struct nvkm_gr *base)
 {
-	struct nv40_gr *gr = (void *)subdev;
+	struct nv40_gr *gr = nv40_gr(base);
 	struct nv40_gr_chan *temp, *chan = NULL;
-	struct nvkm_device *device = gr->base.engine.subdev.device;
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
 	u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR);
 	u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE);
 	u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS);
@@ -301,98 +282,16 @@ nv40_gr_intr(struct nvkm_subdev *subdev)
 	spin_unlock_irqrestore(&gr->base.engine.lock, flags);
 }
 
-static const struct nvkm_gr_func
-nv40_gr = {
-	.chan_new = nv40_gr_chan_new,
-	.sclass = {
-		{ -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */
-		{ -1, -1, 0x0019, &nv40_gr_object }, /* clip */
-		{ -1, -1, 0x0030, &nv40_gr_object }, /* null */
-		{ -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */
-		{ -1, -1, 0x0043, &nv40_gr_object }, /* rop */
-		{ -1, -1, 0x0044, &nv40_gr_object }, /* patt */
-		{ -1, -1, 0x004a, &nv40_gr_object }, /* gdi */
-		{ -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */
-		{ -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */
-		{ -1, -1, 0x0089, &nv40_gr_object }, /* sifm */
-		{ -1, -1, 0x008a, &nv40_gr_object }, /* ifc */
-		{ -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */
-		{ -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */
-		{ -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */
-		{ -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */
-		{ -1, -1, 0x4097, &nv40_gr_object }, /* curie */
-		{}
-	}
-};
-
-static const struct nvkm_gr_func
-nv44_gr = {
-	.chan_new = nv40_gr_chan_new,
-	.sclass = {
-		{ -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */
-		{ -1, -1, 0x0019, &nv40_gr_object }, /* clip */
-		{ -1, -1, 0x0030, &nv40_gr_object }, /* null */
-		{ -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */
-		{ -1, -1, 0x0043, &nv40_gr_object }, /* rop */
-		{ -1, -1, 0x0044, &nv40_gr_object }, /* patt */
-		{ -1, -1, 0x004a, &nv40_gr_object }, /* gdi */
-		{ -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */
-		{ -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */
-		{ -1, -1, 0x0089, &nv40_gr_object }, /* sifm */
-		{ -1, -1, 0x008a, &nv40_gr_object }, /* ifc */
-		{ -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */
-		{ -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */
-		{ -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */
-		{ -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */
-		{ -1, -1, 0x4497, &nv40_gr_object }, /* curie */
-	{}
-	}
-};
-
-static int
-nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
-{
-	struct nvkm_device *device = (void *)parent;
-	struct nv40_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	INIT_LIST_HEAD(&gr->chan);
-
-	nv_subdev(gr)->unit = 0x00001000;
-	nv_subdev(gr)->intr = nv40_gr_intr;
-	if (nv44_gr_class(device))
-		gr->base.func = &nv44_gr;
-	else
-		gr->base.func = &nv40_gr;
-	nv_engine(gr)->tile_prog = nv40_gr_tile_prog;
-
-	gr->base.units = nv40_gr_units;
-	return 0;
-}
-
-static int
-nv40_gr_init(struct nvkm_object *object)
+int
+nv40_gr_init(struct nvkm_gr *base)
 {
-	struct nvkm_engine *engine = nv_engine(object);
-	struct nv40_gr *gr = (void *)engine;
+	struct nv40_gr *gr = nv40_gr(base);
 	struct nvkm_device *device = gr->base.engine.subdev.device;
-	struct nvkm_fb *fb = device->fb;
 	int ret, i, j;
 	u32 vramsz;
 
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
-
 	/* generate and upload context program */
-	ret = nv40_grctx_init(nv_device(gr), &gr->size);
+	ret = nv40_grctx_init(device, &gr->size);
 	if (ret)
 		return ret;
 
@@ -419,7 +318,7 @@ nv40_gr_init(struct nvkm_object *object)
 		nvkm_wr32(device, 0x405000, i);
 	}
 
-	if (nv_device(gr)->chipset == 0x40) {
+	if (device->chipset == 0x40) {
 		nvkm_wr32(device, 0x4009b0, 0x83280fff);
 		nvkm_wr32(device, 0x4009b4, 0x000000a0);
 	} else {
@@ -427,7 +326,7 @@ nv40_gr_init(struct nvkm_object *object)
 		nvkm_wr32(device, 0x400824, 0x000000a0);
 	}
 
-	switch (nv_device(gr)->chipset) {
+	switch (device->chipset) {
 	case 0x40:
 	case 0x45:
 		nvkm_wr32(device, 0x4009b8, 0x0078e366);
@@ -465,7 +364,7 @@ nv40_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, 0x400b3c, 0x00006000);
 
 	/* Tiling related stuff. */
-	switch (nv_device(gr)->chipset) {
+	switch (device->chipset) {
 	case 0x44:
 	case 0x4a:
 		nvkm_wr32(device, 0x400bc4, 0x1003d888);
@@ -485,13 +384,9 @@ nv40_gr_init(struct nvkm_object *object)
 		break;
 	}
 
-	/* Turn all the tiling regions off. */
-	for (i = 0; i < fb->tile.regions; i++)
-		engine->tile_prog(engine, i);
-
 	/* begin RAM config */
-	vramsz = nv_device_resource_len(nv_device(gr), 1) - 1;
-	switch (nv_device(gr)->chipset) {
+	vramsz = nv_device_resource_len(device, 1) - 1;
+	switch (device->chipset) {
 	case 0x40:
 		nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200));
 		nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204));
@@ -503,7 +398,7 @@ nv40_gr_init(struct nvkm_object *object)
 		nvkm_wr32(device, 0x400868, vramsz);
 		break;
 	default:
-		switch (nv_device(gr)->chipset) {
+		switch (device->chipset) {
 		case 0x41:
 		case 0x42:
 		case 0x43:
@@ -531,13 +426,50 @@ nv40_gr_init(struct nvkm_object *object)
 	return 0;
 }
 
-struct nvkm_oclass
-nv40_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x40),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv40_gr_ctor,
-		.dtor = _nvkm_gr_dtor,
-		.init = nv40_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
+int
+nv40_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device,
+	     int index, struct nvkm_gr **pgr)
+{
+	struct nv40_gr *gr;
+
+	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+		return -ENOMEM;
+	*pgr = &gr->base;
+	INIT_LIST_HEAD(&gr->chan);
+
+	return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base);
+}
+
+static const struct nvkm_gr_func
+nv40_gr = {
+	.init = nv40_gr_init,
+	.intr = nv40_gr_intr,
+	.tile = nv40_gr_tile,
+	.units = nv40_gr_units,
+	.chan_new = nv40_gr_chan_new,
+	.sclass = {
+		{ -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */
+		{ -1, -1, 0x0019, &nv40_gr_object }, /* clip */
+		{ -1, -1, 0x0030, &nv40_gr_object }, /* null */
+		{ -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */
+		{ -1, -1, 0x0043, &nv40_gr_object }, /* rop */
+		{ -1, -1, 0x0044, &nv40_gr_object }, /* patt */
+		{ -1, -1, 0x004a, &nv40_gr_object }, /* gdi */
+		{ -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */
+		{ -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */
+		{ -1, -1, 0x0089, &nv40_gr_object }, /* sifm */
+		{ -1, -1, 0x008a, &nv40_gr_object }, /* ifc */
+		{ -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */
+		{ -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */
+		{ -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */
+		{ -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */
+		{ -1, -1, 0x4097, &nv40_gr_object }, /* curie */
+		{}
+	}
 };
+
+int
+nv40_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv40_gr_new_(&nv40_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h
index 42cc409a8df2a..2812ed11f877b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h
@@ -9,6 +9,12 @@ struct nv40_gr {
 	struct list_head chan;
 };
 
+int nv40_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index,
+		 struct nvkm_gr **);
+int nv40_gr_init(struct nvkm_gr *);
+void nv40_gr_intr(struct nvkm_gr *);
+u64 nv40_gr_units(struct nvkm_gr *);
+
 #define nv40_gr_chan(p) container_of((p), struct nv40_gr_chan, object)
 
 struct nv40_gr_chan {
@@ -19,6 +25,11 @@ struct nv40_gr_chan {
 	struct list_head head;
 };
 
+int nv40_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *,
+		     const struct nvkm_oclass *, struct nvkm_object **);
+
+extern const struct nvkm_object_func nv40_gr_object;
+
 /* returns 1 if device is one of the nv4x using the 0x4497 object class,
  * helpful to determine a number of other hardware features
  */
@@ -28,7 +39,7 @@ nv44_gr_class(struct nvkm_device *device)
 	if ((device->chipset & 0xf0) == 0x60)
 		return 1;
 
-	return !(0x0baf & (1 << (device->chipset & 0x0f)));
+	return !(0x0aaf & (1 << (device->chipset & 0x0f)));
 }
 
 int  nv40_grctx_init(struct nvkm_device *, u32 *size);
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c
new file mode 100644
index 0000000000000..45ff80254eb40
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+#include "regs.h"
+
+#include <subdev/fb.h>
+#include <engine/fifo.h>
+
+static void
+nv44_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile)
+{
+	struct nv40_gr *gr = nv40_gr(base);
+	struct nvkm_device *device = gr->base.engine.subdev.device;
+	struct nvkm_fifo *fifo = device->fifo;
+	unsigned long flags;
+
+	nvkm_fifo_pause(fifo, &flags);
+	nv04_gr_idle(&gr->base);
+
+	switch (device->chipset) {
+	case 0x44:
+	case 0x4a:
+		nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch);
+		nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit);
+		nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr);
+		break;
+	case 0x46:
+	case 0x4c:
+	case 0x63:
+	case 0x67:
+	case 0x68:
+		nvkm_wr32(device, NV47_PGRAPH_TSIZE(i), tile->pitch);
+		nvkm_wr32(device, NV47_PGRAPH_TLIMIT(i), tile->limit);
+		nvkm_wr32(device, NV47_PGRAPH_TILE(i), tile->addr);
+		nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+		nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+		nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr);
+		break;
+	case 0x4e:
+		nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch);
+		nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit);
+		nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr);
+		nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+		nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+		nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr);
+		break;
+	default:
+		WARN_ON(1);
+		break;
+	}
+
+	nvkm_fifo_start(fifo, &flags);
+}
+
+static const struct nvkm_gr_func
+nv44_gr = {
+	.init = nv40_gr_init,
+	.intr = nv40_gr_intr,
+	.tile = nv44_gr_tile,
+	.units = nv40_gr_units,
+	.chan_new = nv40_gr_chan_new,
+	.sclass = {
+		{ -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */
+		{ -1, -1, 0x0019, &nv40_gr_object }, /* clip */
+		{ -1, -1, 0x0030, &nv40_gr_object }, /* null */
+		{ -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */
+		{ -1, -1, 0x0043, &nv40_gr_object }, /* rop */
+		{ -1, -1, 0x0044, &nv40_gr_object }, /* patt */
+		{ -1, -1, 0x004a, &nv40_gr_object }, /* gdi */
+		{ -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */
+		{ -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */
+		{ -1, -1, 0x0089, &nv40_gr_object }, /* sifm */
+		{ -1, -1, 0x008a, &nv40_gr_object }, /* ifc */
+		{ -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */
+		{ -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */
+		{ -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */
+		{ -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */
+		{ -1, -1, 0x4497, &nv40_gr_object }, /* curie */
+		{}
+	}
+};
+
+int
+nv44_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv40_gr_new_(&nv44_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
index 11c4c88389378..9992a919a6d9a 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
@@ -25,10 +25,9 @@
 
 #include <core/client.h>
 #include <core/gpuobj.h>
-#include <subdev/timer.h>
 #include <engine/fifo.h>
 
-static u64
+u64
 nv50_gr_units(struct nvkm_gr *gr)
 {
 	return nvkm_rd32(gr->engine.subdev.device, 0x1540);
@@ -55,27 +54,11 @@ nv50_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent,
 	return ret;
 }
 
-static const struct nvkm_object_func
+const struct nvkm_object_func
 nv50_gr_object = {
 	.bind = nv50_gr_object_bind,
 };
 
-static int
-nv50_gr_object_get(struct nvkm_gr *base, int index, struct nvkm_sclass *sclass)
-{
-	struct nv50_gr *gr = nv50_gr(base);
-	int c = 0;
-
-	while (gr->func->sclass[c].oclass) {
-		if (c++ == index) {
-			*sclass = gr->func->sclass[index];
-			return index;
-		}
-	}
-
-	return c;
-}
-
 /*******************************************************************************
  * PGRAPH context
  ******************************************************************************/
@@ -100,7 +83,7 @@ nv50_gr_chan = {
 	.bind = nv50_gr_chan_bind,
 };
 
-static int
+int
 nv50_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
 		 const struct nvkm_oclass *oclass, struct nvkm_object **pobject)
 {
@@ -119,153 +102,6 @@ nv50_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static const struct nvkm_bitfield nv50_gr_status[] = {
-	{ 0x00000001, "BUSY" }, /* set when any bit is set */
-	{ 0x00000002, "DISPATCH" },
-	{ 0x00000004, "UNK2" },
-	{ 0x00000008, "UNK3" },
-	{ 0x00000010, "UNK4" },
-	{ 0x00000020, "UNK5" },
-	{ 0x00000040, "M2MF" },
-	{ 0x00000080, "UNK7" },
-	{ 0x00000100, "CTXPROG" },
-	{ 0x00000200, "VFETCH" },
-	{ 0x00000400, "CCACHE_PREGEOM" },
-	{ 0x00000800, "STRMOUT_VATTR_POSTGEOM" },
-	{ 0x00001000, "VCLIP" },
-	{ 0x00002000, "RATTR_APLANE" },
-	{ 0x00004000, "TRAST" },
-	{ 0x00008000, "CLIPID" },
-	{ 0x00010000, "ZCULL" },
-	{ 0x00020000, "ENG2D" },
-	{ 0x00040000, "RMASK" },
-	{ 0x00080000, "TPC_RAST" },
-	{ 0x00100000, "TPC_PROP" },
-	{ 0x00200000, "TPC_TEX" },
-	{ 0x00400000, "TPC_GEOM" },
-	{ 0x00800000, "TPC_MP" },
-	{ 0x01000000, "ROP" },
-	{}
-};
-
-static const struct nvkm_bitfield
-nv50_gr_vstatus_0[] = {
-	{ 0x01, "VFETCH" },
-	{ 0x02, "CCACHE" },
-	{ 0x04, "PREGEOM" },
-	{ 0x08, "POSTGEOM" },
-	{ 0x10, "VATTR" },
-	{ 0x20, "STRMOUT" },
-	{ 0x40, "VCLIP" },
-	{}
-};
-
-static const struct nvkm_bitfield
-nv50_gr_vstatus_1[] = {
-	{ 0x01, "TPC_RAST" },
-	{ 0x02, "TPC_PROP" },
-	{ 0x04, "TPC_TEX" },
-	{ 0x08, "TPC_GEOM" },
-	{ 0x10, "TPC_MP" },
-	{}
-};
-
-static const struct nvkm_bitfield
-nv50_gr_vstatus_2[] = {
-	{ 0x01, "RATTR" },
-	{ 0x02, "APLANE" },
-	{ 0x04, "TRAST" },
-	{ 0x08, "CLIPID" },
-	{ 0x10, "ZCULL" },
-	{ 0x20, "ENG2D" },
-	{ 0x40, "RMASK" },
-	{ 0x80, "ROP" },
-	{}
-};
-
-static void
-nvkm_gr_vstatus_print(struct nv50_gr *gr, int r,
-		      const struct nvkm_bitfield *units, u32 status)
-{
-	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
-	u32 stat = status;
-	u8  mask = 0x00;
-	char msg[64];
-	int i;
-
-	for (i = 0; units[i].name && status; i++) {
-		if ((status & 7) == 1)
-			mask |= (1 << i);
-		status >>= 3;
-	}
-
-	nvkm_snprintbf(msg, sizeof(msg), units, mask);
-	nvkm_error(subdev, "PGRAPH_VSTATUS%d: %08x [%s]\n", r, stat, msg);
-}
-
-static int
-g84_gr_tlb_flush(struct nvkm_engine *engine)
-{
-	struct nv50_gr *gr = (void *)engine;
-	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
-	struct nvkm_device *device = subdev->device;
-	struct nvkm_timer *tmr = device->timer;
-	bool idle, timeout = false;
-	unsigned long flags;
-	char status[128];
-	u64 start;
-	u32 tmp;
-
-	spin_lock_irqsave(&gr->lock, flags);
-	nvkm_mask(device, 0x400500, 0x00000001, 0x00000000);
-
-	start = nvkm_timer_read(tmr);
-	do {
-		idle = true;
-
-		for (tmp = nvkm_rd32(device, 0x400380); tmp && idle; tmp >>= 3) {
-			if ((tmp & 7) == 1)
-				idle = false;
-		}
-
-		for (tmp = nvkm_rd32(device, 0x400384); tmp && idle; tmp >>= 3) {
-			if ((tmp & 7) == 1)
-				idle = false;
-		}
-
-		for (tmp = nvkm_rd32(device, 0x400388); tmp && idle; tmp >>= 3) {
-			if ((tmp & 7) == 1)
-				idle = false;
-		}
-	} while (!idle &&
-		 !(timeout = nvkm_timer_read(tmr) - start > 2000000000));
-
-	if (timeout) {
-		nvkm_error(subdev, "PGRAPH TLB flush idle timeout fail\n");
-
-		tmp = nvkm_rd32(device, 0x400700);
-		nvkm_snprintbf(status, sizeof(status), nv50_gr_status, tmp);
-		nvkm_error(subdev, "PGRAPH_STATUS %08x [%s]\n", tmp, status);
-
-		nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0,
-				       nvkm_rd32(device, 0x400380));
-		nvkm_gr_vstatus_print(gr, 1, nv50_gr_vstatus_1,
-				       nvkm_rd32(device, 0x400384));
-		nvkm_gr_vstatus_print(gr, 2, nv50_gr_vstatus_2,
-				       nvkm_rd32(device, 0x400388));
-	}
-
-
-	nvkm_wr32(device, 0x100c80, 0x00000001);
-	nvkm_msec(device, 2000,
-		if (!(nvkm_rd32(device, 0x100c80) & 0x00000001))
-			break;
-	);
-	nvkm_mask(device, 0x400500, 0x00000001, 0x00000001);
-	spin_unlock_irqrestore(&gr->lock, flags);
-	return timeout ? -EBUSY : 0;
-}
-
 static const struct nvkm_bitfield nv50_mp_exec_errors[] = {
 	{ 0x01, "STACK_UNDERFLOW" },
 	{ 0x02, "STACK_MISMATCH" },
@@ -453,7 +289,7 @@ nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display)
 	for (i = 0; i < 4; i++) {
 		if (!(units & 1 << (i+24)))
 			continue;
-		if (nv_device(gr)->chipset < 0xa0)
+		if (device->chipset < 0xa0)
 			addr = 0x408200 + (tpid << 12) + (i << 7);
 		else
 			addr = 0x408100 + (tpid << 11) + (i << 7);
@@ -497,7 +333,7 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old,
 	for (i = 0; i < 16; i++) {
 		if (!(units & (1 << i)))
 			continue;
-		if (nv_device(gr)->chipset < 0xa0)
+		if (device->chipset < 0xa0)
 			ustatus_addr = ustatus_old + (i << 12);
 		else
 			ustatus_addr = ustatus_new + (i << 11);
@@ -778,11 +614,12 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display,
 	return 1;
 }
 
-static void
-nv50_gr_intr(struct nvkm_subdev *subdev)
+void
+nv50_gr_intr(struct nvkm_gr *base)
 {
-	struct nv50_gr *gr = (void *)subdev;
-	struct nvkm_device *device = gr->base.engine.subdev.device;
+	struct nv50_gr *gr = nv50_gr(base);
+	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
+	struct nvkm_device *device = subdev->device;
 	struct nvkm_fifo_chan *chan;
 	u32 stat = nvkm_rd32(device, 0x400100);
 	u32 inst = nvkm_rd32(device, 0x40032c) & 0x0fffffff;
@@ -836,140 +673,13 @@ nv50_gr_intr(struct nvkm_subdev *subdev)
 	nvkm_fifo_chan_put(device->fifo, flags, &chan);
 }
 
-static const struct nv50_gr_func
-nv50_gr = {
-	.sclass = {
-		{ -1, -1, 0x0030, &nv50_gr_object },
-		{ -1, -1, 0x502d, &nv50_gr_object },
-		{ -1, -1, 0x5039, &nv50_gr_object },
-		{ -1, -1, 0x5097, &nv50_gr_object },
-		{ -1, -1, 0x50c0, &nv50_gr_object },
-		{}
-	}
-};
-
-static const struct nv50_gr_func
-g84_gr = {
-	.sclass = {
-		{ -1, -1, 0x0030, &nv50_gr_object },
-		{ -1, -1, 0x502d, &nv50_gr_object },
-		{ -1, -1, 0x5039, &nv50_gr_object },
-		{ -1, -1, 0x50c0, &nv50_gr_object },
-		{ -1, -1, 0x8297, &nv50_gr_object },
-		{}
-	}
-};
-
-static const struct nv50_gr_func
-gt200_gr = {
-	.sclass = {
-		{ -1, -1, 0x0030, &nv50_gr_object },
-		{ -1, -1, 0x502d, &nv50_gr_object },
-		{ -1, -1, 0x5039, &nv50_gr_object },
-		{ -1, -1, 0x50c0, &nv50_gr_object },
-		{ -1, -1, 0x8397, &nv50_gr_object },
-		{}
-	}
-};
-
-static const struct nv50_gr_func
-gt215_gr = {
-	.sclass = {
-		{ -1, -1, 0x0030, &nv50_gr_object },
-		{ -1, -1, 0x502d, &nv50_gr_object },
-		{ -1, -1, 0x5039, &nv50_gr_object },
-		{ -1, -1, 0x50c0, &nv50_gr_object },
-		{ -1, -1, 0x8597, &nv50_gr_object },
-		{ -1, -1, 0x85c0, &nv50_gr_object },
-		{}
-	}
-};
-
-static const struct nv50_gr_func
-mcp89_gr = {
-	.sclass = {
-		{ -1, -1, 0x0030, &nv50_gr_object },
-		{ -1, -1, 0x502d, &nv50_gr_object },
-		{ -1, -1, 0x5039, &nv50_gr_object },
-		{ -1, -1, 0x50c0, &nv50_gr_object },
-		{ -1, -1, 0x85c0, &nv50_gr_object },
-		{ -1, -1, 0x8697, &nv50_gr_object },
-		{}
-	}
-};
-
-static const struct nvkm_gr_func
-nv50_gr_ = {
-	.chan_new = nv50_gr_chan_new,
-	.object_get = nv50_gr_object_get,
-};
-
-static int
-nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
-	     struct nvkm_oclass *oclass, void *data, u32 size,
-	     struct nvkm_object **pobject)
-{
-	struct nv50_gr *gr;
-	int ret;
-
-	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
-	*pobject = nv_object(gr);
-	if (ret)
-		return ret;
-
-	nv_subdev(gr)->unit = 0x00201000;
-	nv_subdev(gr)->intr = nv50_gr_intr;
-
-	gr->base.func = &nv50_gr_;
-	gr->base.units = nv50_gr_units;
-
-	switch (nv_device(gr)->chipset) {
-	case 0x50:
-		gr->func = &nv50_gr;
-		break;
-	case 0x84:
-	case 0x86:
-	case 0x92:
-	case 0x94:
-	case 0x96:
-	case 0x98:
-		gr->func = &g84_gr;
-		break;
-	case 0xa0:
-	case 0xaa:
-	case 0xac:
-		gr->func = &gt200_gr;
-		break;
-	case 0xa3:
-	case 0xa5:
-	case 0xa8:
-		gr->func = &gt215_gr;
-		break;
-	case 0xaf:
-		gr->func = &mcp89_gr;
-		break;
-	}
-
-	/* unfortunate hw bug workaround... */
-	if (nv_device(gr)->chipset != 0x50 &&
-	    nv_device(gr)->chipset != 0xac)
-		nv_engine(gr)->tlb_flush = g84_gr_tlb_flush;
-
-	spin_lock_init(&gr->lock);
-	return 0;
-}
-
-static int
-nv50_gr_init(struct nvkm_object *object)
+int
+nv50_gr_init(struct nvkm_gr *base)
 {
-	struct nv50_gr *gr = (void *)object;
+	struct nv50_gr *gr = nv50_gr(base);
 	struct nvkm_device *device = gr->base.engine.subdev.device;
 	int ret, units, i;
 
-	ret = nvkm_gr_init(&gr->base);
-	if (ret)
-		return ret;
-
 	/* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */
 	nvkm_wr32(device, 0x40008c, 0x00000004);
 
@@ -986,7 +696,7 @@ nv50_gr_init(struct nvkm_object *object)
 		if (!(units & (1 << i)))
 			continue;
 
-		if (nv_device(gr)->chipset < 0xa0) {
+		if (device->chipset < 0xa0) {
 			nvkm_wr32(device, 0x408900 + (i << 12), 0xc0000000);
 			nvkm_wr32(device, 0x408e08 + (i << 12), 0xc0000000);
 			nvkm_wr32(device, 0x408314 + (i << 12), 0xc0000000);
@@ -1004,7 +714,7 @@ nv50_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, 0x400500, 0x00010001);
 
 	/* upload context program, initialise ctxctl defaults */
-	ret = nv50_grctx_init(nv_device(gr), &gr->size);
+	ret = nv50_grctx_init(device, &gr->size);
 	if (ret)
 		return ret;
 
@@ -1016,7 +726,7 @@ nv50_gr_init(struct nvkm_object *object)
 	nvkm_wr32(device, 0x400330, 0x00000000);
 
 	/* some unknown zcull magic */
-	switch (nv_device(gr)->chipset & 0xf0) {
+	switch (device->chipset & 0xf0) {
 	case 0x50:
 	case 0x80:
 	case 0x90:
@@ -1024,9 +734,9 @@ nv50_gr_init(struct nvkm_object *object)
 		break;
 	case 0xa0:
 	default:
-		if (nv_device(gr)->chipset == 0xa0 ||
-		    nv_device(gr)->chipset == 0xaa ||
-		    nv_device(gr)->chipset == 0xac) {
+		if (device->chipset == 0xa0 ||
+		    device->chipset == 0xaa ||
+		    device->chipset == 0xac) {
 			nvkm_wr32(device, 0x402ca8, 0x00000802);
 		} else {
 			nvkm_wr32(device, 0x402cc0, 0x00000000);
@@ -1043,16 +753,42 @@ nv50_gr_init(struct nvkm_object *object)
 		nvkm_wr32(device, 0x402c28 + (i * 0x10), 0x00000000);
 		nvkm_wr32(device, 0x402c2c + (i * 0x10), 0x00000000);
 	}
+
 	return 0;
 }
 
-struct nvkm_oclass
-nv50_gr_oclass = {
-	.handle = NV_ENGINE(GR, 0x50),
-	.ofuncs = &(struct nvkm_ofuncs) {
-		.ctor = nv50_gr_ctor,
-		.dtor = _nvkm_gr_dtor,
-		.init = nv50_gr_init,
-		.fini = _nvkm_gr_fini,
-	},
+int
+nv50_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device,
+	     int index, struct nvkm_gr **pgr)
+{
+	struct nv50_gr *gr;
+
+	if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL)))
+		return -ENOMEM;
+	spin_lock_init(&gr->lock);
+	*pgr = &gr->base;
+
+	return nvkm_gr_ctor(func, device, index, 0x00201000, true, &gr->base);
+}
+
+static const struct nvkm_gr_func
+nv50_gr = {
+	.init = nv50_gr_init,
+	.intr = nv50_gr_intr,
+	.chan_new = nv50_gr_chan_new,
+	.units = nv50_gr_units,
+	.sclass = {
+		{ -1, -1, 0x0030, &nv50_gr_object },
+		{ -1, -1, 0x502d, &nv50_gr_object },
+		{ -1, -1, 0x5039, &nv50_gr_object },
+		{ -1, -1, 0x5097, &nv50_gr_object },
+		{ -1, -1, 0x50c0, &nv50_gr_object },
+		{}
+	}
 };
+
+int
+nv50_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr)
+{
+	return nv50_gr_new_(&nv50_gr, device, index, pgr);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h
index 145ea5026a8e4..45eec83a5969b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h
@@ -10,10 +10,13 @@ struct nv50_gr {
 	u32 size;
 };
 
-struct nv50_gr_func {
-	void *(*dtor)(struct nv50_gr *);
-	struct nvkm_sclass sclass[];
-};
+int nv50_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index,
+		 struct nvkm_gr **);
+int nv50_gr_init(struct nvkm_gr *);
+void nv50_gr_intr(struct nvkm_gr *);
+u64 nv50_gr_units(struct nvkm_gr *);
+
+int g84_gr_tlb_flush(struct nvkm_gr *);
 
 #define nv50_gr_chan(p) container_of((p), struct nv50_gr_chan, object)
 
@@ -22,6 +25,11 @@ struct nv50_gr_chan {
 	struct nv50_gr *gr;
 };
 
+int nv50_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *,
+		     const struct nvkm_oclass *, struct nvkm_object **);
+
+extern const struct nvkm_object_func nv50_gr_object;
+
 int  nv50_grctx_init(struct nvkm_device *, u32 *size);
 void nv50_grctx_fill(struct nvkm_device *, struct nvkm_gpuobj *);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
index f7fd617b6fe51..a234590be88e8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h
@@ -2,14 +2,37 @@
 #define __NVKM_GR_PRIV_H__
 #define nvkm_gr(p) container_of((p), struct nvkm_gr, engine)
 #include <engine/gr.h>
+#include <core/enum.h>
+struct nvkm_fb_tile;
 struct nvkm_fifo_chan;
 
+int nvkm_gr_ctor(const struct nvkm_gr_func *, struct nvkm_device *,
+		 int index, u32 pmc_enable, bool enable,
+		 struct nvkm_gr *);
+
+bool nv04_gr_idle(struct nvkm_gr *);
+
 struct nvkm_gr_func {
+	void *(*dtor)(struct nvkm_gr *);
+	int (*oneinit)(struct nvkm_gr *);
+	int (*init)(struct nvkm_gr *);
+	void (*intr)(struct nvkm_gr *);
+	void (*tile)(struct nvkm_gr *, int region, struct nvkm_fb_tile *);
+	int (*tlb_flush)(struct nvkm_gr *);
 	int (*chan_new)(struct nvkm_gr *, struct nvkm_fifo_chan *,
 			const struct nvkm_oclass *, struct nvkm_object **);
 	int (*object_get)(struct nvkm_gr *, int, struct nvkm_sclass *);
+	/* Returns chipset-specific counts of units packed into an u64.
+	 */
+	u64 (*units)(struct nvkm_gr *);
 	struct nvkm_sclass sclass[];
 };
 
+extern const struct nvkm_bitfield nv04_gr_nsource[];
 extern const struct nvkm_object_func nv04_gr_object;
+
+extern const struct nvkm_bitfield nv10_gr_intr_name[];
+extern const struct nvkm_bitfield nv10_gr_nstatus[];
+
+extern const struct nvkm_enum nv50_data_error_names[];
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
index 0f39ff883ec0d..1ca02f870095c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
@@ -52,11 +52,13 @@ void
 nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile)
 {
 	struct nvkm_device *device = fb->subdev.device;
-	fb->func->tile.prog(fb, region, tile);
-	if (likely(device->gr))
-		device->gr->engine.tile_prog(&device->gr->engine, region);
-	if (likely(device->mpeg))
-		device->mpeg->tile_prog(device->mpeg, region);
+	if (fb->func->tile.prog) {
+		fb->func->tile.prog(fb, region, tile);
+		if (device->gr)
+			nvkm_engine_tile(&device->gr->engine, region);
+		if (likely(device->mpeg))
+			device->mpeg->tile_prog(device->mpeg, region);
+	}
 }
 
 int
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
index 931f14094eb50..21a990c1ac8bb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
@@ -23,11 +23,10 @@
  */
 #include "priv.h"
 
+#include <core/gpuobj.h>
 #include <subdev/fb.h>
 #include <subdev/timer.h>
-
-#include <core/engine.h>
-#include <core/gpuobj.h>
+#include <engine/gr.h>
 
 static void
 nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_memory *pgt[2])
@@ -167,13 +166,10 @@ nv50_vm_flush(struct nvkm_vm *vm)
 			continue;
 
 		/* unfortunate hw bug workaround... */
-		if (i == NVDEV_ENGINE_GR) {
-			struct nvkm_engine *engine =
-				nvkm_device_engine(device, i);
-			if (engine && engine->tlb_flush) {
-				engine->tlb_flush(engine);
+		if (i == NVDEV_ENGINE_GR && device->gr) {
+			int ret = nvkm_gr_tlb_flush(device->gr);
+			if (ret != -ENODEV)
 				continue;
-			}
 		}
 
 		switch (i) {
-- 
2.30.2