drm/nouveau: port all engines to new engine module format
[linux-3.10.git] / drivers / gpu / drm / nouveau / core / engine / graph / nv10.c
index d006658..ce38196 100644 (file)
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
-#include "drm.h"
-#include <nouveau_drm.h>
-#include "nouveau_drv.h"
-#include "nouveau_util.h"
-
-struct nv10_graph_engine {
-       struct nouveau_exec_engine base;
-};
+#include <core/os.h>
+#include <core/class.h>
+#include <core/handle.h>
+
+#include <subdev/fb.h>
+
+#include <engine/fifo.h>
+#include <engine/graph.h>
+
+#include "regs.h"
 
 struct pipe_state {
-       uint32_t pipe_0x0000[0x040/4];
-       uint32_t pipe_0x0040[0x010/4];
-       uint32_t pipe_0x0200[0x0c0/4];
-       uint32_t pipe_0x4400[0x080/4];
-       uint32_t pipe_0x6400[0x3b0/4];
-       uint32_t pipe_0x6800[0x2f0/4];
-       uint32_t pipe_0x6c00[0x030/4];
-       uint32_t pipe_0x7000[0x130/4];
-       uint32_t pipe_0x7400[0x0c0/4];
-       uint32_t pipe_0x7800[0x0c0/4];
+       u32 pipe_0x0000[0x040/4];
+       u32 pipe_0x0040[0x010/4];
+       u32 pipe_0x0200[0x0c0/4];
+       u32 pipe_0x4400[0x080/4];
+       u32 pipe_0x6400[0x3b0/4];
+       u32 pipe_0x6800[0x2f0/4];
+       u32 pipe_0x6c00[0x030/4];
+       u32 pipe_0x7000[0x130/4];
+       u32 pipe_0x7400[0x0c0/4];
+       u32 pipe_0x7800[0x0c0/4];
 };
 
 static int nv10_graph_ctx_regs[] = {
@@ -388,117 +389,322 @@ static int nv17_graph_ctx_regs[] = {
        0x00400a04,
 };
 
-struct graph_state {
+struct nv10_graph_priv {
+       struct nouveau_graph base;
+       struct nv10_graph_chan *chan[32];
+       spinlock_t lock;
+};
+
+struct nv10_graph_chan {
+       struct nouveau_object base;
+       int chid;
        int nv10[ARRAY_SIZE(nv10_graph_ctx_regs)];
        int nv17[ARRAY_SIZE(nv17_graph_ctx_regs)];
        struct pipe_state pipe_state;
-       uint32_t lma_window[4];
+       u32 lma_window[4];
 };
 
-#define PIPE_SAVE(dev, state, addr)                                    \
+
+static inline struct nv10_graph_priv *
+nv10_graph_priv(struct nv10_graph_chan *chan)
+{
+       return (void *)nv_object(chan)->engine;
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+#define PIPE_SAVE(priv, state, addr)                                   \
        do {                                                            \
                int __i;                                                \
-               nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr);           \
+               nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);          \
                for (__i = 0; __i < ARRAY_SIZE(state); __i++)           \
-                       state[__i] = nv_rd32(dev, NV10_PGRAPH_PIPE_DATA); \
+                       state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \
        } while (0)
 
-#define PIPE_RESTORE(dev, state, addr)                                 \
+#define PIPE_RESTORE(priv, state, addr)                                        \
        do {                                                            \
                int __i;                                                \
-               nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, addr);           \
+               nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr);          \
                for (__i = 0; __i < ARRAY_SIZE(state); __i++)           \
-                       nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, state[__i]); \
+                       nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \
        } while (0)
 
