drm/nouveau: Pre-G80 tiling support.
authorFrancisco Jerez <currojerez@riseup.net>
Wed, 16 Dec 2009 11:12:27 +0000 (12:12 +0100)
committerBen Skeggs <bskeggs@redhat.com>
Sun, 10 Jan 2010 22:47:56 +0000 (08:47 +1000)
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv10_fb.c
drivers/gpu/drm/nouveau/nv10_graph.c
drivers/gpu/drm/nouveau/nv20_graph.c
drivers/gpu/drm/nouveau/nv40_fb.c
drivers/gpu/drm/nouveau/nv40_graph.c

index 48d0ad9434a80371f43317a8a1c30ecb54126156..446a92ad2eef54ed5970fb344c2492a1c8293dbe 100644 (file)
@@ -277,8 +277,13 @@ struct nouveau_timer_engine {
 };
 
 struct nouveau_fb_engine {
+       int num_tiles;
+
        int  (*init)(struct drm_device *dev);
        void (*takedown)(struct drm_device *dev);
+
+       void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
+                                uint32_t size, uint32_t pitch);
 };
 
 struct nouveau_fifo_engine {
@@ -332,6 +337,9 @@ struct nouveau_pgraph_engine {
        void (*destroy_context)(struct nouveau_channel *);
        int  (*load_context)(struct nouveau_channel *);
        int  (*unload_context)(struct drm_device *);
+
+       void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
+                                 uint32_t size, uint32_t pitch);
 };
 
 struct nouveau_engine {
@@ -881,10 +889,14 @@ extern void nv04_fb_takedown(struct drm_device *);
 /* nv10_fb.c */
 extern int  nv10_fb_init(struct drm_device *);
 extern void nv10_fb_takedown(struct drm_device *);
+extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t,
+                                     uint32_t, uint32_t);
 
 /* nv40_fb.c */
 extern int  nv40_fb_init(struct drm_device *);
 extern void nv40_fb_takedown(struct drm_device *);
+extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
+                                     uint32_t, uint32_t);
 
 /* nv04_fifo.c */
 extern int  nv04_fifo_init(struct drm_device *);
@@ -945,6 +957,8 @@ extern void nv10_graph_destroy_context(struct nouveau_channel *);
 extern int  nv10_graph_load_context(struct nouveau_channel *);
 extern int  nv10_graph_unload_context(struct drm_device *);
 extern void nv10_graph_context_switch(struct drm_device *);
+extern void nv10_graph_set_region_tiling(struct drm_device *, int, uint32_t,
+                                        uint32_t, uint32_t);
 
 /* nv20_graph.c */
 extern struct nouveau_pgraph_object_class nv20_graph_grclass[];
@@ -956,6 +970,8 @@ extern int  nv20_graph_unload_context(struct drm_device *);
 extern int  nv20_graph_init(struct drm_device *);
 extern void nv20_graph_takedown(struct drm_device *);
 extern int  nv30_graph_init(struct drm_device *);
+extern void nv20_graph_set_region_tiling(struct drm_device *, int, uint32_t,
+                                        uint32_t, uint32_t);
 
 /* nv40_graph.c */
 extern struct nouveau_pgraph_object_class nv40_graph_grclass[];
@@ -967,6 +983,8 @@ extern void nv40_graph_destroy_context(struct nouveau_channel *);
 extern int  nv40_graph_load_context(struct nouveau_channel *);
 extern int  nv40_graph_unload_context(struct drm_device *);
 extern void nv40_grctx_init(struct nouveau_grctx *);
+extern void nv40_graph_set_region_tiling(struct drm_device *, int, uint32_t,
+                                        uint32_t, uint32_t);
 
 /* nv50_graph.c */
 extern struct nouveau_pgraph_object_class nv50_graph_grclass[];
index fa1b0e7165b9956ea3581c378ba61f13c75afb36..251f1b3b38b927e73a0cef903c913109224d8172 100644 (file)
 #define NV04_PGRAPH_BLEND                                  0x00400824
 #define NV04_PGRAPH_STORED_FMT                             0x00400830
 #define NV04_PGRAPH_PATT_COLORRAM                          0x00400900
