nouveau: NV4X PFIFO engtab functions
authorBen Skeggs <skeggsb@gmail.com>
Sun, 24 Jun 2007 08:56:01 +0000 (18:56 +1000)
committerBen Skeggs <skeggsb@gmail.com>
Sun, 24 Jun 2007 08:56:01 +0000 (18:56 +1000)
linux-core/Makefile.kernel
linux-core/nv40_fifo.c [new symlink]
shared-core/nouveau_drv.h
shared-core/nouveau_fifo.c
shared-core/nouveau_reg.h
shared-core/nouveau_state.c
shared-core/nv40_fifo.c [new file with mode: 0644]

index 6f5b021..3e78b6d 100644 (file)
@@ -25,6 +25,7 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
                nv04_timer.o \
                nv04_mc.o nv40_mc.o \
                nv04_fb.o nv10_fb.o nv40_fb.o \
+               nv40_fifo.o \
                nv04_graph.o nv10_graph.o nv20_graph.o nv30_graph.o \
                nv40_graph.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
diff --git a/linux-core/nv40_fifo.c b/linux-core/nv40_fifo.c
new file mode 120000 (symlink)
index 0000000..cc71e7a
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/nv40_fifo.c
\ No newline at end of file
index da604d3..7c29a88 100644 (file)
@@ -100,7 +100,7 @@ struct nouveau_config {
        } cmdbuf;
 };
 
