]>
Commit | Line | Data |
---|---|---|
4b223eef BS |
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 | { | |
68b83a93 BS |
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 | ||
d961db75 | 53 | gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT; |
4b223eef BS |
54 | return 0; |
55 | } | |
56 | ||
57 | void | |
58 | nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |
59 | { | |
68b83a93 BS |
60 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
61 | ||
62 | if (gpuobj && gpuobj->im_backing) { | |
63 | if (gpuobj->im_bound) | |
64 | dev_priv->engine.instmem.unbind(dev, gpuobj); | |
65 | nouveau_bo_unpin(gpuobj->im_backing); | |
66 | nouveau_bo_ref(NULL, &gpuobj->im_backing); | |
67 | gpuobj->im_backing = NULL; | |
68 | } | |
4b223eef BS |
69 | } |
70 | ||
71 | int | |
72 | nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |
73 | { | |
68b83a93 BS |
74 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
75 | uint32_t pte, pte_end; | |
76 | uint64_t vram; | |
77 | ||
78 | if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) | |
79 | return -EINVAL; | |
80 | ||
81 | NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", | |
82 | gpuobj->im_pramin->start, gpuobj->im_pramin->size); | |
83 | ||
84 | pte = gpuobj->im_pramin->start >> 12; | |
85 | pte_end = (gpuobj->im_pramin->size >> 12) + pte; | |
43efc9ce | 86 | vram = gpuobj->vinst; |
68b83a93 BS |
87 | |
88 | NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", | |
89 | gpuobj->im_pramin->start, pte, pte_end); | |
43efc9ce | 90 | NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); |
68b83a93 BS |
91 | |
92 | while (pte < pte_end) { | |
93 | nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); | |
94 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | |
95 | vram += 4096; | |
96 | pte++; | |
97 | } | |
98 | dev_priv->engine.instmem.flush(dev); | |
99 | ||
100 | if (1) { | |
101 | u32 chan = nv_rd32(dev, 0x1700) << 16; | |
102 | nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); | |
103 | nv_wr32(dev, 0x100cbc, 0x80000005); | |
104 | } | |
105 | ||
106 | gpuobj->im_bound = 1; | |
4b223eef BS |
107 | return 0; |
108 | } | |
109 | ||
110 | int | |
111 | nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |
112 | { | |
68b83a93 BS |
113 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
114 | uint32_t pte, pte_end; | |
115 | ||
116 | if (gpuobj->im_bound == 0) | |
117 | return -EINVAL; | |
118 | ||
119 | pte = gpuobj->im_pramin->start >> 12; | |
120 | pte_end = (gpuobj->im_pramin->size >> 12) + pte; | |
121 | while (pte < pte_end) { | |
122 | nv_wr32(dev, 0x702000 + (pte * 8), 0); | |
123 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | |
124 | pte++; | |
125 | } | |
126 | dev_priv->engine.instmem.flush(dev); | |
127 | ||
128 | gpuobj->im_bound = 0; | |
4b223eef BS |
129 | return 0; |
130 | } | |
131 | ||
132 | void | |
133 | nvc0_instmem_flush(struct drm_device *dev) | |
134 | { | |
68b83a93 | 135 | nv_wr32(dev, 0x070000, 1); |
4b5c152a | 136 | if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) |
68b83a93 | 137 | NV_ERROR(dev, "PRAMIN flush timeout\n"); |
4b223eef BS |
138 | } |
139 | ||
140 | int | |
141 | nvc0_instmem_suspend(struct drm_device *dev) | |
142 | { | |
147cad09 | 143 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
b515f3a2 | 144 | u32 *buf; |
147cad09 BS |
145 | int i; |
146 | ||
147 | dev_priv->susres.ramin_copy = vmalloc(65536); | |
148 | if (!dev_priv->susres.ramin_copy) | |
149 | return -ENOMEM; | |
b515f3a2 | 150 | buf = dev_priv->susres.ramin_copy; |
147cad09 | 151 | |
b515f3a2 BS |
152 | for (i = 0; i < 65536; i += 4) |
153 | buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i); | |
4b223eef BS |
154 | return 0; |
155 | } | |
156 | ||
157 | void | |
158 | nvc0_instmem_resume(struct drm_device *dev) | |
159 | { | |
147cad09 | 160 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
b515f3a2 | 161 | u32 *buf = dev_priv->susres.ramin_copy; |
147cad09 BS |
162 | u64 chan; |
163 | int i; | |
164 | ||
165 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | |
166 | nv_wr32(dev, 0x001700, chan >> 16); | |
167 | ||
b515f3a2 BS |
168 | for (i = 0; i < 65536; i += 4) |
169 | nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]); | |
147cad09 BS |
170 | vfree(dev_priv->susres.ramin_copy); |
171 | dev_priv->susres.ramin_copy = NULL; | |
172 | ||
173 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | |
4b223eef BS |
174 | } |
175 | ||
176 | int | |
177 | nvc0_instmem_init(struct drm_device *dev) | |
178 | { | |
68b83a93 BS |
179 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
180 | u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; | |
181 | int ret, i; | |
182 | ||
183 | dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; | |
184 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | |
185 | imem = 4096 + 4096 + 32768; | |
186 | ||
187 | nv_wr32(dev, 0x001700, chan >> 16); | |
188 | ||
189 | /* channel setup */ | |
190 | nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); | |
191 | nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); | |
192 | nv_wr32(dev, 0x700208, lower_32_bits(lim3)); | |
193 | nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); | |
194 | ||
195 | /* point pgd -> pgt */ | |
196 | nv_wr32(dev, 0x701000, 0); | |
197 | nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); | |
198 | ||
199 | /* point pgt -> physical vram for channel */ | |
200 | pgt3 = 0x2000; | |
201 | for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { | |
202 | nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); | |
203 | nv_wr32(dev, 0x700004 + pgt3, 0); | |
204 | } | |
205 | ||
206 | /* clear rest of pgt */ | |
207 | for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { | |
208 | nv_wr32(dev, 0x700000 + pgt3, 0); | |
209 | nv_wr32(dev, 0x700004 + pgt3, 0); | |
210 | } | |
211 | ||
212 | /* point bar3 at the channel */ | |
213 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | |
214 | ||
215 | /* Global PRAMIN heap */ | |
216 | ret = drm_mm_init(&dev_priv->ramin_heap, imem, | |
217 | dev_priv->ramin_size - imem); | |
218 | if (ret) { | |
219 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); | |
220 | return -ENOMEM; | |
221 | } | |
222 | ||
4b223eef BS |
223 | return 0; |
224 | } | |
225 | ||
226 | void | |
227 | nvc0_instmem_takedown(struct drm_device *dev) | |
228 | { | |
229 | } | |
230 |