-#define NV40_PGRAPH_TILE0(i)                               (0x00400900 + (i*16))
-#define NV40_PGRAPH_TLIMIT0(i)                             (0x00400904 + (i*16))
-#define NV40_PGRAPH_TSIZE0(i)                              (0x00400908 + (i*16))
-#define NV40_PGRAPH_TSTATUS0(i)                            (0x0040090C + (i*16))
+#define NV20_PGRAPH_TILE(i)                                (0x00400900 + (i*16))
+#define NV20_PGRAPH_TLIMIT(i)                              (0x00400904 + (i*16))
+#define NV20_PGRAPH_TSIZE(i)                               (0x00400908 + (i*16))
+#define NV20_PGRAPH_TSTATUS(i)                             (0x0040090C + (i*16))
 #define NV10_PGRAPH_TILE(i)                                (0x00400B00 + (i*16))
 #define NV10_PGRAPH_TLIMIT(i)                              (0x00400B04 + (i*16))
 #define NV10_PGRAPH_TSIZE(i)                               (0x00400B08 + (i*16))
 #define NV10_PGRAPH_TSTATUS(i)                             (0x00400B0C + (i*16))
 #define NV04_PGRAPH_U_RAM                                  0x00400D00
-#define NV47_PGRAPH_TILE0(i)                               (0x00400D00 + (i*16))
-#define NV47_PGRAPH_TLIMIT0(i)                             (0x00400D04 + (i*16))
-#define NV47_PGRAPH_TSIZE0(i)                              (0x00400D08 + (i*16))
-#define NV47_PGRAPH_TSTATUS0(i)                            (0x00400D0C + (i*16))
+#define NV47_PGRAPH_TILE(i)                                (0x00400D00 + (i*16))
+#define NV47_PGRAPH_TLIMIT(i)                              (0x00400D04 + (i*16))
+#define NV47_PGRAPH_TSIZE(i)                               (0x00400D08 + (i*16))
+#define NV47_PGRAPH_TSTATUS(i)                             (0x00400D0C + (i*16))
 #define NV04_PGRAPH_V_RAM                                  0x00400D40
 #define NV04_PGRAPH_W_RAM                                  0x00400D80
 #define NV10_PGRAPH_COMBINER0_IN_ALPHA                     0x00400E40
index 9f988431f34c8313748066e297dc3ce09d3e9ceb..6a459139910f6976eb75fcf38602023adebde8dc 100644 (file)
@@ -102,6 +102,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv10_fb_init;
                engine->fb.takedown             = nv10_fb_takedown;
+               engine->fb.set_region_tiling    = nv10_fb_set_region_tiling;
                engine->graph.grclass           = nv10_graph_grclass;
                engine->graph.init              = nv10_graph_init;
                engine->graph.takedown          = nv10_graph_takedown;
@@ -111,6 +112,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->graph.fifo_access       = nv04_graph_fifo_access;
                engine->graph.load_context      = nv10_graph_load_context;
                engine->graph.unload_context    = nv10_graph_unload_context;
+               engine->graph.set_region_tiling = nv10_graph_set_region_tiling;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nouveau_stub_takedown;
@@ -143,6 +145,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv10_fb_init;
                engine->fb.takedown             = nv10_fb_takedown;
+               engine->fb.set_region_tiling    = nv10_fb_set_region_tiling;
                engine->graph.grclass           = nv20_graph_grclass;
                engine->graph.init              = nv20_graph_init;
                engine->graph.takedown          = nv20_graph_takedown;
@@ -152,6 +155,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->graph.fifo_access       = nv04_graph_fifo_access;
                engine->graph.load_context      = nv20_graph_load_context;
                engine->graph.unload_context    = nv20_graph_unload_context;
+               engine->graph.set_region_tiling = nv20_graph_set_region_tiling;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nouveau_stub_takedown;
@@ -184,6 +188,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv10_fb_init;
                engine->fb.takedown             = nv10_fb_takedown;
+               engine->fb.set_region_tiling    = nv10_fb_set_region_tiling;
                engine->graph.grclass           = nv30_graph_grclass;
                engine->graph.init              = nv30_graph_init;
                engine->graph.takedown          = nv20_graph_takedown;