-static void nv10_graph_save_pipe(struct nouveau_channel *chan)
+static struct nouveau_oclass
+nv10_graph_sclass[] = {
+       { 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+       { 0x0019, &nv04_graph_ofuncs }, /* clip */
+       { 0x0030, &nv04_graph_ofuncs }, /* null */
+       { 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+       { 0x0043, &nv04_graph_ofuncs }, /* rop */
+       { 0x0044, &nv04_graph_ofuncs }, /* pattern */
+       { 0x004a, &nv04_graph_ofuncs }, /* gdi */
+       { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+       { 0x005f, &nv04_graph_ofuncs }, /* blit */
+       { 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+       { 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+       { 0x0089, &nv04_graph_ofuncs }, /* sifm */
+       { 0x008a, &nv04_graph_ofuncs }, /* ifc */
+       { 0x009f, &nv04_graph_ofuncs }, /* blit */
+       { 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+       { 0x0094, &nv04_graph_ofuncs }, /* ttri */
+       { 0x0095, &nv04_graph_ofuncs }, /* mtri */
+       { 0x0056, &nv04_graph_ofuncs }, /* celcius */
+       {},
+};
+
+static struct nouveau_oclass
+nv15_graph_sclass[] = {
+       { 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+       { 0x0019, &nv04_graph_ofuncs }, /* clip */
+       { 0x0030, &nv04_graph_ofuncs }, /* null */
+       { 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+       { 0x0043, &nv04_graph_ofuncs }, /* rop */
+       { 0x0044, &nv04_graph_ofuncs }, /* pattern */
+       { 0x004a, &nv04_graph_ofuncs }, /* gdi */
+       { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+       { 0x005f, &nv04_graph_ofuncs }, /* blit */
+       { 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+       { 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+       { 0x0089, &nv04_graph_ofuncs }, /* sifm */
+       { 0x008a, &nv04_graph_ofuncs }, /* ifc */
+       { 0x009f, &nv04_graph_ofuncs }, /* blit */
+       { 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+       { 0x0094, &nv04_graph_ofuncs }, /* ttri */
+       { 0x0095, &nv04_graph_ofuncs }, /* mtri */
+       { 0x0096, &nv04_graph_ofuncs }, /* celcius */
+       {},
+};
+
+static int
+nv17_graph_mthd_lma_window(struct nouveau_object *object, u32 mthd,
+                          void *args, u32 size)
+{
+       struct nv10_graph_chan *chan = (void *)object->parent;
+       struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+       struct pipe_state *pipe = &chan->pipe_state;
+       u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
+       u32 xfmode0, xfmode1;
+       u32 data = *(u32 *)args;
+       int i;
+
+       chan->lma_window[(mthd - 0x1638) / 4] = data;
+
+       if (mthd != 0x1644)
+               return 0;
+
+       nv04_graph_idle(priv);
+
+       PIPE_SAVE(priv, pipe_0x0040, 0x0040);
+       PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+
+       PIPE_RESTORE(priv, chan->lma_window, 0x6790);
+
+       nv04_graph_idle(priv);
+
+       xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+       xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+
+       PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+       PIPE_SAVE(priv, pipe_0x64c0, 0x64c0);
+       PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0);
+       PIPE_SAVE(priv, pipe_0x6a80, 0x6a80);
+
+       nv04_graph_idle(priv);
+
+       nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+       nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+       for (i = 0; i < 4; i++)
+               nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+       for (i = 0; i < 4; i++)
+               nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+       for (i = 0; i < 3; i++)
+               nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+       for (i = 0; i < 3; i++)
+               nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+       nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+       PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
+
+       nv04_graph_idle(priv);
+
+       PIPE_RESTORE(priv, pipe_0x0040, 0x0040);
+
+       nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+       nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+
+       PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0);
+       PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0);
+       PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80);
+       PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
+       nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+       nv04_graph_idle(priv);
+
+       return 0;
+}
+
+static int
+nv17_graph_mthd_lma_enable(struct nouveau_object *object, u32 mthd,
+                          void *args, u32 size)
 {
-       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-       struct pipe_state *pipe = &pgraph_ctx->pipe_state;
-       struct drm_device *dev = chan->dev;
-
-       PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
-       PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
-       PIPE_SAVE(dev, pipe->pipe_0x6400, 0x6400);
-       PIPE_SAVE(dev, pipe->pipe_0x6800, 0x6800);
-       PIPE_SAVE(dev, pipe->pipe_0x6c00, 0x6c00);
-       PIPE_SAVE(dev, pipe->pipe_0x7000, 0x7000);
-       PIPE_SAVE(dev, pipe->pipe_0x7400, 0x7400);
-       PIPE_SAVE(dev, pipe->pipe_0x7800, 0x7800);
-       PIPE_SAVE(dev, pipe->pipe_0x0040, 0x0040);
-       PIPE_SAVE(dev, pipe->pipe_0x0000, 0x0000);
+       struct nv10_graph_chan *chan = (void *)object->parent;
+       struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+
+       nv04_graph_idle(priv);
+
+       nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100);
+       nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000);
+       return 0;
 }
 
-static void nv10_graph_load_pipe(struct nouveau_channel *chan)
+static struct nouveau_omthds
+nv17_celcius_omthds[] = {
+       { 0x1638, nv17_graph_mthd_lma_window },
+       { 0x163c, nv17_graph_mthd_lma_window },
+       { 0x1640, nv17_graph_mthd_lma_window },
+       { 0x1644, nv17_graph_mthd_lma_window },
+       { 0x1658, nv17_graph_mthd_lma_enable },
+       {}
+};
+
+static struct nouveau_oclass
+nv17_graph_sclass[] = {
+       { 0x0012, &nv04_graph_ofuncs }, /* beta1 */
+       { 0x0019, &nv04_graph_ofuncs }, /* clip */
+       { 0x0030, &nv04_graph_ofuncs }, /* null */
+       { 0x0039, &nv04_graph_ofuncs }, /* m2mf */
+       { 0x0043, &nv04_graph_ofuncs }, /* rop */
+       { 0x0044, &nv04_graph_ofuncs }, /* pattern */
+       { 0x004a, &nv04_graph_ofuncs }, /* gdi */
+       { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
+       { 0x005f, &nv04_graph_ofuncs }, /* blit */
+       { 0x0062, &nv04_graph_ofuncs }, /* surf2d */
+       { 0x0072, &nv04_graph_ofuncs }, /* beta4 */
+       { 0x0089, &nv04_graph_ofuncs }, /* sifm */
+       { 0x008a, &nv04_graph_ofuncs }, /* ifc */
+       { 0x009f, &nv04_graph_ofuncs }, /* blit */
+       { 0x0093, &nv04_graph_ofuncs }, /* surf3d */
+       { 0x0094, &nv04_graph_ofuncs }, /* ttri */
+       { 0x0095, &nv04_graph_ofuncs }, /* mtri */
+       { 0x0099, &nv04_graph_ofuncs, nv17_celcius_omthds },
+       {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv10_graph_chan *
+nv10_graph_channel(struct nv10_graph_priv *priv)
 {
-       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-       struct pipe_state *pipe = &pgraph_ctx->pipe_state;
-       struct drm_device *dev = chan->dev;
-       uint32_t xfmode0, xfmode1;
+       struct nv10_graph_chan *chan = NULL;
+       if (nv_rd32(priv, 0x400144) & 0x00010000) {
+               int chid = nv_rd32(priv, 0x400148) >> 24;
+               if (chid < ARRAY_SIZE(priv->chan))
+                       chan = priv->chan[chid];
+       }
+       return chan;
+}
+
+static void
+nv10_graph_save_pipe(struct nv10_graph_chan *chan)
+{
+       struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+       struct pipe_state *pipe = &chan->pipe_state;
+
+       PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+       PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+       PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400);
+       PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800);
+       PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00);
+       PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000);
+       PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400);
+       PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800);
+       PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040);
+       PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000);
+}
+
+static void
+nv10_graph_load_pipe(struct nv10_graph_chan *chan)
+{
+       struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+       struct pipe_state *pipe = &chan->pipe_state;
+       u32 xfmode0, xfmode1;
        int i;
 
-       nouveau_wait_for_idle(dev);
+       nv04_graph_idle(priv);
        /* XXX check haiku comments */
-       xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0);
-       xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1);
-       nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000);
-       nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+       xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+       xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+       nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+       nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
        for (i = 0; i < 4; i++)