-struct nouveau_engine_func {
+typedef struct nouveau_engine_func {
        struct {
                int     (*init)(drm_device_t *dev);
                void    (*takedown)(drm_device_t *dev);
@@ -135,7 +135,7 @@ struct nouveau_engine_func {
                int     (*load_context)(drm_device_t *, int channel);
                int     (*save_context)(drm_device_t *, int channel);
        } fifo;
-};
+} nouveau_engine_func_t;
 
 typedef struct drm_nouveau_private {
        /* the card type, takes NV_* as values */
@@ -255,6 +255,12 @@ extern void nv10_fb_takedown(drm_device_t *dev);
 extern int  nv40_fb_init(drm_device_t *dev);
 extern void nv40_fb_takedown(drm_device_t *dev);
 
+/* nv40_fifo.c */
+extern int  nv40_fifo_create_context(drm_device_t *, int channel);
+extern void nv40_fifo_destroy_context(drm_device_t *, int channel);
+extern int  nv40_fifo_load_context(drm_device_t *, int channel);
+extern int  nv40_fifo_save_context(drm_device_t *, int channel);
+
 /* nv04_graph.c */
 extern void nouveau_nv04_context_switch(drm_device_t *dev);
 extern int nv04_graph_init(drm_device_t *dev);
index 5bbd1c0..50f094b 100644 (file)
@@ -358,64 +358,6 @@ static void nouveau_nv10_context_save(drm_device_t *dev)
 #endif
 #undef RAMFC_WR
 
-#define RAMFC_WR(offset, val) NV_WRITE(fifoctx + NV40_RAMFC_##offset, (val))
-static void nouveau_nv40_context_init(drm_device_t *dev, int channel)
-{
-       drm_nouveau_private_t *dev_priv = dev->dev_private;
-       struct nouveau_fifo *chan = &dev_priv->fifos[channel];
-       uint32_t fifoctx, cb_inst, grctx_inst;
-       int i;
-
-       cb_inst = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance);
-       grctx_inst = nouveau_chip_instance_get(dev, chan->ramin_grctx);
-       fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128;
-       for (i=0;i<128;i+=4)
-               NV_WRITE(fifoctx + i, 0);
-
-       /* Fill entries that are seen filled in dumps of nvidia driver just
-        * after channel's is put into DMA mode
-        */
-       RAMFC_WR(DMA_INSTANCE  , cb_inst);
-       RAMFC_WR(DMA_FETCH     , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
-                                NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-                                NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
-#ifdef __BIG_ENDIAN
-                                NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
-                                0x30000000 /* no idea.. */);
-       RAMFC_WR(GRCTX_INSTANCE, grctx_inst);
-       RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF);
-}
-
-static void nouveau_nv40_context_save(drm_device_t *dev)
-{
-       drm_nouveau_private_t *dev_priv = dev->dev_private;
-       uint32_t fifoctx;
-       int channel;
-
-       channel = NV_READ(NV03_PFIFO_CACHE1_PUSH1) & (nouveau_fifo_number(dev)-1);
-       fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128;
-
-       RAMFC_WR(DMA_PUT          , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT));
-       RAMFC_WR(DMA_GET          , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
-       RAMFC_WR(REF_CNT          , NV_READ(NV10_PFIFO_CACHE1_REF_CNT));
-       RAMFC_WR(DMA_INSTANCE     , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE));
-       RAMFC_WR(DMA_DCOUNT       , NV_READ(NV10_PFIFO_CACHE1_DMA_DCOUNT));
-       RAMFC_WR(DMA_STATE        , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE));
-       RAMFC_WR(DMA_FETCH        , NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH));
-       RAMFC_WR(ENGINE           , NV_READ(NV04_PFIFO_CACHE1_ENGINE));
-       RAMFC_WR(PULL1_ENGINE     , NV_READ(NV04_PFIFO_CACHE1_PULL1));
-       RAMFC_WR(ACQUIRE_VALUE    , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
-       RAMFC_WR(ACQUIRE_TIMESTAMP, NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP));
-       RAMFC_WR(ACQUIRE_TIMEOUT  , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
-       RAMFC_WR(SEMAPHORE        , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE));
-       RAMFC_WR(DMA_SUBROUTINE   , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
-       RAMFC_WR(GRCTX_INSTANCE   , NV_READ(NV40_PFIFO_GRCTX_INSTANCE));
-       RAMFC_WR(DMA_TIMESLICE    , NV_READ(NV04_PFIFO_DMA_TIMESLICE) & 0x1FFFF);
-       RAMFC_WR(UNK_40           , NV_READ(NV40_PFIFO_UNK32E4));
-}
-#undef RAMFC_WR
-
 /* This function should load values from RAMFC into PFIFO, but for now
  * it just clobbers PFIFO with what nouveau_fifo_alloc used to setup
  * unconditionally.
@@ -461,6 +403,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
 {
        int ret;
        drm_nouveau_private_t *dev_priv = dev->dev_private;
+       nouveau_engine_func_t *engine = &dev_priv->Engine;
        struct nouveau_fifo *chan;
        int channel;
 
@@ -560,14 +503,17 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
        case NV_30:
                nouveau_nv30_context_init(dev, channel);
                break;
-       case NV_40:
-       case NV_44:
-               nouveau_nv40_context_init(dev, channel);
-               break;
        default:
-               DRM_ERROR("fifoctx: unknown card type\n");
-               nouveau_fifo_free(dev, channel);
-               return DRM_ERR(EINVAL);
+               if (!engine->fifo.create_context) {
+                       DRM_ERROR("fifo.create_context == NULL\n");
+                       return DRM_ERR(EINVAL);
+               }
+
+               ret = engine->fifo.create_context(dev, channel);
+               if (ret) {
+                       nouveau_fifo_free(dev, channel);
+                       return ret;
+               }
        }
 
        /* enable the fifo dma operation */