@@ -193,6 +198,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->graph.destroy_context   = nv20_graph_destroy_context;
                engine->graph.load_context      = nv20_graph_load_context;
                engine->graph.unload_context    = nv20_graph_unload_context;
+               engine->graph.set_region_tiling = nv20_graph_set_region_tiling;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nouveau_stub_takedown;
@@ -226,6 +232,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv40_fb_init;
                engine->fb.takedown             = nv40_fb_takedown;
+               engine->fb.set_region_tiling    = nv40_fb_set_region_tiling;
                engine->graph.grclass           = nv40_graph_grclass;
                engine->graph.init              = nv40_graph_init;
                engine->graph.takedown          = nv40_graph_takedown;
@@ -235,6 +242,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->graph.destroy_context   = nv40_graph_destroy_context;
                engine->graph.load_context      = nv40_graph_load_context;
                engine->graph.unload_context    = nv40_graph_unload_context;
+               engine->graph.set_region_tiling = nv40_graph_set_region_tiling;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv40_fifo_init;
                engine->fifo.takedown           = nouveau_stub_takedown;
index 79e2d104d70a0176bffa23d46b25ff68749d8265..cc5cda44e5018bfd7bc0a777fd88f8a94e33794a 100644 (file)
@@ -3,17 +3,37 @@
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
 
+void
+nv10_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
+                         uint32_t size, uint32_t pitch)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t limit = max(1u, addr + size) - 1;
+
+       if (pitch) {
+               if (dev_priv->card_type >= NV_20)
+                       addr |= 1;
+               else
+                       addr |= 1 << 31;
+       }
+
+       nv_wr32(dev, NV10_PFB_TLIMIT(i), limit);
+       nv_wr32(dev, NV10_PFB_TSIZE(i), pitch);
+       nv_wr32(dev, NV10_PFB_TILE(i), addr);
+}
+
 int
 nv10_fb_init(struct drm_device *dev)
 {
-       uint32_t fb_bar_size;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
        int i;
 
-       fb_bar_size = drm_get_resource_len(dev, 0) - 1;
-       for (i = 0; i < NV10_PFB_TILE__SIZE; i++) {
-               nv_wr32(dev, NV10_PFB_TILE(i), 0);
-               nv_wr32(dev, NV10_PFB_TLIMIT(i), fb_bar_size);
-       }
+       pfb->num_tiles = NV10_PFB_TILE__SIZE;
+
+       /* Turn all the tiling regions off. */
+       for (i = 0; i < pfb->num_tiles; i++)
+               pfb->set_region_tiling(dev, i, 0, 0, 0);
 
        return 0;
 }
index 6870e0ee2e7e315b85c12342f84f5c2732705fa8..fcf2cdd19493bf55dbff29699af17bb40708b70d 100644 (file)
@@ -807,6 +807,20 @@ void nv10_graph_destroy_context(struct nouveau_channel *chan)
        chan->pgraph_ctx = NULL;
 }
 
+void
+nv10_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
+                            uint32_t size, uint32_t pitch)
+{
+       uint32_t limit = max(1u, addr + size) - 1;
+
+       if (pitch)
+               addr |= 1 << 31;
+
+       nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), limit);
+       nv_wr32(dev, NV10_PGRAPH_TSIZE(i), pitch);
+       nv_wr32(dev, NV10_PGRAPH_TILE(i), addr);
+}
+
 int nv10_graph_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -838,17 +852,9 @@ int nv10_graph_init(struct drm_device *dev)
        } else
                nv_wr32(dev, NV10_PGRAPH_DEBUG_4, 0x00000000);
 
-       /* copy tile info from PFB */
-       for (i = 0; i < NV10_PFB_TILE__SIZE; i++) {
-               nv_wr32(dev, NV10_PGRAPH_TILE(i),
-                                       nv_rd32(dev, NV10_PFB_TILE(i)));
-               nv_wr32(dev, NV10_PGRAPH_TLIMIT(i),
-                                       nv_rd32(dev, NV10_PFB_TLIMIT(i)));
-               nv_wr32(dev, NV10_PGRAPH_TSIZE(i),
-                                       nv_rd32(dev, NV10_PFB_TSIZE(i)));
-               nv_wr32(dev, NV10_PGRAPH_TSTATUS(i),
-                                       nv_rd32(dev, NV10_PFB_TSTATUS(i)));
-       }
+       /* Turn all the tiling regions off. */
+       for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
+               nv10_graph_set_region_tiling(dev, i, 0, 0, 0);
 
        nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH1, 0x00000000);
        nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH2, 0x00000000);