-               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+               nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
        for (i = 0; i < 4; i++)
-               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+               nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
 
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
        for (i = 0; i < 3; i++)
-               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+               nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
 
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
        for (i = 0; i < 3; i++)
-               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+               nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
 
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
-       nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+       nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+       nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
 
 
-       PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
-       nouveau_wait_for_idle(dev);
+       PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
+       nv04_graph_idle(priv);
 
        /* restore XFMODE */
-       nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
-       nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
-       PIPE_RESTORE(dev, pipe->pipe_0x6400, 0x6400);
-       PIPE_RESTORE(dev, pipe->pipe_0x6800, 0x6800);
-       PIPE_RESTORE(dev, pipe->pipe_0x6c00, 0x6c00);
-       PIPE_RESTORE(dev, pipe->pipe_0x7000, 0x7000);
-       PIPE_RESTORE(dev, pipe->pipe_0x7400, 0x7400);
-       PIPE_RESTORE(dev, pipe->pipe_0x7800, 0x7800);
-       PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
-       PIPE_RESTORE(dev, pipe->pipe_0x0000, 0x0000);
-       PIPE_RESTORE(dev, pipe->pipe_0x0040, 0x0040);
-       nouveau_wait_for_idle(dev);
+       nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+       nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+       PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400);
+       PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800);
+       PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00);
+       PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000);
+       PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400);
+       PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800);
+       PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+       PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000);
+       PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040);
+       nv04_graph_idle(priv);
 }
 
-static void nv10_graph_create_pipe(struct nouveau_channel *chan)
+static void
+nv10_graph_create_pipe(struct nv10_graph_chan *chan)
 {
-       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-       struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
-       struct drm_device *dev = chan->dev;
-       uint32_t *fifo_pipe_state_addr;
+       struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+       struct pipe_state *pipe_state = &chan->pipe_state;
+       u32 *pipe_state_addr;
        int i;
 #define PIPE_INIT(addr) \
        do { \
-               fifo_pipe_state_addr = fifo_pipe_state->pipe_##addr; \
+               pipe_state_addr = pipe_state->pipe_##addr; \
        } while (0)
 #define PIPE_INIT_END(addr) \
        do { \
-               uint32_t *__end_addr = fifo_pipe_state->pipe_##addr + \
-                               ARRAY_SIZE(fifo_pipe_state->pipe_##addr); \
-               if (fifo_pipe_state_addr != __end_addr) \
-                       NV_ERROR(dev, "incomplete pipe init for 0x%x :  %p/%p\n", \
-                               addr, fifo_pipe_state_addr, __end_addr); \
+               u32 *__end_addr = pipe_state->pipe_##addr + \
+                               ARRAY_SIZE(pipe_state->pipe_##addr); \
+               if (pipe_state_addr != __end_addr) \
+                       nv_error(priv, "incomplete pipe init for 0x%x :  %p/%p\n", \
+                               addr, pipe_state_addr, __end_addr); \
        } while (0)
-#define NV_WRITE_PIPE_INIT(value) *(fifo_pipe_state_addr++) = value
+#define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value
 
        PIPE_INIT(0x0200);
        for (i = 0; i < 48; i++)
@@ -634,34 +840,36 @@ static void nv10_graph_create_pipe(struct nouveau_channel *chan)
 #undef NV_WRITE_PIPE_INIT
 }
 
-static int nv10_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
+static int
+nv10_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
 {
        int i;
        for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) {
                if (nv10_graph_ctx_regs[i] == reg)
                        return i;
        }
-       NV_ERROR(dev, "unknow offset nv10_ctx_regs %d\n", reg);
+       nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg);
        return -1;
 }
 
