Merge branch 'drm-nouveau-next' of git://git.freedesktop.org/git/nouveau/linux-2...
[pandora-kernel.git] / drivers / gpu / drm / nouveau / nv10_fb.c
1 #include "drmP.h"
2 #include "drm.h"
3 #include "nouveau_drv.h"
4 #include "nouveau_drm.h"
5
6 static struct drm_mm_node *
7 nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size)
8 {
9         struct drm_nouveau_private *dev_priv = dev->dev_private;
10         struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
11         struct drm_mm_node *mem;
12         int ret;
13
14         ret = drm_mm_pre_get(&pfb->tag_heap);
15         if (ret)
16                 return NULL;
17
18         spin_lock(&dev_priv->tile.lock);
19         mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0);
20         if (mem)
21                 mem = drm_mm_get_block_atomic(mem, size, 0);
22         spin_unlock(&dev_priv->tile.lock);
23
24         return mem;
25 }
26
27 static void
28 nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node *mem)
29 {
30         struct drm_nouveau_private *dev_priv = dev->dev_private;
31
32         spin_lock(&dev_priv->tile.lock);
33         drm_mm_put_block(mem);
34         spin_unlock(&dev_priv->tile.lock);
35 }
36
37 void
38 nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr,
39                          uint32_t size, uint32_t pitch, uint32_t flags)
40 {
41         struct drm_nouveau_private *dev_priv = dev->dev_private;
42         struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
43         int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16);
44
45         tile->addr = addr;
46         tile->limit = max(1u, addr + size) - 1;
47         tile->pitch = pitch;
48
49         if (dev_priv->card_type == NV_20) {
50                 if (flags & NOUVEAU_GEM_TILE_ZETA) {
51                         /*
52                          * Allocate some of the on-die tag memory,
53                          * used to store Z compression meta-data (most
54                          * likely just a bitmap determining if a given
55                          * tile is compressed or not).
56                          */
57                         tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256);
58
59                         if (tile->tag_mem) {
60                                 /* Enable Z compression */
61                                 if (dev_priv->chipset >= 0x25)
62                                         tile->zcomp = tile->tag_mem->start |
63                                                 (bpp == 16 ?
64                                                  NV25_PFB_ZCOMP_MODE_16 :
65                                                  NV25_PFB_ZCOMP_MODE_32);
66                                 else
67                                         tile->zcomp = tile->tag_mem->start |
68                                                 NV20_PFB_ZCOMP_EN |
69                                                 (bpp == 16 ? 0 :
70                                                  NV20_PFB_ZCOMP_MODE_32);
71                         }
72
73                         tile->addr |= 3;
74                 } else {
75                         tile->addr |= 1;
76                 }
77
78         } else {
79                 tile->addr |= 1 << 31;
80         }
81 }
82
83 void
84 nv10_fb_free_tile_region(struct drm_device *dev, int i)
85 {
86         struct drm_nouveau_private *dev_priv = dev->dev_private;
87         struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
88
89         if (tile->tag_mem) {
90                 nv20_fb_free_tag(dev, tile->tag_mem);
91                 tile->tag_mem = NULL;
92         }
93
94         tile->addr = tile->limit = tile->pitch = tile->zcomp = 0;
95 }
96
97 void
98 nv10_fb_set_tile_region(struct drm_device *dev, int i)
99 {
100         struct drm_nouveau_private *dev_priv = dev->dev_private;
101         struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
102
103         nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit);
104         nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch);
105         nv_wr32(dev, NV10_PFB_TILE(i), tile->addr);
106
107         if (dev_priv->card_type == NV_20)
108                 nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp);
109 }
110
111 int
112 nv10_fb_init(struct drm_device *dev)
113 {
114         struct drm_nouveau_private *dev_priv = dev->dev_private;
115         struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
116         int i;
117
118         pfb->num_tiles = NV10_PFB_TILE__SIZE;
119
120         if (dev_priv->card_type == NV_20)
121                 drm_mm_init(&pfb->tag_heap, 0,
122                             (dev_priv->chipset >= 0x25 ?
123                              64 * 1024 : 32 * 1024));
124
125         /* Turn all the tiling regions off. */
126         for (i = 0; i < pfb->num_tiles; i++)
127                 pfb->set_tile_region(dev, i);
128
129         return 0;
130 }
131
132 void
133 nv10_fb_takedown(struct drm_device *dev)
134 {
135         struct drm_nouveau_private *dev_priv = dev->dev_private;
136         struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
137         int i;
138
139         for (i = 0; i < pfb->num_tiles; i++)
140                 pfb->free_tile_region(dev, i);
141
142         if (dev_priv->card_type == NV_20)
143                 drm_mm_takedown(&pfb->tag_heap);
144 }