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