-static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
+static int
+nv17_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
 {
        int i;
        for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) {
                if (nv17_graph_ctx_regs[i] == reg)
                        return i;
        }
-       NV_ERROR(dev, "unknow offset nv17_ctx_regs %d\n", reg);
+       nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg);
        return -1;
 }
 
-static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
-                                      uint32_t inst)
+static void
+nv10_graph_load_dma_vtxbuf(struct nv10_graph_chan *chan, int chid, u32 inst)
 {
-       struct drm_device *dev = chan->dev;
-       uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
-       uint32_t ctx_user, ctx_switch[5];
+       struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+       u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
+       u32 ctx_user, ctx_switch[5];
        int i, subchan = -1;
 
        /* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
@@ -671,7 +879,7 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
 
        /* Look for a celsius object */
        for (i = 0; i < 8; i++) {
-               int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
+               int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
 
                if (class == 0x56 || class == 0x96 || class == 0x99) {
                        subchan = i;
@@ -683,168 +891,158 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
                return;
 
        /* Save the current ctx object */
-       ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
+       ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER);
        for (i = 0; i < 5; i++)
-               ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i));
+               ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i));
 
        /* Save the FIFO state */
-       st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
-       st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL);
-       st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH);
-       fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR);
+       st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2);
+       st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL);
+       st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH);
+       fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR);
 
        for (i = 0; i < ARRAY_SIZE(fifo); i++)
-               fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i);
+               fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i);
 
        /* Switch to the celsius subchannel */
        for (i = 0; i < 5; i++)
-               nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i),
-                       nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i)));
-       nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
+               nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i),
+                       nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i)));
+       nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
 
        /* Inject NV10TCL_DMA_VTXBUF */
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2,
-               0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
-       nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
-       nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-       nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+       nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
+       nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2,
+               0x2c000000 | chid << 20 | subchan << 16 | 0x18c);
+       nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
+       nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
+       nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+       nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
 
        /* Restore the FIFO state */
        for (i = 0; i < ARRAY_SIZE(fifo); i++)
-               nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]);
+               nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]);
 
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2);
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
+       nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
+       nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2);
+       nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
+       nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
 
        /* Restore the current ctx object */
        for (i = 0; i < 5; i++)
-               nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
-       nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
+               nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
+       nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user);
 }
 
 static int
-nv10_graph_load_context(struct nouveau_channel *chan)
+nv10_graph_load_context(struct nv10_graph_chan *chan, int chid)
 {
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
-       uint32_t tmp;
+       struct nv10_graph_priv *priv = nv10_graph_priv(chan);
+       u32 inst;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
-               nv_wr32(dev, nv10_graph_ctx_regs[i], pgraph_ctx->nv10[i]);
-       if (dev_priv->chipset >= 0x17) {
+               nv_wr32(priv, nv10_graph_ctx_regs[i], chan->nv10[i]);
+
+       if (nv_device(priv)->chipset >= 0x17) {
                for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
-                       nv_wr32(dev, nv17_graph_ctx_regs[i],
-                                               pgraph_ctx->nv17[i]);
+                       nv_wr32(priv, nv17_graph_ctx_regs[i], chan->nv17[i]);
        }
 
        nv10_graph_load_pipe(chan);
-       nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1)
-                                         & 0xffff));
-
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-       tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
-       nv_wr32(dev, NV10_PGRAPH_CTX_USER, (tmp & 0xffffff) | chan->id << 24);
-       tmp = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, tmp & 0xcfffffff);
+
+       inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff;
+       nv10_graph_load_dma_vtxbuf(chan, chid, inst);
+
+       nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+       nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+       nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000);
        return 0;
 }
 
 static int
-nv10_graph_unload_context(struct drm_device *dev)
+nv10_graph_unload_context(struct nv10_graph_chan *chan)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_channel *chan;
-       struct graph_state *ctx;
-       uint32_t tmp;
+       struct nv10_graph_priv *priv = nv10_graph_priv(chan);
        int i;
 
-       chan = nv10_graph_channel(dev);
-       if (!chan)
-               return 0;
-       ctx = chan->engctx[NVOBJ_ENGINE_GR];
-
        for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
