diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv20_fb.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv20_fb.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nv20_fb.c b/drivers/gpu/drm/nouveau/nv20_fb.c new file mode 100644 index 000000000000..19bd64059a66 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv20_fb.c | |||
@@ -0,0 +1,148 @@ | |||
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 **pmem) | ||
29 | { | ||
30 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
31 | struct drm_mm_node *mem = *pmem; | ||
32 | if (mem) { | ||
33 | spin_lock(&dev_priv->tile.lock); | ||
34 | drm_mm_put_block(mem); | ||
35 | spin_unlock(&dev_priv->tile.lock); | ||
36 | *pmem = NULL; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | void | ||
41 | nv20_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, | ||
42 | uint32_t size, uint32_t pitch, uint32_t flags) | ||
43 | { | ||
44 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
45 | struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; | ||
46 | int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16); | ||
47 | |||
48 | tile->addr = 0x00000001 | addr; | ||
49 | tile->limit = max(1u, addr + size) - 1; | ||
50 | tile->pitch = pitch; | ||
51 | |||
52 | /* Allocate some of the on-die tag memory, used to store Z | ||
53 | * compression meta-data (most likely just a bitmap determining | ||
54 | * if a given tile is compressed or not). | ||
55 | */ | ||
56 | if (flags & NOUVEAU_GEM_TILE_ZETA) { | ||
57 | tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256); | ||
58 | if (tile->tag_mem) { | ||
59 | /* Enable Z compression */ | ||
60 | tile->zcomp = tile->tag_mem->start; | ||
61 | if (dev_priv->chipset >= 0x25) { | ||
62 | if (bpp == 16) | ||
63 | tile->zcomp |= NV25_PFB_ZCOMP_MODE_16; | ||
64 | else | ||
65 | tile->zcomp |= NV25_PFB_ZCOMP_MODE_32; | ||
66 | } else { | ||
67 | tile->zcomp |= NV20_PFB_ZCOMP_EN; | ||
68 | if (bpp != 16) | ||
69 | tile->zcomp |= NV20_PFB_ZCOMP_MODE_32; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | tile->addr |= 2; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | void | ||
78 | nv20_fb_free_tile_region(struct drm_device *dev, int i) | ||
79 | { | ||
80 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
81 | struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; | ||
82 | |||
83 | tile->addr = tile->limit = tile->pitch = tile->zcomp = 0; | ||
84 | nv20_fb_free_tag(dev, &tile->tag_mem); | ||
85 | } | ||
86 | |||
87 | void | ||
88 | nv20_fb_set_tile_region(struct drm_device *dev, int i) | ||
89 | { | ||
90 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
91 | struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; | ||
92 | |||
93 | nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit); | ||
94 | nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); | ||
95 | nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); | ||
96 | nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp); | ||
97 | } | ||
98 | |||
99 | int | ||
100 | nv20_fb_vram_init(struct drm_device *dev) | ||
101 | { | ||
102 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
103 | u32 mem_size = nv_rd32(dev, 0x10020c); | ||
104 | u32 pbus1218 = nv_rd32(dev, 0x001218); | ||
105 | |||
106 | dev_priv->vram_size = mem_size & 0xff000000; | ||
107 | switch (pbus1218 & 0x00000300) { | ||
108 | case 0x00000000: dev_priv->vram_type = NV_MEM_TYPE_SDRAM; break; | ||
109 | case 0x00000100: dev_priv->vram_type = NV_MEM_TYPE_DDR1; break; | ||
110 | case 0x00000200: dev_priv->vram_type = NV_MEM_TYPE_GDDR3; break; | ||
111 | case 0x00000300: dev_priv->vram_type = NV_MEM_TYPE_GDDR2; break; | ||
112 | } | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | int | ||
118 | nv20_fb_init(struct drm_device *dev) | ||
119 | { | ||
120 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
121 | struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; | ||
122 | int i; | ||
123 | |||
124 | if (dev_priv->chipset >= 0x25) | ||
125 | drm_mm_init(&pfb->tag_heap, 0, 64 * 1024); | ||
126 | else | ||
127 | drm_mm_init(&pfb->tag_heap, 0, 32 * 1024); | ||
128 | |||
129 | /* Turn all the tiling regions off. */ | ||
130 | pfb->num_tiles = NV10_PFB_TILE__SIZE; | ||
131 | for (i = 0; i < pfb->num_tiles; i++) | ||
132 | pfb->set_tile_region(dev, i); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | void | ||
138 | nv20_fb_takedown(struct drm_device *dev) | ||
139 | { | ||
140 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
141 | struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; | ||
142 | int i; | ||
143 | |||
144 | for (i = 0; i < pfb->num_tiles; i++) | ||
145 | pfb->free_tile_region(dev, i); | ||
146 | |||
147 | drm_mm_takedown(&pfb->tag_heap); | ||
148 | } | ||