@@ -581,7 +527,11 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
         * other case, the GPU will handle this when it switches contexts.
         */
        if (dev_priv->fifo_alloc_count == 0) {
-               nouveau_fifo_context_restore(dev, channel);
+               if (engine->fifo.load_context)
+                       engine->fifo.load_context(dev, channel);
+               else
+                       nouveau_fifo_context_restore(dev, channel);
+
                if (dev_priv->card_type >= NV_30) {
                        uint32_t inst;
 
@@ -615,6 +565,7 @@ static int nouveau_fifo_alloc(drm_device_t* dev, int *chan_ret, DRMFILE filp)
 void nouveau_fifo_free(drm_device_t* dev, int channel)
 {
        drm_nouveau_private_t *dev_priv = dev->dev_private;
+       nouveau_engine_func_t *engine = &dev_priv->Engine;
        struct nouveau_fifo *chan = &dev_priv->fifos[channel];
        int i;
        int ctx_size = nouveau_fifo_ctx_size(dev);
@@ -629,12 +580,17 @@ void nouveau_fifo_free(drm_device_t* dev, int channel)
        // FIXME XXX needs more code
        
        /* Clean RAMFC */
-       for (i=0;i<ctx_size;i+=4) {
-               DRM_DEBUG("RAMFC +%02x: 0x%08x\n", i, NV_READ(NV_RAMIN +
-                                       dev_priv->ramfc_offset + 
-                                       channel*ctx_size + i));
-               NV_WRITE(NV_RAMIN + dev_priv->ramfc_offset +
-                               channel*ctx_size + i, 0);
+       if (engine->fifo.destroy_context)
+               engine->fifo.destroy_context(dev, channel);
+       else {
+               for (i=0;i<ctx_size;i+=4) {
+                       DRM_DEBUG("RAMFC +%02x: 0x%08x\n",
+                                 i, NV_READ(NV_RAMIN +
+                                            dev_priv->ramfc_offset + 
+                                            channel*ctx_size + i));
+                       NV_WRITE(NV_RAMIN + dev_priv->ramfc_offset +
+                                       channel*ctx_size + i, 0);
+               }
        }
 
        /* Cleanup PGRAPH state */
index ea4a2f6..07c54a9 100644 (file)
 #define NV40_RAMFC_UNK_40                                        0x40
 #define NV40_RAMFC_UNK_44                                        0x44
 #define NV40_RAMFC_UNK_48                                        0x48
-#define NV40_RAMFC_2088                                          0x4C
-#define NV40_RAMFC_3300                                          0x50
+#define NV40_RAMFC_UNK_4C                                        0x4C
+#define NV40_RAMFC_UNK_50                                        0x50
 
index 592797c..42860e9 100644 (file)
@@ -138,6 +138,10 @@ static int nouveau_init_engine_ptrs(drm_device_t *dev)
                engine->graph.takedown  = nv40_graph_takedown;
                engine->fifo.init       = nouveau_fifo_init;
                engine->fifo.takedown   = nouveau_stub_takedown;
+               engine->fifo.create_context     = nv40_fifo_create_context;
+               engine->fifo.destroy_context    = nv40_fifo_destroy_context;
+               engine->fifo.load_context       = nv40_fifo_load_context;
+               engine->fifo.save_context       = nv40_fifo_save_context;
                break;
        case 0x50:
        default:
diff --git a/shared-core/nv40_fifo.c b/shared-core/nv40_fifo.c
new file mode 100644 (file)
index 0000000..b67a7e5
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007 Ben Skeggs.
+ * 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 paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+
+#define RAMFC_WR(offset, val)  NV_WRITE(fifoctx + NV40_RAMFC_##offset, (val))
+#define RAMFC_RD(offset)       NV_READ (fifoctx + NV40_RAMFC_##offset)
+
+int
+nv40_fifo_create_context(drm_device_t *dev, int channel)
+{
+       drm_nouveau_private_t *dev_priv = dev->dev_private;
+       struct nouveau_fifo *chan = &dev_priv->fifos[channel];
+       uint32_t fifoctx, grctx, pushbuf;
+       int i;
+
+       fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128;
+       for (i=0;i<128;i+=4)
+               NV_WRITE(fifoctx + i, 0);
+
+       grctx   = nouveau_chip_instance_get(dev, chan->ramin_grctx);
+       pushbuf = nouveau_chip_instance_get(dev, chan->cmdbuf_obj->instance);
+
+       /* Fill entries that are seen filled in dumps of nvidia driver just
+        * after channel's is put into DMA mode
+        */
+       RAMFC_WR(DMA_PUT       , chan->pushbuf_base);
+       RAMFC_WR(DMA_GET       , chan->pushbuf_base);
+       RAMFC_WR(DMA_INSTANCE  , pushbuf);
+       RAMFC_WR(DMA_FETCH     , NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+                                NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+                                NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
+#ifdef __BIG_ENDIAN
+                                NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+                                0x30000000 /* no idea.. */);
+       RAMFC_WR(DMA_SUBROUTINE, 0);
+       RAMFC_WR(GRCTX_INSTANCE, grctx);
+       RAMFC_WR(DMA_TIMESLICE , 0x0001FFFF);
+
+       return 0;
+}
+
+void
+nv40_fifo_destroy_context(drm_device_t *dev, int channel)
+{
+       drm_nouveau_private_t *dev_priv = dev->dev_private;
+       uint32_t fifoctx;
+       int i;
+
+       fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128;
+       for (i=0;i<128;i+=4)
+               NV_WRITE(fifoctx + i, 0);
+}
+
+int
+nv40_fifo_load_context(drm_device_t *dev, int channel)
+{
+       drm_nouveau_private_t *dev_priv = dev->dev_private;
+       uint32_t fifoctx;
+       uint32_t tmp, tmp2;
+
+       fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128;
+
+       NV_WRITE(NV04_PFIFO_CACHE1_DMA_GET          , RAMFC_RD(DMA_GET));
+       NV_WRITE(NV04_PFIFO_CACHE1_DMA_PUT          , RAMFC_RD(DMA_PUT));
+       NV_WRITE(NV10_PFIFO_CACHE1_REF_CNT          , RAMFC_RD(REF_CNT));
+       NV_WRITE(NV04_PFIFO_CACHE1_DMA_INSTANCE     , RAMFC_RD(DMA_INSTANCE));
+       NV_WRITE(NV10_PFIFO_CACHE1_DMA_DCOUNT       , RAMFC_RD(DMA_DCOUNT));
+       NV_WRITE(NV04_PFIFO_CACHE1_DMA_STATE        , RAMFC_RD(DMA_STATE));
+
+       /* No idea what 0x2058 is.. */
+       tmp   = RAMFC_RD(DMA_FETCH);
+       tmp2  = NV_READ(0x2058) & 0xFFF;
+       tmp2 |= (tmp & 0x30000000);
+       NV_WRITE(0x2058, tmp2);
+       tmp  &= ~0x30000000;
+       NV_WRITE(NV04_PFIFO_CACHE1_DMA_FETCH        , tmp);
+
+       NV_WRITE(NV04_PFIFO_CACHE1_ENGINE           , RAMFC_RD(ENGINE));
+       NV_WRITE(NV04_PFIFO_CACHE1_PULL1            , RAMFC_RD(PULL1_ENGINE));
+       NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_VALUE    , RAMFC_RD(ACQUIRE_VALUE));
+       NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, RAMFC_RD(ACQUIRE_TIMESTAMP));
+       NV_WRITE(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT  , RAMFC_RD(ACQUIRE_TIMEOUT));
+       NV_WRITE(NV10_PFIFO_CACHE1_SEMAPHORE        , RAMFC_RD(SEMAPHORE));
+       NV_WRITE(NV10_PFIFO_CACHE1_DMA_SUBROUTINE   , RAMFC_RD(DMA_SUBROUTINE));
+       NV_WRITE(NV40_PFIFO_GRCTX_INSTANCE          , RAMFC_RD(GRCTX_INSTANCE));
+       NV_WRITE(0x32e4, RAMFC_RD(UNK_40));
+       /* NVIDIA does this next line twice... */
+       NV_WRITE(0x32e8, RAMFC_RD(UNK_44));
+       NV_WRITE(0x2088, RAMFC_RD(UNK_4C));
+       NV_WRITE(0x3300, RAMFC_RD(UNK_50));
+
+       /* not sure what part is PUT, and which is GET.. never seen a non-zero
+        * value appear in a mmio-trace yet..
+        */
+#if 0
+       tmp = NV_READ(UNK_84);
+       NV_WRITE(NV_PFIFO_CACHE1_GET, tmp ???);
+       NV_WRITE(NV_PFIFO_CACHE1_PUT, tmp ???);
+#endif
+
+       /* Don't clobber the TIMEOUT_ENABLED flag when restoring from RAMFC */
+       tmp  = NV_READ(NV04_PFIFO_DMA_TIMESLICE) & ~0x1FFFF;
+       tmp |= RAMFC_RD(DMA_TIMESLICE) & 0x1FFFF;
+       NV_WRITE(NV04_PFIFO_DMA_TIMESLICE, tmp);
+
+       /* Set channel active, and in DMA mode */
+       NV_WRITE(NV03_PFIFO_CACHE1_PUSH1  , 0x00010000 | channel);
+       /* Reset DMA_CTL_AT_INFO to INVALID */
+       tmp = NV_READ(NV04_PFIFO_CACHE1_DMA_CTL) & ~(1<<31);
+       NV_WRITE(NV04_PFIFO_CACHE1_DMA_CTL, tmp);
+
+       return 0;
+}
+
+int
+nv40_fifo_save_context(drm_device_t *dev, int channel)
+{
+       drm_nouveau_private_t *dev_priv = dev->dev_private;
+       uint32_t fifoctx;
+       uint32_t tmp;
+
+       fifoctx = NV_RAMIN + dev_priv->ramfc_offset + channel*128;
+
+       RAMFC_WR(DMA_PUT          , NV_READ(NV04_PFIFO_CACHE1_DMA_PUT));
+       RAMFC_WR(DMA_GET          , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
+       RAMFC_WR(REF_CNT          , NV_READ(NV10_PFIFO_CACHE1_REF_CNT));
+       RAMFC_WR(DMA_INSTANCE     , NV_READ(NV04_PFIFO_CACHE1_DMA_INSTANCE));
+       RAMFC_WR(DMA_DCOUNT       , NV_READ(NV10_PFIFO_CACHE1_DMA_DCOUNT));
+       RAMFC_WR(DMA_STATE        , NV_READ(NV04_PFIFO_CACHE1_DMA_STATE));
+
+       tmp  = NV_READ(NV04_PFIFO_CACHE1_DMA_FETCH);
+       tmp |= NV_READ(0x2058) & 0x30000000;
+       RAMFC_WR(DMA_FETCH        , tmp);
+
+       RAMFC_WR(ENGINE           , NV_READ(NV04_PFIFO_CACHE1_ENGINE));
+       RAMFC_WR(PULL1_ENGINE     , NV_READ(NV04_PFIFO_CACHE1_PULL1));
+       RAMFC_WR(ACQUIRE_VALUE    , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
+       tmp = NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP);
+       RAMFC_WR(ACQUIRE_TIMESTAMP, tmp);
+       RAMFC_WR(ACQUIRE_TIMEOUT  , NV_READ(NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
+       RAMFC_WR(SEMAPHORE        , NV_READ(NV10_PFIFO_CACHE1_SEMAPHORE));
+
+       /* NVIDIA read 0x3228 first, then write DMA_GET here.. maybe something
+        * more involved depending on the value of 0x3228?
+        */
+       RAMFC_WR(DMA_SUBROUTINE   , NV_READ(NV04_PFIFO_CACHE1_DMA_GET));
+
+       RAMFC_WR(GRCTX_INSTANCE   , NV_READ(NV40_PFIFO_GRCTX_INSTANCE));
+
+       /* No idea what the below is for exactly, ripped from a mmio-trace */
+       RAMFC_WR(UNK_40           , NV_READ(NV40_PFIFO_UNK32E4));
+
+       /* NVIDIA do this next line twice.. bug? */
+       RAMFC_WR(UNK_44           , NV_READ(0x32e8));
+       RAMFC_WR(UNK_4C           , NV_READ(0x2088));
+       RAMFC_WR(UNK_50           , NV_READ(0x3300));
+
+#if 0 /* no real idea which is PUT/GET in UNK_48.. */
+       tmp  = NV_READ(NV04_PFIFO_CACHE1_GET);
+       tmp |= (NV_READ(NV04_PFIFO_CACHE1_PUT) << 16);
+       RAMFC_WR(UNK_48           , tmp);
+#endif
+
+       return 0;
+}
+