-               ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]);
+               chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]);
 
-       if (dev_priv->chipset >= 0x17) {
+       if (nv_device(priv)->chipset >= 0x17) {
                for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
-                       ctx->nv17[i] = nv_rd32(dev, nv17_graph_ctx_regs[i]);
+                       chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]);
        }
 
        nv10_graph_save_pipe(chan);
 
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-       tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-       tmp |= 31 << 24;
-       nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+       nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+       nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
        return 0;
 }
 
 static void
-nv10_graph_context_switch(struct drm_device *dev)
+nv10_graph_context_switch(struct nv10_graph_priv *priv)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_channel *chan = NULL;
+       struct nv10_graph_chan *prev = NULL;
+       struct nv10_graph_chan *next = NULL;
+       unsigned long flags;
        int chid;
 
-       nouveau_wait_for_idle(dev);
+       spin_lock_irqsave(&priv->lock, flags);
+       nv04_graph_idle(priv);
 
        /* If previous context is valid, we need to save it */
-       nv10_graph_unload_context(dev);
+       prev = nv10_graph_channel(priv);
+       if (prev)
+               nv10_graph_unload_context(prev);
+
+       /* load context for next channel */
+       chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
+       next = priv->chan[chid];
+       if (next)
+               nv10_graph_load_context(next, chid);
 
-       /* Load context for next channel */
-       chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
-       chan = dev_priv->channels.ptr[chid];
-       if (chan && chan->engctx[NVOBJ_ENGINE_GR])
-               nv10_graph_load_context(chan);
+       spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 #define NV_WRITE_CTX(reg, val) do { \
-       int offset = nv10_graph_ctx_regs_find_offset(dev, reg); \
+       int offset = nv10_graph_ctx_regs_find_offset(priv, reg); \
        if (offset > 0) \
-               pgraph_ctx->nv10[offset] = val; \
+               chan->nv10[offset] = val; \
        } while (0)
 
 #define NV17_WRITE_CTX(reg, val) do { \
-       int offset = nv17_graph_ctx_regs_find_offset(dev, reg); \
+       int offset = nv17_graph_ctx_regs_find_offset(priv, reg); \
        if (offset > 0) \
-               pgraph_ctx->nv17[offset] = val; \
+               chan->nv17[offset] = val; \
        } while (0)
 
-struct nouveau_channel *
-nv10_graph_channel(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int chid = 31;
-
-       if (nv_rd32(dev, NV10_PGRAPH_CTX_CONTROL) & 0x00010000)
-               chid = nv_rd32(dev, NV10_PGRAPH_CTX_USER) >> 24;
-
-       if (chid >= 31)
-               return NULL;
-
-       return dev_priv->channels.ptr[chid];
-}
-
 static int
-nv10_graph_context_new(struct nouveau_channel *chan, int engine)
+nv10_graph_context_ctor(struct nouveau_object *parent,
+                       struct nouveau_object *engine,
+                       struct nouveau_oclass *oclass, void *data, u32 size,
+                       struct nouveau_object **pobject)
 {
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct graph_state *pgraph_ctx;
-
-       NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id);
-
-       pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
-       if (pgraph_ctx == NULL)
-               return -ENOMEM;
-       chan->engctx[engine] = pgraph_ctx;
+       struct nouveau_fifo_chan *fifo = (void *)parent;
+       struct nv10_graph_priv *priv = (void *)engine;
+       struct nv10_graph_chan *chan;
+       unsigned long flags;
+       int ret;
+
+       ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
+       *pobject = nv_object(chan);
+       if (ret)
+               return ret;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (priv->chan[fifo->chid]) {
+               *pobject = nv_object(priv->chan[fifo->chid]);
+               atomic_inc(&(*pobject)->refcount);
+               spin_unlock_irqrestore(&priv->lock, flags);
+               nouveau_object_destroy(&chan->base);
+               return 1;
+       }
 
        NV_WRITE_CTX(0x00400e88, 0x08000000);
        NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
@@ -853,212 +1051,91 @@ nv10_graph_context_new(struct nouveau_channel *chan, int engine)
        NV_WRITE_CTX(0x00400e14, 0x00001000);
        NV_WRITE_CTX(0x00400e30, 0x00080008);
        NV_WRITE_CTX(0x00400e34, 0x00080008);
-       if (dev_priv->chipset >= 0x17) {
+       if (nv_device(priv)->chipset >= 0x17) {
                /* is it really needed ??? */
                NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
-                                       nv_rd32(dev, NV10_PGRAPH_DEBUG_4));
-               NV17_WRITE_CTX(0x004006b0, nv_rd32(dev, 0x004006b0));
+                                       nv_rd32(priv, NV10_PGRAPH_DEBUG_4));
+               NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0));
                NV17_WRITE_CTX(0x00400eac, 0x0fff0000);
                NV17_WRITE_CTX(0x00400eb0, 0x0fff0000);
                NV17_WRITE_CTX(0x00400ec0, 0x00000080);
                NV17_WRITE_CTX(0x00400ed0, 0x00000080);
        }
