Commit | Line | Data |
---|---|---|
d81c19e3 BS |
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; | |
ff92a6cd BS |
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 | } | |
d81c19e3 | 113 | |
d81c19e3 BS |
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 | } |