drm/nv31/mpeg: support for a single class3174 user
authorBen Skeggs <bskeggs@redhat.com>
Thu, 23 Jun 2011 06:44:05 +0000 (16:44 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 20 Sep 2011 06:03:44 +0000 (16:03 +1000)
Uncertain if/how the hw does multiple PMPEG channels, supporting one is
better than none however.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv31_mpeg.c

index 93a2e83d02467b98d00f9a9fb7d4184d4db6dab9..07691c2eceac915253d4df8f4a9ab2b39e0b2ad6 100644 (file)
@@ -633,7 +633,10 @@ nouveau_card_init(struct drm_device *dev)
                        break;
                }
 
-               if (dev_priv->card_type == NV_40)
+               if (dev_priv->card_type == NV_40 ||
+                   dev_priv->chipset == 0x31 ||
+                   dev_priv->chipset == 0x34 ||
+                   dev_priv->chipset == 0x36)
                        nv31_mpeg_create(dev);
                else
                if (dev_priv->card_type == NV_50 &&
index 72e86660258dad67442ca442cfaf19127cfe4c96..6f06a0713f005f227c0913fd0d3f94ef49c111d4 100644 (file)
 
 struct nv31_mpeg_engine {
        struct nouveau_exec_engine base;
+       atomic_t refcount;
 };
 
+
+static int
+nv31_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine);
+
+       if (!atomic_add_unless(&pmpeg->refcount, 1, 1))
+               return -EBUSY;
+
+       chan->engctx[engine] = (void *)0xdeadcafe;
+       return 0;
+}
+
+static void
+nv31_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine);
+       atomic_dec(&pmpeg->refcount);
+       chan->engctx[engine] = NULL;
+}
+
 static int
 nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
 {
@@ -121,7 +143,7 @@ nv31_mpeg_init(struct drm_device *dev, int engine)
        /* PMPEG init */
        nv_wr32(dev, 0x00b32c, 0x00000000);
        nv_wr32(dev, 0x00b314, 0x00000100);
-       nv_wr32(dev, 0x00b220, 0x00000044);
+       nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031);
        nv_wr32(dev, 0x00b300, 0x02001ec1);
        nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
 
@@ -191,6 +213,10 @@ nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst)
        unsigned long flags;
        int i;
 
+       /* hardcode drm channel id on nv3x, so swmthd lookup works */
+       if (dev_priv->card_type < NV_40)
+               return 0;
+
        spin_lock_irqsave(&dev_priv->channels.lock, flags);
        for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
                if (!dev_priv->channels.ptr[i])
@@ -275,17 +301,24 @@ nv31_mpeg_destroy(struct drm_device *dev, int engine)
 int
 nv31_mpeg_create(struct drm_device *dev)
 {
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv31_mpeg_engine *pmpeg;
 
        pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
        if (!pmpeg)
                return -ENOMEM;
+       atomic_set(&pmpeg->refcount, 0);
 
        pmpeg->base.destroy = nv31_mpeg_destroy;
        pmpeg->base.init = nv31_mpeg_init;
        pmpeg->base.fini = nv31_mpeg_fini;
-       pmpeg->base.context_new = nv40_mpeg_context_new;
-       pmpeg->base.context_del = nv40_mpeg_context_del;
+       if (dev_priv->card_type < NV_40) {
+               pmpeg->base.context_new = nv31_mpeg_context_new;
+               pmpeg->base.context_del = nv31_mpeg_context_del;
+       } else {
+               pmpeg->base.context_new = nv40_mpeg_context_new;
+               pmpeg->base.context_del = nv40_mpeg_context_del;
+       }
        pmpeg->base.object_new = nv31_mpeg_object_new;
 
        /* ISR vector, PMC_ENABLE bit,  and TILE regs are shared between