index 18ba74f19703f15100df2da20629b6e0b2523740..d6fc0a82f03dd20ea8b7c21da48d75c98ebb0ad9 100644 (file)
@@ -514,6 +514,27 @@ nv20_graph_rdi(struct drm_device *dev)
        nouveau_wait_for_idle(dev);
 }
 
+void
+nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
+                            uint32_t size, uint32_t pitch)
+{
+       uint32_t limit = max(1u, addr + size) - 1;
+
+       if (pitch)
+               addr |= 1;
+
+       nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit);
+       nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch);
+       nv_wr32(dev, NV20_PGRAPH_TILE(i), addr);
+
+       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
+       nv_wr32(dev, NV10_PGRAPH_RDI_DATA, limit);
+       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
+       nv_wr32(dev, NV10_PGRAPH_RDI_DATA, pitch);
+       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
+       nv_wr32(dev, NV10_PGRAPH_RDI_DATA, addr);
+}
+
 int
 nv20_graph_init(struct drm_device *dev)
 {
@@ -572,27 +593,10 @@ nv20_graph_init(struct drm_device *dev)
                nv_wr32(dev, NV10_PGRAPH_RDI_DATA , 0x00000030);
        }
 
-       /* copy tile info from PFB */
-       for (i = 0; i < NV10_PFB_TILE__SIZE; i++) {
-               nv_wr32(dev, 0x00400904 + i * 0x10,
-                                       nv_rd32(dev, NV10_PFB_TLIMIT(i)));
-                       /* which is NV40_PGRAPH_TLIMIT0(i) ?? */
-               nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + i * 4);
-               nv_wr32(dev, NV10_PGRAPH_RDI_DATA,
-                                       nv_rd32(dev, NV10_PFB_TLIMIT(i)));
-               nv_wr32(dev, 0x00400908 + i * 0x10,
-                                       nv_rd32(dev, NV10_PFB_TSIZE(i)));
-                       /* which is NV40_PGRAPH_TSIZE0(i) ?? */
-               nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + i * 4);
-               nv_wr32(dev, NV10_PGRAPH_RDI_DATA,
-                                       nv_rd32(dev, NV10_PFB_TSIZE(i)));
-               nv_wr32(dev, 0x00400900 + i * 0x10,
-                                       nv_rd32(dev, NV10_PFB_TILE(i)));
-                       /* which is NV40_PGRAPH_TILE0(i) ?? */
-               nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + i * 4);
-               nv_wr32(dev, NV10_PGRAPH_RDI_DATA,
-                                       nv_rd32(dev, NV10_PFB_TILE(i)));
-       }
+       /* Turn all the tiling regions off. */
+       for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
+               nv20_graph_set_region_tiling(dev, i, 0, 0, 0);
+
        for (i = 0; i < 8; i++) {
                nv_wr32(dev, 0x400980 + i * 4, nv_rd32(dev, 0x100300 + i * 4));
                nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0090 + i * 4);
@@ -704,18 +708,9 @@ nv30_graph_init(struct drm_device *dev)
 
        nv_wr32(dev, 0x4000c0, 0x00000016);
 
-       /* copy tile info from PFB */
-       for (i = 0; i < NV10_PFB_TILE__SIZE; i++) {
-               nv_wr32(dev, 0x00400904 + i * 0x10,
-                                       nv_rd32(dev, NV10_PFB_TLIMIT(i)));
-                       /* which is NV40_PGRAPH_TLIMIT0(i) ?? */
-               nv_wr32(dev, 0x00400908 + i * 0x10,
-                                       nv_rd32(dev, NV10_PFB_TSIZE(i)));
-                       /* which is NV40_PGRAPH_TSIZE0(i) ?? */
-               nv_wr32(dev, 0x00400900 + i * 0x10,
-                                       nv_rd32(dev, NV10_PFB_TILE(i)));
-                       /* which is NV40_PGRAPH_TILE0(i) ?? */
-       }
+       /* Turn all the tiling regions off. */
+       for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
+               nv20_graph_set_region_tiling(dev, i, 0, 0, 0);
 
        nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
        nv_wr32(dev, NV10_PGRAPH_STATE      , 0xFFFFFFFF);