-       NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->id << 24);
+       NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24);
 
        nv10_graph_create_pipe(chan);
+
+       priv->chan[fifo->chid] = chan;
+       chan->chid = fifo->chid;
+       spin_unlock_irqrestore(&priv->lock, flags);
        return 0;
 }
 
 static void
-nv10_graph_context_del(struct nouveau_channel *chan, int engine)
+nv10_graph_context_dtor(struct nouveau_object *object)
 {
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct graph_state *pgraph_ctx = chan->engctx[engine];
+       struct nv10_graph_priv *priv = (void *)object->engine;
+       struct nv10_graph_chan *chan = (void *)object;
        unsigned long flags;
 
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-
-       /* Unload the context if it's the currently active one */
-       if (nv10_graph_channel(dev) == chan)
-               nv10_graph_unload_context(dev);
+       spin_lock_irqsave(&priv->lock, flags);
+       priv->chan[chan->chid] = NULL;
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-       nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-       /* Free the context resources */
-       chan->engctx[engine] = NULL;
-       kfree(pgraph_ctx);
-}
-
-static void
-nv10_graph_set_tile_region(struct drm_device *dev, int i)
-{
-       struct nouveau_fb_tile *tile = nvfb_tile(dev, i);
-       nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), tile->limit);
-       nv_wr32(dev, NV10_PGRAPH_TSIZE(i), tile->pitch);
-       nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
+       nouveau_object_destroy(&chan->base);
 }
 
 static int
-nv10_graph_init(struct drm_device *dev, int engine)
+nv10_graph_context_fini(struct nouveau_object *object, bool suspend)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       u32 tmp;
-       int i;
-
-       nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
-                       ~NV_PMC_ENABLE_PGRAPH);
-       nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
-                        NV_PMC_ENABLE_PGRAPH);
-
-       nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
-       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
-       nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
-       nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x00000000);
-       nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x00118700);
-       /* nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
-       nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
-       nv_wr32(dev, NV04_PGRAPH_DEBUG_3, 0x55DE0830 |
-                                     (1<<29) |
-                                     (1<<31));
-       if (dev_priv->chipset >= 0x17) {
-               nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x1f000000);
-               nv_wr32(dev, 0x400a10, 0x3ff3fb6);
-               nv_wr32(dev, 0x400838, 0x2f8684);
-               nv_wr32(dev, 0x40083c, 0x115f3f);
-               nv_wr32(dev, 0x004006b0, 0x40000020);
-       } else
-               nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
+       struct nv10_graph_priv *priv = (void *)object->engine;
+       struct nv10_graph_chan *chan = (void *)object;
+       unsigned long flags;
 
-       /* Turn all the tiling regions off. */
-       for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
-               nv10_graph_set_tile_region(dev, i);
-
-       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF);
-
-       tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-       tmp |= 31 << 24;
-       nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
-       nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
+       spin_lock_irqsave(&priv->lock, flags);
+       nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+       if (nv10_graph_channel(priv) == chan)
+               nv10_graph_unload_context(chan);
+       nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
-       return 0;
+       return nouveau_object_fini(&chan->base, suspend);
 }
 
-static int
-nv10_graph_fini(struct drm_device *dev, int engine, bool suspend)
-{
-       nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-       if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) {
-               nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
-               return -EBUSY;
-       }
-       nv10_graph_unload_context(dev);
-       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       return 0;
-}
-
-static int
-nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
-                          u32 class, u32 mthd, u32 data)
-{
-       struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR];
-       struct drm_device *dev = chan->dev;
-       struct pipe_state *pipe = &ctx->pipe_state;
-       uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
-       uint32_t xfmode0, xfmode1;
-       int i;
-
-       ctx->lma_window[(mthd - 0x1638) / 4] = data;
-
-       if (mthd != 0x1644)
-               return 0;
-
-       nouveau_wait_for_idle(dev);
-
-       PIPE_SAVE(dev, pipe_0x0040, 0x0040);
-       PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
-
-       PIPE_RESTORE(dev, ctx->lma_window, 0x6790);
-
-       nouveau_wait_for_idle(dev);
-
-       xfmode0 = nv_rd32(dev, NV10_PGRAPH_XFMODE0);
-       xfmode1 = nv_rd32(dev, NV10_PGRAPH_XFMODE1);
-
-       PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
-       PIPE_SAVE(dev, pipe_0x64c0, 0x64c0);
-       PIPE_SAVE(dev, pipe_0x6ab0, 0x6ab0);
-       PIPE_SAVE(dev, pipe_0x6a80, 0x6a80);
-
-       nouveau_wait_for_idle(dev);
-
-       nv_wr32(dev, NV10_PGRAPH_XFMODE0, 0x10000000);
-       nv_wr32(dev, NV10_PGRAPH_XFMODE1, 0x00000000);
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
-       for (i = 0; i < 4; i++)
-               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-       for (i = 0; i < 4; i++)
-               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
-       for (i = 0; i < 3; i++)
-               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
-       for (i = 0; i < 3; i++)
-               nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
-       nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000008);
-
-       PIPE_RESTORE(dev, pipe->pipe_0x0200, 0x0200);
-
-       nouveau_wait_for_idle(dev);
-
-       PIPE_RESTORE(dev, pipe_0x0040, 0x0040);
-
-       nv_wr32(dev, NV10_PGRAPH_XFMODE0, xfmode0);
-       nv_wr32(dev, NV10_PGRAPH_XFMODE1, xfmode1);
-
-       PIPE_RESTORE(dev, pipe_0x64c0, 0x64c0);
-       PIPE_RESTORE(dev, pipe_0x6ab0, 0x6ab0);
-       PIPE_RESTORE(dev, pipe_0x6a80, 0x6a80);
-       PIPE_RESTORE(dev, pipe->pipe_0x4400, 0x4400);
-
-       nv_wr32(dev, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
-       nv_wr32(dev, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
-       nouveau_wait_for_idle(dev);
+static struct nouveau_oclass
+nv10_graph_cclass = {
+       .handle = NV_ENGCTX(GR, 0x10),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv10_graph_context_ctor,
+               .dtor = nv10_graph_context_dtor,
+               .init = nouveau_object_init,
+               .fini = nv10_graph_context_fini,
+       },
+};
 
-       return 0;
-}
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
 
