]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/nouveau/nve0_fifo.c
Merge tag 'cleanup2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / nve0_fifo.c
index 82ad47cdeab9eb0c2b78e853c5162b483ba8469a..1855ecbd843b81161245cfd15ccb1f4e7f8e2343 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "nouveau_drv.h"
 #include "nouveau_mm.h"
+#include "nouveau_fifo.h"
 
 #define NVE0_FIFO_ENGINE_NUM 32
 
@@ -37,6 +38,7 @@ struct nve0_fifo_engine {
 };
 
 struct nve0_fifo_priv {
+       struct nouveau_fifo_priv base;
        struct nve0_fifo_engine engine[NVE0_FIFO_ENGINE_NUM];
        struct {
                struct nouveau_gpuobj *mem;
@@ -46,7 +48,7 @@ struct nve0_fifo_priv {
 };
 
 struct nve0_fifo_chan {
-       struct nouveau_gpuobj *ramfc;
+       struct nouveau_fifo_chan base;
        u32 engine;
 };
 
@@ -55,8 +57,7 @@ nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nve0_fifo_priv *priv = pfifo->priv;
+       struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
        struct nve0_fifo_engine *peng = &priv->engine[engine];
        struct nouveau_gpuobj *cur;
        u32 match = (engine << 16) | 0x00000001;
@@ -75,7 +76,7 @@ nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
 
        peng->cur_playlist = !peng->cur_playlist;
 
-       for (i = 0, p = 0; i < pfifo->channels; i++) {
+       for (i = 0, p = 0; i < priv->base.channels; i++) {
                u32 ctrl = nv_rd32(dev, 0x800004 + (i * 8)) & 0x001f0001;
                if (ctrl != match)
                        continue;
@@ -91,30 +92,23 @@ nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
                NV_ERROR(dev, "PFIFO: playlist %d update timeout\n", engine);
 }
 
-int
-nve0_fifo_channel_id(struct drm_device *dev)
-{
-       return 4095;
-}
-
-int
-nve0_fifo_create_context(struct nouveau_channel *chan)
+static int
+nve0_fifo_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nve0_fifo_priv *priv = pfifo->priv;
-       struct nve0_fifo_chan *fifoch;
+       struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+       struct nve0_fifo_chan *fctx;
        u64 usermem = priv->user.mem->vinst + chan->id * 512;
        u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
-       int ret;
+       int ret = 0, i;
 
-       chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
-       if (!chan->fifo_priv)
+       fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+       if (!fctx)
                return -ENOMEM;
-       fifoch = chan->fifo_priv;
-       fifoch->engine = 0; /* PGRAPH */
+
+       fctx->engine = 0; /* PGRAPH */
 
        /* allocate vram for control regs, map into polling area */
        chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
@@ -124,56 +118,48 @@ nve0_fifo_create_context(struct nouveau_channel *chan)
                goto error;
        }
 
-       /* ramfc */
-       ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
-                                     chan->ramin->vinst, 0x100,
-                                     NVOBJ_FLAG_ZERO_ALLOC, &fifoch->ramfc);
-       if (ret)
-               goto error;
-
-       nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(usermem));
-       nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(usermem));
-       nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
-       nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
-       nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
-       nv_wo32(fifoch->ramfc, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
+       for (i = 0; i < 0x100; i += 4)
+               nv_wo32(chan->ramin, i, 0x00000000);
+       nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem));
+       nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem));
+       nv_wo32(chan->ramin, 0x10, 0x0000face);
+       nv_wo32(chan->ramin, 0x30, 0xfffff902);
+       nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt));
+       nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
                                     upper_32_bits(ib_virt));
