diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvc0_instmem.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_instmem.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c new file mode 100644 index 000000000000..3ab3cdc42173 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include "drmP.h" | ||
26 | |||
27 | #include "nouveau_drv.h" | ||
28 | |||
29 | int | ||
30 | nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, | ||
31 | uint32_t *size) | ||
32 | { | ||
33 | int ret; | ||
34 | |||
35 | *size = ALIGN(*size, 4096); | ||
36 | if (*size == 0) | ||
37 | return -EINVAL; | ||
38 | |||
39 | ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, | ||
40 | true, false, &gpuobj->im_backing); | ||
41 | if (ret) { | ||
42 | NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); | ||
47 | if (ret) { | ||
48 | NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); | ||
49 | nouveau_bo_ref(NULL, &gpuobj->im_backing); | ||
50 | return ret; | ||
51 | } | ||
52 | |||
53 | gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start; | ||
54 | gpuobj->im_backing_start <<= PAGE_SHIFT; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | void | ||
59 | nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | ||
60 | { | ||
61 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
62 | |||
63 | if (gpuobj && gpuobj->im_backing) { | ||
64 | if (gpuobj->im_bound) | ||
65 | dev_priv->engine.instmem.unbind(dev, gpuobj); | ||
66 | nouveau_bo_unpin(gpuobj->im_backing); | ||
67 | nouveau_bo_ref(NULL, &gpuobj->im_backing); | ||
68 | gpuobj->im_backing = NULL; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | int | ||
73 | nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | ||
74 | { | ||
75 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
76 | uint32_t pte, pte_end; | ||
77 | uint64_t vram; | ||
78 | |||
79 | if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) | ||
80 | return -EINVAL; | ||
81 | |||
82 | NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", | ||
83 | gpuobj->im_pramin->start, gpuobj->im_pramin->size); | ||
84 | |||
85 | pte = gpuobj->im_pramin->start >> 12; | ||
86 | pte_end = (gpuobj->im_pramin->size >> 12) + pte; | ||
87 | vram = gpuobj->im_backing_start; | ||
88 | |||
89 | NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", | ||
90 | gpuobj->im_pramin->start, pte, pte_end); | ||
91 | NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); | ||
92 | |||
93 | while (pte < pte_end) { | ||
94 | nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); | ||
95 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | ||
96 | vram += 4096; | ||
97 | pte++; | ||
98 | } | ||
99 | dev_priv->engine.instmem.flush(dev); | ||
100 | |||
101 | if (1) { | ||
102 | u32 chan = nv_rd32(dev, 0x1700) << 16; | ||
103 | nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); | ||
104 | nv_wr32(dev, 0x100cbc, 0x80000005); | ||
105 | } | ||
106 | |||
107 | gpuobj->im_bound = 1; | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | int | ||
112 | nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | ||
113 | { | ||
114 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
115 | uint32_t pte, pte_end; | ||
116 | |||
117 | if (gpuobj->im_bound == 0) | ||
118 | return -EINVAL; | ||
119 | |||
120 | pte = gpuobj->im_pramin->start >> 12; | ||
121 | pte_end = (gpuobj->im_pramin->size >> 12) + pte; | ||
122 | while (pte < pte_end) { | ||
123 | nv_wr32(dev, 0x702000 + (pte * 8), 0); | ||
124 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | ||
125 | pte++; | ||
126 | } | ||
127 | dev_priv->engine.instmem.flush(dev); | ||
128 | |||
129 | gpuobj->im_bound = 0; | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | void | ||
134 | nvc0_instmem_flush(struct drm_device *dev) | ||
135 | { | ||
136 | nv_wr32(dev, 0x070000, 1); | ||
137 | if (!nv_wait(0x070000, 0x00000002, 0x00000000)) | ||
138 | NV_ERROR(dev, "PRAMIN flush timeout\n"); | ||
139 | } | ||
140 | |||
141 | int | ||
142 | nvc0_instmem_suspend(struct drm_device *dev) | ||
143 | { | ||
144 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
145 | int i; | ||
146 | |||
147 | dev_priv->susres.ramin_copy = vmalloc(65536); | ||
148 | if (!dev_priv->susres.ramin_copy) | ||
149 | return -ENOMEM; | ||
150 | |||
151 | for (i = 0x700000; i < 0x710000; i += 4) | ||
152 | dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | void | ||
157 | nvc0_instmem_resume(struct drm_device *dev) | ||
158 | { | ||
159 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
160 | u64 chan; | ||
161 | int i; | ||
162 | |||
163 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | ||
164 | nv_wr32(dev, 0x001700, chan >> 16); | ||
165 | |||
166 | for (i = 0x700000; i < 0x710000; i += 4) | ||
167 | nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]); | ||
168 | vfree(dev_priv->susres.ramin_copy); | ||
169 | dev_priv->susres.ramin_copy = NULL; | ||
170 | |||
171 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | ||
172 | } | ||
173 | |||
174 | int | ||
175 | nvc0_instmem_init(struct drm_device *dev) | ||
176 | { | ||
177 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
178 | u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; | ||
179 | int ret, i; | ||
180 | |||
181 | dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; | ||
182 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | ||
183 | imem = 4096 + 4096 + 32768; | ||
184 | |||
185 | nv_wr32(dev, 0x001700, chan >> 16); | ||
186 | |||
187 | /* channel setup */ | ||
188 | nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); | ||
189 | nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); | ||
190 | nv_wr32(dev, 0x700208, lower_32_bits(lim3)); | ||
191 | nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); | ||
192 | |||
193 | /* point pgd -> pgt */ | ||
194 | nv_wr32(dev, 0x701000, 0); | ||
195 | nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); | ||
196 | |||
197 | /* point pgt -> physical vram for channel */ | ||
198 | pgt3 = 0x2000; | ||
199 | for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { | ||
200 | nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); | ||
201 | nv_wr32(dev, 0x700004 + pgt3, 0); | ||
202 | } | ||
203 | |||
204 | /* clear rest of pgt */ | ||
205 | for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { | ||
206 | nv_wr32(dev, 0x700000 + pgt3, 0); | ||
207 | nv_wr32(dev, 0x700004 + pgt3, 0); | ||
208 | } | ||
209 | |||
210 | /* point bar3 at the channel */ | ||
211 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | ||
212 | |||
213 | /* Global PRAMIN heap */ | ||
214 | ret = drm_mm_init(&dev_priv->ramin_heap, imem, | ||
215 | dev_priv->ramin_size - imem); | ||
216 | if (ret) { | ||
217 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); | ||
218 | return -ENOMEM; | ||
219 | } | ||
220 | |||
221 | /*XXX: incorrect, but needed to make hash func "work" */ | ||
222 | dev_priv->ramht_offset = 0x10000; | ||
223 | dev_priv->ramht_bits = 9; | ||
224 | dev_priv->ramht_size = (1 << dev_priv->ramht_bits); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | void | ||
229 | nvc0_instmem_takedown(struct drm_device *dev) | ||
230 | { | ||
231 | } | ||
232 | |||