-static int
-nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
-                          u32 class, u32 mthd, u32 data)
+static void
+nv10_graph_tile_prog(struct nouveau_engine *engine, int i)
 {
-       struct drm_device *dev = chan->dev;
+       struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
+       struct nouveau_fifo *pfifo = nouveau_fifo(engine);
+       struct nv10_graph_priv *priv = (void *)engine;
+       unsigned long flags;
 
-       nouveau_wait_for_idle(dev);
+       pfifo->pause(pfifo, &flags);
+       nv04_graph_idle(priv);
 
-       nv_wr32(dev, NV10_PGRAPH_DEBUG_4,
-               nv_rd32(dev, NV10_PGRAPH_DEBUG_4) | 0x1 << 8);
-       nv_wr32(dev, 0x004006b0,
-               nv_rd32(dev, 0x004006b0) | 0x8 << 24);
+       nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit);
+       nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch);
+       nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr);
 
-       return 0;
+       pfifo->start(pfifo, &flags);
 }
 
-struct nouveau_bitfield nv10_graph_intr[] = {
+struct nouveau_bitfield nv10_graph_intr_name[] = {
        { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
        { NV_PGRAPH_INTR_ERROR,  "ERROR"  },
        {}
@@ -1073,115 +1150,165 @@ struct nouveau_bitfield nv10_graph_nstatus[] = {
 };
 
 static void
-nv10_graph_isr(struct drm_device *dev)
+nv10_graph_intr(struct nouveau_subdev *subdev)
 {
-       u32 stat;
-
-       while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-               u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-               u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-               u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-               u32 chid = (addr & 0x01f00000) >> 20;
-               u32 subc = (addr & 0x00070000) >> 16;
-               u32 mthd = (addr & 0x00001ffc);
-               u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-               u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff;
-               u32 show = stat;
-
-               if (stat & NV_PGRAPH_INTR_ERROR) {
-                       if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-                               if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-                                       show &= ~NV_PGRAPH_INTR_ERROR;
-                       }
-               }
+       struct nv10_graph_priv *priv = (void *)subdev;
+       struct nv10_graph_chan *chan = NULL;
+       struct nouveau_namedb *namedb = NULL;
+       struct nouveau_handle *handle = NULL;
+       u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+       u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+       u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+       u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+       u32 chid = (addr & 0x01f00000) >> 20;
+       u32 subc = (addr & 0x00070000) >> 16;
+       u32 mthd = (addr & 0x00001ffc);
+       u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+       u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+       u32 show = stat;
+       unsigned long flags;
 
-               if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-                       nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-                       stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-                       show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-                       nv10_graph_context_switch(dev);
+       spin_lock_irqsave(&priv->lock, flags);
+       chan = priv->chan[chid];
+       if (chan)
+               namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       if (stat & NV_PGRAPH_INTR_ERROR) {
+               if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+                       handle = nouveau_namedb_get_class(namedb, class);
+                       if (handle && !nv_call(handle->object, mthd, data))
+                               show &= ~NV_PGRAPH_INTR_ERROR;
                }
+       }
 
-               nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-               nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-               if (show && nouveau_ratelimit()) {
-                       NV_INFO(dev, "PGRAPH -");
-                       nouveau_bitfield_print(nv10_graph_intr, show);
-                       printk(" nsource:");
-                       nouveau_bitfield_print(nv04_graph_nsource, nsource);
-                       printk(" nstatus:");
-                       nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
-                       printk("\n");
-                       NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-                                    "mthd 0x%04x data 0x%08x\n",
-                               chid, subc, class, mthd, data);
-               }
+       if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+               nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+               stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+               show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+               nv10_graph_context_switch(priv);
+       }
+
+       nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+       nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+       if (show) {
+               nv_error(priv, "");
+               nouveau_bitfield_print(nv10_graph_intr_name, show);
+               printk(" nsource:");
+               nouveau_bitfield_print(nv04_graph_nsource, nsource);
+               printk(" nstatus:");
+               nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
+               printk("\n");
+               nv_error(priv, "ch %d/%d class 0x%04x "
+                              "mthd 0x%04x data 0x%08x\n",
+                        chid, subc, class, mthd, data);
        }