-       nv_wo32(fifoch->ramfc, 0x84, 0x20400000);
-       nv_wo32(fifoch->ramfc, 0x94, 0x30000001);
-       nv_wo32(fifoch->ramfc, 0x9c, 0x00000100);
-       nv_wo32(fifoch->ramfc, 0xac, 0x0000001f);
-       nv_wo32(fifoch->ramfc, 0xe4, 0x00000000);
-       nv_wo32(fifoch->ramfc, 0xe8, chan->id);
-       nv_wo32(fifoch->ramfc, 0xf8, 0x10003080); /* 0x002310 */
-       nv_wo32(fifoch->ramfc, 0xfc, 0x10000010); /* 0x002350 */
+       nv_wo32(chan->ramin, 0x84, 0x20400000);
+       nv_wo32(chan->ramin, 0x94, 0x30000001);
+       nv_wo32(chan->ramin, 0x9c, 0x00000100);
+       nv_wo32(chan->ramin, 0xac, 0x0000001f);
+       nv_wo32(chan->ramin, 0xe4, 0x00000000);
+       nv_wo32(chan->ramin, 0xe8, chan->id);
+       nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */
+       nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */
        pinstmem->flush(dev);
 
        nv_wr32(dev, 0x800000 + (chan->id * 8), 0x80000000 |
                                                (chan->ramin->vinst >> 12));
        nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
-       nve0_fifo_playlist_update(dev, fifoch->engine);
+       nve0_fifo_playlist_update(dev, fctx->engine);
        nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
-       return 0;
 
 error:
-       pfifo->destroy_context(chan);
+       if (ret)
+               priv->base.base.context_del(chan, engine);
        return ret;
 }
 
-void
-nve0_fifo_destroy_context(struct nouveau_channel *chan)
+static void
+nve0_fifo_context_del(struct nouveau_channel *chan, int engine)
 {
-       struct nve0_fifo_chan *fifoch = chan->fifo_priv;
+       struct nve0_fifo_chan *fctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
 
-       if (!fifoch)
-               return;
-
        nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000800, 0x00000800);
        nv_wr32(dev, 0x002634, chan->id);
        if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
                NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
-       nve0_fifo_playlist_update(dev, fifoch->engine);
+       nve0_fifo_playlist_update(dev, fctx->engine);
        nv_wr32(dev, 0x800000 + (chan->id * 8), 0x00000000);
 
        if (chan->user) {
@@ -181,118 +167,17 @@ nve0_fifo_destroy_context(struct nouveau_channel *chan)
                chan->user = NULL;
        }
 
-       nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
-       chan->fifo_priv = NULL;
-       kfree(fifoch);
-}
-
-int
-nve0_fifo_load_context(struct nouveau_channel *chan)
-{
-       return 0;
-}
-
-int
-nve0_fifo_unload_context(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       int i;
-
-       for (i = 0; i < pfifo->channels; i++) {
-               if (!(nv_rd32(dev, 0x800004 + (i * 8)) & 1))
-                       continue;
-
-               nv_mask(dev, 0x800004 + (i * 8), 0x00000800, 0x00000800);
-               nv_wr32(dev, 0x002634, i);
-               if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
-                       NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
-                               i, nv_rd32(dev, 0x002634));
-                       return -EBUSY;
-               }
-       }
-
-       return 0;
-}
-
-static void
-nve0_fifo_destroy(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nve0_fifo_priv *priv;
-       int i;
-
-       priv = pfifo->priv;
-       if (!priv)
-               return;
-
-       nouveau_vm_put(&priv->user.bar);
-       nouveau_gpuobj_ref(NULL, &priv->user.mem);
-
-       for (i = 0; i < NVE0_FIFO_ENGINE_NUM; i++) {
-               nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
-               nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
-       }
-       kfree(priv);
-}
-
-void
-nve0_fifo_takedown(struct drm_device *dev)
-{
-       nv_wr32(dev, 0x002140, 0x00000000);
-       nve0_fifo_destroy(dev);
+       chan->engctx[NVOBJ_ENGINE_FIFO] = NULL;
+       kfree(fctx);
 }
 
 static int