index ca1d27107a8e4a5a2c097b26aa4882aebfd0b841..3cd07d8d5bd7a93c27f118dc5923991954a35d23 100644 (file)
@@ -3,12 +3,37 @@
 #include "nouveau_drv.h"
 #include "nouveau_drm.h"
 
+void
+nv40_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
+                         uint32_t size, uint32_t pitch)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t limit = max(1u, addr + size) - 1;
+
+       if (pitch)
+               addr |= 1;
+
+       switch (dev_priv->chipset) {
+       case 0x40:
+               nv_wr32(dev, NV10_PFB_TLIMIT(i), limit);
+               nv_wr32(dev, NV10_PFB_TSIZE(i), pitch);
+               nv_wr32(dev, NV10_PFB_TILE(i), addr);
+               break;
+
+       default:
+               nv_wr32(dev, NV40_PFB_TLIMIT(i), limit);
+               nv_wr32(dev, NV40_PFB_TSIZE(i), pitch);
+               nv_wr32(dev, NV40_PFB_TILE(i), addr);
+               break;
+       }
+}
+
 int
 nv40_fb_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t fb_bar_size, tmp;
-       int num_tiles;
+       struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+       uint32_t tmp;
        int i;
 
        /* This is strictly a NV4x register (don't know about NV5x). */
@@ -23,35 +48,23 @@ nv40_fb_init(struct drm_device *dev)
        case 0x45:
                tmp = nv_rd32(dev, NV10_PFB_CLOSE_PAGE2);
                nv_wr32(dev, NV10_PFB_CLOSE_PAGE2, tmp & ~(1 << 15));
-               num_tiles = NV10_PFB_TILE__SIZE;
+               pfb->num_tiles = NV10_PFB_TILE__SIZE;
                break;
        case 0x46: /* G72 */
        case 0x47: /* G70 */
        case 0x49: /* G71 */
        case 0x4b: /* G73 */
        case 0x4c: /* C51 (G7X version) */
-               num_tiles = NV40_PFB_TILE__SIZE_1;
+               pfb->num_tiles = NV40_PFB_TILE__SIZE_1;
                break;
        default:
-               num_tiles = NV40_PFB_TILE__SIZE_0;
+               pfb->num_tiles = NV40_PFB_TILE__SIZE_0;
                break;
        }
 
-       fb_bar_size = drm_get_resource_len(dev, 0) - 1;
-       switch (dev_priv->chipset) {
-       case 0x40:
-               for (i = 0; i < num_tiles; i++) {
-                       nv_wr32(dev, NV10_PFB_TILE(i), 0);
-                       nv_wr32(dev, NV10_PFB_TLIMIT(i), fb_bar_size);
-               }
-               break;
-       default:
-               for (i = 0; i < num_tiles; i++) {
-                       nv_wr32(dev, NV40_PFB_TILE(i), 0);
-                       nv_wr32(dev, NV40_PFB_TLIMIT(i), fb_bar_size);
-               }
-               break;
-       }
+       /* Turn all the tiling regions off. */
+       for (i = 0; i < pfb->num_tiles; i++)
+               pfb->set_region_tiling(dev, i, 0, 0, 0);
 
        return 0;
 }
index 2b332bb55acf75b4cce5bafb9dc5110538e47428..53e8afe1dcd1a0dc6fedf5fd9d819edc87e4b918 100644 (file)
@@ -181,6 +181,48 @@ nv40_graph_unload_context(struct drm_device *dev)
        return ret;
 }
 