+
+       nouveau_namedb_put(handle);
 }
 
-static void
-nv10_graph_destroy(struct drm_device *dev, int engine)
+static int
+nv10_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+               struct nouveau_oclass *oclass, void *data, u32 size,
+               struct nouveau_object **pobject)
 {
-       struct nv10_graph_engine *pgraph = nv_engine(dev, engine);
+       struct nv10_graph_priv *priv;
+       int ret;
+
+       ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       nv_subdev(priv)->unit = 0x00001000;
+       nv_subdev(priv)->intr = nv10_graph_intr;
+       nv_engine(priv)->cclass = &nv10_graph_cclass;
+
+       if (nv_device(priv)->chipset <= 0x10)
+               nv_engine(priv)->sclass = nv10_graph_sclass;
+       else
+       if (nv_device(priv)->chipset <  0x17 ||
+           nv_device(priv)->chipset == 0x1a)
+               nv_engine(priv)->sclass = nv15_graph_sclass;
+       else
+               nv_engine(priv)->sclass = nv17_graph_sclass;
+
+       nv_engine(priv)->tile_prog = nv10_graph_tile_prog;
+       spin_lock_init(&priv->lock);
+       return 0;
+}
 
-       nouveau_irq_unregister(dev, 12);
-       kfree(pgraph);
+static void
+nv10_graph_dtor(struct nouveau_object *object)
+{
+       struct nv10_graph_priv *priv = (void *)object;
+       nouveau_graph_destroy(&priv->base);
 }
 
-int
-nv10_graph_create(struct drm_device *dev)
+static int
+nv10_graph_init(struct nouveau_object *object)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nv10_graph_engine *pgraph;
-
-       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
-       if (!pgraph)
-               return -ENOMEM;
-
-       pgraph->base.destroy = nv10_graph_destroy;
-       pgraph->base.init = nv10_graph_init;
-       pgraph->base.fini = nv10_graph_fini;
-       pgraph->base.context_new = nv10_graph_context_new;
-       pgraph->base.context_del = nv10_graph_context_del;
-       pgraph->base.object_new = nv04_graph_object_new;
-       pgraph->base.set_tile_region = nv10_graph_set_tile_region;
-
-       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
-       nouveau_irq_register(dev, 12, nv10_graph_isr);
-
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
-       NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
-       NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
-       NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
-
-       /* celcius */
-       if (dev_priv->chipset <= 0x10) {
-               NVOBJ_CLASS(dev, 0x0056, GR);
-       } else
-       if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
-               NVOBJ_CLASS(dev, 0x0096, GR);
+       struct nouveau_engine *engine = nv_engine(object);
+       struct nouveau_fb *pfb = nouveau_fb(object);
+       struct nv10_graph_priv *priv = (void *)engine;
+       int ret, i;
+
+       ret = nouveau_graph_init(&priv->base);
+       if (ret)
+               return ret;
+
+       nv_wr32(priv, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
+       nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+       nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+       nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+       nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+       /* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
+       nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
+       nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
+
+       if (nv_device(priv)->chipset >= 0x17) {
+               nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000);
+               nv_wr32(priv, 0x400a10, 0x03ff3fb6);
+               nv_wr32(priv, 0x400838, 0x002f8684);
+               nv_wr32(priv, 0x40083c, 0x00115f3f);
+               nv_wr32(priv, 0x4006b0, 0x40000020);
        } else {
-               NVOBJ_CLASS(dev, 0x0099, GR);
-               NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+               nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
        }
 
+       /* Turn all the tiling regions off. */
+       for (i = 0; i < pfb->tile.regions; i++)
+               engine->tile_prog(engine, i);
+
+       nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
+       nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
+       nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
+       nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
+       nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
+       nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF);
+
+       nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
+       nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+       nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
        return 0;
 }
+
+static int
+nv10_graph_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nv10_graph_priv *priv = (void *)object;
+       return nouveau_graph_fini(&priv->base, suspend);
+}
+
+struct nouveau_oclass
+nv10_graph_oclass = {
+       .handle = NV_ENGINE(GR, 0x10),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv10_graph_ctor,
+               .dtor = nv10_graph_dtor,
+               .init = nv10_graph_init,
+               .fini = nv10_graph_fini,
+       },
+};