-nve0_fifo_create(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nve0_fifo_priv *priv;
-       int ret;
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-       pfifo->priv = priv;
-
-       ret = nouveau_gpuobj_new(dev, NULL, pfifo->channels * 512, 0x1000,
-                                NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
-       if (ret)
-               goto error;
-
-       ret = nouveau_vm_get(dev_priv->bar1_vm, priv->user.mem->size,
-                            12, NV_MEM_ACCESS_RW, &priv->user.bar);
-       if (ret)
-               goto error;
-
-       nouveau_vm_map(&priv->user.bar, *(struct nouveau_mem **)priv->user.mem->node);
-
-       nouveau_irq_register(dev, 8, nve0_fifo_isr);
-       return 0;
-
-error:
-       nve0_fifo_destroy(dev);
-       return ret;
-}
-
-int
-nve0_fifo_init(struct drm_device *dev)
+nve0_fifo_init(struct drm_device *dev, int engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_channel *chan;
-       struct nve0_fifo_chan *fifoch;
-       struct nve0_fifo_priv *priv;
-       int ret, i;
-
-       if (!pfifo->priv) {
-               ret = nve0_fifo_create(dev);
-               if (ret)
-                       return ret;
-       }
-       priv = pfifo->priv;
+       struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+       struct nve0_fifo_chan *fctx;
+       int i;
 
        /* reset PFIFO, enable all available PSUBFIFO areas */
        nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
@@ -316,22 +201,44 @@ nve0_fifo_init(struct drm_device *dev)
        nv_wr32(dev, 0x002140, 0xbfffffff);
 
        /* restore PFIFO context table */
-       for (i = 0; i < pfifo->channels; i++) {
-               chan = dev_priv->channels.ptr[i];
-               if (!chan || !chan->fifo_priv)
+       for (i = 0; i < priv->base.channels; i++) {
+               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+               if (!chan || !(fctx = chan->engctx[engine]))
                        continue;
-               fifoch = chan->fifo_priv;
 
                nv_wr32(dev, 0x800000 + (i * 8), 0x80000000 |
                                                 (chan->ramin->vinst >> 12));
                nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
-               nve0_fifo_playlist_update(dev, fifoch->engine);
+               nve0_fifo_playlist_update(dev, fctx->engine);
                nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
        }
 
        return 0;
 }
 
+static int
+nve0_fifo_fini(struct drm_device *dev, int engine, bool suspend)
+{
+       struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+       int i;
+
+       for (i = 0; i < priv->base.channels; i++) {
+               if (!(nv_rd32(dev, 0x800004 + (i * 8)) & 1))
+                       continue;
+
+               nv_mask(dev, 0x800004 + (i * 8), 0x00000800, 0x00000800);
+               nv_wr32(dev, 0x002634, i);
+               if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+                       NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+                               i, nv_rd32(dev, 0x002634));
+                       return -EBUSY;
+               }
+       }
+
+       nv_wr32(dev, 0x002140, 0x00000000);
+       return 0;
+}
+
 struct nouveau_enum nve0_fifo_fault_unit[] = {
        {}
 };
@@ -457,3 +364,60 @@ nve0_fifo_isr(struct drm_device *dev)
                nv_wr32(dev, 0x002140, 0);
        }
 }
+
+static void
+nve0_fifo_destroy(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+       int i;
+
+       nouveau_vm_put(&priv->user.bar);
+       nouveau_gpuobj_ref(NULL, &priv->user.mem);
+
+       for (i = 0; i < NVE0_FIFO_ENGINE_NUM; i++) {
+               nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
+               nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
+       }
+
+       dev_priv->eng[engine] = NULL;
+       kfree(priv);
+}
+
+int
+nve0_fifo_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nve0_fifo_priv *priv;
+       int ret;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base.base.destroy = nve0_fifo_destroy;
+       priv->base.base.init = nve0_fifo_init;
+       priv->base.base.fini = nve0_fifo_fini;
+       priv->base.base.context_new = nve0_fifo_context_new;
+       priv->base.base.context_del = nve0_fifo_context_del;
+       priv->base.channels = 4096;
+       dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+
+       ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 512, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+       if (ret)
+               goto error;
+
+       ret = nouveau_vm_get(dev_priv->bar1_vm, priv->user.mem->size,
+                            12, NV_MEM_ACCESS_RW, &priv->user.bar);
+       if (ret)
+               goto error;
+
+       nouveau_vm_map(&priv->user.bar, *(struct nouveau_mem **)priv->user.mem->node);
+
+       nouveau_irq_register(dev, 8, nve0_fifo_isr);
+error:
+       if (ret)
+               priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
+       return ret;
+}