+void
+nv40_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
+                            uint32_t size, uint32_t pitch)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t limit = max(1u, addr + size) - 1;
+
+       if (pitch)
+               addr |= 1;
+
+       switch (dev_priv->chipset) {
+       case 0x44:
+       case 0x4a:
+       case 0x4e:
+               nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch);
+               nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit);
+               nv_wr32(dev, NV20_PGRAPH_TILE(i), addr);
+               break;
+
+       case 0x46:
+       case 0x47:
+       case 0x49:
+       case 0x4b:
+               nv_wr32(dev, NV47_PGRAPH_TSIZE(i), pitch);
+               nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), limit);
+               nv_wr32(dev, NV47_PGRAPH_TILE(i), addr);
+               nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch);
+               nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit);
+               nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr);
+               break;
+
+       default:
+               nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch);
+               nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit);
+               nv_wr32(dev, NV20_PGRAPH_TILE(i), addr);
+               nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch);
+               nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit);
+               nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr);
+               break;
+       }
+}
+
 /*
  * G70         0x47
  * G71         0x49
@@ -195,7 +237,8 @@ nv40_graph_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv =
                (struct drm_nouveau_private *)dev->dev_private;
-       uint32_t vramsz, tmp;
+       struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
+       uint32_t vramsz;
        int i, j;
 
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
@@ -292,74 +335,9 @@ nv40_graph_init(struct drm_device *dev)
        nv_wr32(dev, 0x400b38, 0x2ffff800);
        nv_wr32(dev, 0x400b3c, 0x00006000);
 
-       /* copy tile info from PFB */
-       switch (dev_priv->chipset) {
-       case 0x40: /* vanilla NV40 */
-               for (i = 0; i < NV10_PFB_TILE__SIZE; i++) {
-                       tmp = nv_rd32(dev, NV10_PFB_TILE(i));
-                       nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp);
-                       tmp = nv_rd32(dev, NV10_PFB_TLIMIT(i));
-                       nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp);
-                       tmp = nv_rd32(dev, NV10_PFB_TSIZE(i));
-                       nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp);
-                       tmp = nv_rd32(dev, NV10_PFB_TSTATUS(i));
-                       nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp);
-               }
-               break;
-       case 0x44:
-       case 0x4a:
-       case 0x4e: /* NV44-based cores don't have 0x406900? */
-               for (i = 0; i < NV40_PFB_TILE__SIZE_0; i++) {
-                       tmp = nv_rd32(dev, NV40_PFB_TILE(i));
-                       nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i));
-                       nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TSIZE(i));
-                       nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i));
-                       nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp);
-               }
-               break;
-       case 0x46:
-       case 0x47:
-       case 0x49:
-       case 0x4b: /* G7X-based cores */
-               for (i = 0; i < NV40_PFB_TILE__SIZE_1; i++) {
-                       tmp = nv_rd32(dev, NV40_PFB_TILE(i));
-                       nv_wr32(dev, NV47_PGRAPH_TILE0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i));
-                       nv_wr32(dev, NV47_PGRAPH_TLIMIT0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TSIZE(i));
-                       nv_wr32(dev, NV47_PGRAPH_TSIZE0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i));
-                       nv_wr32(dev, NV47_PGRAPH_TSTATUS0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp);
-               }
-               break;
-       default: /* everything else */
-               for (i = 0; i < NV40_PFB_TILE__SIZE_0; i++) {
-                       tmp = nv_rd32(dev, NV40_PFB_TILE(i));
-                       nv_wr32(dev, NV40_PGRAPH_TILE0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TILE1(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TLIMIT(i));
-                       nv_wr32(dev, NV40_PGRAPH_TLIMIT0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TSIZE(i));
-                       nv_wr32(dev, NV40_PGRAPH_TSIZE0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tmp);
-                       tmp = nv_rd32(dev, NV40_PFB_TSTATUS(i));
-                       nv_wr32(dev, NV40_PGRAPH_TSTATUS0(i), tmp);
-                       nv_wr32(dev, NV40_PGRAPH_TSTATUS1(i), tmp);
-               }
-               break;
-       }
+       /* Turn all the tiling regions off. */
+       for (i = 0; i < pfb->num_tiles; i++)
+               nv40_graph_set_region_tiling(dev, i, 0, 0, 0);
 
        /* begin RAM config */
        vramsz = drm_get_resource_len(dev, 0) - 1;