]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/gpu/drm/nouveau/nv10_graph.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / gpu / drm / nouveau / nv10_graph.c
index 8e68c97311597ebe2c8b8a9b58536e0df3f81eb3..8c92edb7bbcd1833dcc2c823f230793b243e86e1 100644 (file)
 #include "drm.h"
 #include "nouveau_drm.h"
 #include "nouveau_drv.h"
+#include "nouveau_util.h"
+
+static int  nv10_graph_register(struct drm_device *);
+static void nv10_graph_isr(struct drm_device *);
 
 #define NV10_FIFO_NUMBER 32
 
@@ -786,15 +790,13 @@ nv10_graph_unload_context(struct drm_device *dev)
        return 0;
 }
 
-void
+static void
 nv10_graph_context_switch(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_channel *chan = NULL;
        int chid;
 
-       pgraph->fifo_access(dev, false);
        nouveau_wait_for_idle(dev);
 
        /* If previous context is valid, we need to save it */
@@ -802,11 +804,9 @@ nv10_graph_context_switch(struct drm_device *dev)
 
        /* Load context for next channel */
        chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
-       chan = dev_priv->fifos[chid];
+       chan = dev_priv->channels.ptr[chid];
        if (chan && chan->pgraph_ctx)
                nv10_graph_load_context(chan);
-
-       pgraph->fifo_access(dev, true);
 }
 
 #define NV_WRITE_CTX(reg, val) do { \
@@ -833,7 +833,7 @@ nv10_graph_channel(struct drm_device *dev)
        if (chid >= dev_priv->engine.fifo.channels)
                return NULL;
 
-       return dev_priv->fifos[chid];
+       return dev_priv->channels.ptr[chid];
 }
 
 int nv10_graph_create_context(struct nouveau_channel *chan)
@@ -875,37 +875,54 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
 
 void nv10_graph_destroy_context(struct nouveau_channel *chan)
 {
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       pgraph->fifo_access(dev, false);
+
+       /* Unload the context if it's the currently active one */
+       if (pgraph->channel(dev) == chan)
+               pgraph->unload_context(dev);
 
+       /* Free the context resources */
        kfree(pgraph_ctx);
        chan->pgraph_ctx = NULL;
+
+       pgraph->fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 }
 
 void
-nv10_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
-                            uint32_t size, uint32_t pitch)
+nv10_graph_set_tile_region(struct drm_device *dev, int i)
 {
-       uint32_t limit = max(1u, addr + size) - 1;
-
-       if (pitch)
-               addr |= 1 << 31;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
 
-       nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), limit);
-       nv_wr32(dev, NV10_PGRAPH_TSIZE(i), pitch);
-       nv_wr32(dev, NV10_PGRAPH_TILE(i), addr);
+       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);
 }
 
 int nv10_graph_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        uint32_t tmp;
-       int i;
+       int ret, 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);
 
+       ret = nv10_graph_register(dev);
+       if (ret)
+               return ret;
+
+       nouveau_irq_register(dev, 12, nv10_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -928,7 +945,7 @@ int nv10_graph_init(struct drm_device *dev)
 
        /* 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);
+               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);
@@ -948,17 +965,17 @@ int nv10_graph_init(struct drm_device *dev)
 
 void nv10_graph_takedown(struct drm_device *dev)
 {
+       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
+       nouveau_irq_unregister(dev, 12);
 }
 
 static int
-nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass,
-                          int mthd, uint32_t data)
+nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
+                          u32 class, u32 mthd, u32 data)
 {
        struct drm_device *dev = chan->dev;
        struct graph_state *ctx = chan->pgraph_ctx;
        struct pipe_state *pipe = &ctx->pipe_state;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
        uint32_t xfmode0, xfmode1;
        int i;
@@ -1025,18 +1042,14 @@ nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass,
 
        nouveau_wait_for_idle(dev);
 
-       pgraph->fifo_access(dev, true);
-
        return 0;
 }
 
 static int
-nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass,
-                          int mthd, uint32_t data)
+nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
+                          u32 class, u32 mthd, u32 data)
 {
        struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
 
        nouveau_wait_for_idle(dev);
 
@@ -1045,40 +1058,118 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass,
        nv_wr32(dev, 0x004006b0,
                nv_rd32(dev, 0x004006b0) | 0x8 << 24);
 
-       pgraph->fifo_access(dev, true);
+       return 0;
+}
+
+static int
+nv10_graph_register(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->engine.graph.registered)
+               return 0;
+
+       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+       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);
+       } 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);
+       }
 
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+       dev_priv->engine.graph.registered = true;
        return 0;
 }
 
-static struct nouveau_pgraph_object_method nv17_graph_celsius_mthds[] = {
-       { 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 },
+struct nouveau_bitfield nv10_graph_intr[] = {
+       { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+       { NV_PGRAPH_INTR_ERROR,  "ERROR"  },
        {}
 };
 
-struct nouveau_pgraph_object_class nv10_graph_grclass[] = {
-       { 0x0030, false, NULL }, /* null */
-       { 0x0039, false, NULL }, /* m2mf */
-       { 0x004a, false, NULL }, /* gdirect */
-       { 0x005f, false, NULL }, /* imageblit */
-       { 0x009f, false, NULL }, /* imageblit (nv12) */
-       { 0x008a, false, NULL }, /* ifc */
-       { 0x0089, false, NULL }, /* sifm */
-       { 0x0062, false, NULL }, /* surf2d */
-       { 0x0043, false, NULL }, /* rop */
-       { 0x0012, false, NULL }, /* beta1 */
-       { 0x0072, false, NULL }, /* beta4 */
-       { 0x0019, false, NULL }, /* cliprect */
-       { 0x0044, false, NULL }, /* pattern */
-       { 0x0052, false, NULL }, /* swzsurf */
-       { 0x0093, false, NULL }, /* surf3d */
-       { 0x0094, false, NULL }, /* tex_tri */
-       { 0x0095, false, NULL }, /* multitex_tri */
-       { 0x0056, false, NULL }, /* celcius (nv10) */
-       { 0x0096, false, NULL }, /* celcius (nv11) */
-       { 0x0099, false, nv17_graph_celsius_mthds }, /* celcius (nv17) */
+struct nouveau_bitfield nv10_graph_nstatus[] =
+{
+       { NV10_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
+       { NV10_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
+       { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
+       { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
        {}
 };
+
+static void
+nv10_graph_isr(struct drm_device *dev)
+{
+       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;
+                       }
+               }
+
+               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);
+               }
+
+               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);
+               }
+       }
+}