Commit | Line | Data |
---|---|---|
6ee73861 | 1 | /* |
ebb945a9 | 2 | * Copyright 2012 Red Hat Inc. |
6ee73861 | 3 | * |
ebb945a9 BS |
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: | |
6ee73861 | 10 | * |
ebb945a9 BS |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. | |
6ee73861 | 13 | * |
ebb945a9 BS |
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. | |
6ee73861 | 21 | * |
ebb945a9 | 22 | * Authors: Ben Skeggs |
6ee73861 BS |
23 | */ |
24 | ||
ebb945a9 BS |
25 | #include <core/client.h> |
26 | #include <core/engctx.h> | |
02a841d4 | 27 | #include <core/ramht.h> |
ebb945a9 BS |
28 | #include <core/class.h> |
29 | #include <core/math.h> | |
6ee73861 | 30 | |
ebb945a9 BS |
31 | #include <subdev/timer.h> |
32 | #include <subdev/bar.h> | |
c420b2dc | 33 | |
ebb945a9 BS |
34 | #include <engine/dmaobj.h> |
35 | #include <engine/fifo.h> | |
36 | ||
37 | #include "nv50.h" | |
38 | ||
39 | /******************************************************************************* | |
40 | * FIFO channel objects | |
41 | ******************************************************************************/ | |
c420b2dc BS |
42 | |
43 | void | |
ebb945a9 | 44 | nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) |
6ee73861 | 45 | { |
ebb945a9 | 46 | struct nouveau_bar *bar = nouveau_bar(priv); |
a8eaebc6 | 47 | struct nouveau_gpuobj *cur; |
694931d2 | 48 | int i, p; |
6ee73861 | 49 | |
b5096566 | 50 | mutex_lock(&nv_subdev(priv)->mutex); |
c420b2dc BS |
51 | cur = priv->playlist[priv->cur_playlist]; |
52 | priv->cur_playlist = !priv->cur_playlist; | |
6ee73861 | 53 | |
ebb945a9 BS |
54 | for (i = priv->base.min, p = 0; i < priv->base.max; i++) { |
55 | if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000) | |
694931d2 | 56 | nv_wo32(cur, p++ * 4, i); |
6ee73861 | 57 | } |
694931d2 | 58 | |
ebb945a9 | 59 | bar->flush(bar); |
6ee73861 | 60 | |
ebb945a9 BS |
61 | nv_wr32(priv, 0x0032f4, cur->addr >> 12); |
62 | nv_wr32(priv, 0x0032ec, p); | |
63 | nv_wr32(priv, 0x002500, 0x00000101); | |
b5096566 | 64 | mutex_unlock(&nv_subdev(priv)->mutex); |
6ee73861 BS |
65 | } |
66 | ||
c420b2dc | 67 | static int |
ebb945a9 BS |
68 | nv50_fifo_context_attach(struct nouveau_object *parent, |
69 | struct nouveau_object *object) | |
6ee73861 | 70 | { |
ebb945a9 BS |
71 | struct nouveau_bar *bar = nouveau_bar(parent); |
72 | struct nv50_fifo_base *base = (void *)parent->parent; | |
73 | struct nouveau_gpuobj *ectx = (void *)object; | |
74 | u64 limit = ectx->addr + ectx->size - 1; | |
75 | u64 start = ectx->addr; | |
76 | u32 addr; | |
77 | ||
78 | switch (nv_engidx(object->engine)) { | |
79 | case NVDEV_ENGINE_SW : return 0; | |
80 | case NVDEV_ENGINE_GR : addr = 0x0000; break; | |
81 | case NVDEV_ENGINE_MPEG : addr = 0x0060; break; | |
82 | default: | |
83 | return -EINVAL; | |
6ee73861 BS |
84 | } |
85 | ||
4c2d4222 | 86 | nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; |
ebb945a9 BS |
87 | nv_wo32(base->eng, addr + 0x00, 0x00190000); |
88 | nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); | |
89 | nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); | |
90 | nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | | |
91 | upper_32_bits(start)); | |
92 | nv_wo32(base->eng, addr + 0x10, 0x00000000); | |
93 | nv_wo32(base->eng, addr + 0x14, 0x00000000); | |
94 | bar->flush(bar); | |
95 | return 0; | |
6ee73861 BS |
96 | } |
97 | ||
ebb945a9 BS |
98 | static int |
99 | nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend, | |
100 | struct nouveau_object *object) | |
03bd6efa | 101 | { |
ebb945a9 BS |
102 | struct nouveau_bar *bar = nouveau_bar(parent); |
103 | struct nv50_fifo_priv *priv = (void *)parent->engine; | |
104 | struct nv50_fifo_base *base = (void *)parent->parent; | |
105 | struct nv50_fifo_chan *chan = (void *)parent; | |
106 | u32 addr, me; | |
107 | int ret = 0; | |
108 | ||
109 | switch (nv_engidx(object->engine)) { | |
110 | case NVDEV_ENGINE_SW : return 0; | |
111 | case NVDEV_ENGINE_GR : addr = 0x0000; break; | |
112 | case NVDEV_ENGINE_MPEG : addr = 0x0060; break; | |
113 | default: | |
114 | return -EINVAL; | |
115 | } | |
116 | ||
c420b2dc BS |
117 | /* HW bug workaround: |
118 | * | |
119 | * PFIFO will hang forever if the connected engines don't report | |
120 | * that they've processed the context switch request. | |
121 | * | |
122 | * In order for the kickoff to work, we need to ensure all the | |
123 | * connected engines are in a state where they can answer. | |
124 | * | |
125 | * Newer chipsets don't seem to suffer from this issue, and well, | |
126 | * there's also a "ignore these engines" bitmask reg we can use | |
127 | * if we hit the issue there.. | |
128 | */ | |
ebb945a9 | 129 | me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001); |
c420b2dc BS |
130 | |
131 | /* do the kickoff... */ | |
ebb945a9 BS |
132 | nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); |
133 | if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { | |
93260d3c MS |
134 | nv_error(priv, "channel %d [%s] unload timeout\n", |
135 | chan->base.chid, nouveau_client_name(chan)); | |
ebb945a9 BS |
136 | if (suspend) |
137 | ret = -EBUSY; | |
03bd6efa | 138 | } |
ebb945a9 | 139 | nv_wr32(priv, 0x00b860, me); |
edc260d0 BS |
140 | |
141 | if (ret == 0) { | |
142 | nv_wo32(base->eng, addr + 0x00, 0x00000000); | |
143 | nv_wo32(base->eng, addr + 0x04, 0x00000000); | |
144 | nv_wo32(base->eng, addr + 0x08, 0x00000000); | |
145 | nv_wo32(base->eng, addr + 0x0c, 0x00000000); | |
146 | nv_wo32(base->eng, addr + 0x10, 0x00000000); | |
147 | nv_wo32(base->eng, addr + 0x14, 0x00000000); | |
148 | bar->flush(bar); | |
149 | } | |
150 | ||
ebb945a9 | 151 | return ret; |
03bd6efa BS |
152 | } |
153 | ||
ebb945a9 BS |
154 | static int |
155 | nv50_fifo_object_attach(struct nouveau_object *parent, | |
156 | struct nouveau_object *object, u32 handle) | |
6ee73861 | 157 | { |
ebb945a9 BS |
158 | struct nv50_fifo_chan *chan = (void *)parent; |
159 | u32 context; | |
160 | ||
161 | if (nv_iclass(object, NV_GPUOBJ_CLASS)) | |
162 | context = nv_gpuobj(object)->node->offset >> 4; | |
163 | else | |
164 | context = 0x00000004; /* just non-zero */ | |
165 | ||
166 | switch (nv_engidx(object->engine)) { | |
167 | case NVDEV_ENGINE_DMAOBJ: | |
168 | case NVDEV_ENGINE_SW : context |= 0x00000000; break; | |
169 | case NVDEV_ENGINE_GR : context |= 0x00100000; break; | |
170 | case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; | |
171 | default: | |
172 | return -EINVAL; | |
d908175c | 173 | } |
03bd6efa | 174 | |
ebb945a9 BS |
175 | return nouveau_ramht_insert(chan->ramht, 0, handle, context); |
176 | } | |
177 | ||
178 | void | |
179 | nv50_fifo_object_detach(struct nouveau_object *parent, int cookie) | |
180 | { | |
181 | struct nv50_fifo_chan *chan = (void *)parent; | |
182 | nouveau_ramht_remove(chan->ramht, cookie); | |
6ee73861 BS |
183 | } |
184 | ||
c420b2dc | 185 | static int |
368be5f1 BS |
186 | nv50_fifo_chan_ctor_dma(struct nouveau_object *parent, |
187 | struct nouveau_object *engine, | |
188 | struct nouveau_oclass *oclass, void *data, u32 size, | |
189 | struct nouveau_object **pobject) | |
190 | { | |
191 | struct nouveau_bar *bar = nouveau_bar(parent); | |
192 | struct nv50_fifo_base *base = (void *)parent; | |
193 | struct nv50_fifo_chan *chan; | |
194 | struct nv03_channel_dma_class *args = data; | |
195 | int ret; | |
196 | ||
197 | if (size < sizeof(*args)) | |
198 | return -EINVAL; | |
199 | ||
200 | ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, | |
201 | 0x2000, args->pushbuf, | |
507ceb15 MP |
202 | (1ULL << NVDEV_ENGINE_DMAOBJ) | |
203 | (1ULL << NVDEV_ENGINE_SW) | | |
204 | (1ULL << NVDEV_ENGINE_GR) | | |
205 | (1ULL << NVDEV_ENGINE_MPEG), &chan); | |
368be5f1 BS |
206 | *pobject = nv_object(chan); |
207 | if (ret) | |
208 | return ret; | |
209 | ||
210 | nv_parent(chan)->context_attach = nv50_fifo_context_attach; | |
211 | nv_parent(chan)->context_detach = nv50_fifo_context_detach; | |
212 | nv_parent(chan)->object_attach = nv50_fifo_object_attach; | |
213 | nv_parent(chan)->object_detach = nv50_fifo_object_detach; | |
214 | ||
f50c8054 BS |
215 | ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, |
216 | &chan->ramht); | |
368be5f1 BS |
217 | if (ret) |
218 | return ret; | |
219 | ||
220 | nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset)); | |
221 | nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset)); | |
222 | nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset)); | |
223 | nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset)); | |
224 | nv_wo32(base->ramfc, 0x3c, 0x003f6078); | |
225 | nv_wo32(base->ramfc, 0x44, 0x01003fff); | |
226 | nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); | |
227 | nv_wo32(base->ramfc, 0x4c, 0xffffffff); | |
228 | nv_wo32(base->ramfc, 0x60, 0x7fffffff); | |
229 | nv_wo32(base->ramfc, 0x78, 0x00000000); | |
230 | nv_wo32(base->ramfc, 0x7c, 0x30000001); | |
231 | nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | | |
232 | (4 << 24) /* SEARCH_FULL */ | | |
233 | (chan->ramht->base.node->offset >> 4)); | |
234 | bar->flush(bar); | |
235 | return 0; | |
236 | } | |
237 | ||
238 | static int | |
239 | nv50_fifo_chan_ctor_ind(struct nouveau_object *parent, | |
240 | struct nouveau_object *engine, | |
241 | struct nouveau_oclass *oclass, void *data, u32 size, | |
242 | struct nouveau_object **pobject) | |
6ee73861 | 243 | { |
dbff2dee | 244 | struct nv50_channel_ind_class *args = data; |
ebb945a9 BS |
245 | struct nouveau_bar *bar = nouveau_bar(parent); |
246 | struct nv50_fifo_base *base = (void *)parent; | |
247 | struct nv50_fifo_chan *chan; | |
248 | u64 ioffset, ilength; | |
249 | int ret; | |
250 | ||
251 | if (size < sizeof(*args)) | |
252 | return -EINVAL; | |
253 | ||
254 | ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, | |
255 | 0x2000, args->pushbuf, | |
507ceb15 MP |
256 | (1ULL << NVDEV_ENGINE_DMAOBJ) | |
257 | (1ULL << NVDEV_ENGINE_SW) | | |
258 | (1ULL << NVDEV_ENGINE_GR) | | |
259 | (1ULL << NVDEV_ENGINE_MPEG), &chan); | |
ebb945a9 BS |
260 | *pobject = nv_object(chan); |
261 | if (ret) | |
262 | return ret; | |
c420b2dc | 263 | |
ebb945a9 BS |
264 | nv_parent(chan)->context_attach = nv50_fifo_context_attach; |
265 | nv_parent(chan)->context_detach = nv50_fifo_context_detach; | |
266 | nv_parent(chan)->object_attach = nv50_fifo_object_attach; | |
267 | nv_parent(chan)->object_detach = nv50_fifo_object_detach; | |
c420b2dc | 268 | |
f50c8054 BS |
269 | ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, |
270 | &chan->ramht); | |
ebb945a9 BS |
271 | if (ret) |
272 | return ret; | |
273 | ||
274 | ioffset = args->ioffset; | |
275 | ilength = log2i(args->ilength / 8); | |
276 | ||
277 | nv_wo32(base->ramfc, 0x3c, 0x403f6078); | |
278 | nv_wo32(base->ramfc, 0x44, 0x01003fff); | |
279 | nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); | |
280 | nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); | |
281 | nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); | |
282 | nv_wo32(base->ramfc, 0x60, 0x7fffffff); | |
283 | nv_wo32(base->ramfc, 0x78, 0x00000000); | |
284 | nv_wo32(base->ramfc, 0x7c, 0x30000001); | |
285 | nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | | |
286 | (4 << 24) /* SEARCH_FULL */ | | |
287 | (chan->ramht->base.node->offset >> 4)); | |
288 | bar->flush(bar); | |
6ee73861 BS |
289 | return 0; |
290 | } | |
291 | ||
ebb945a9 BS |
292 | void |
293 | nv50_fifo_chan_dtor(struct nouveau_object *object) | |
294 | { | |
295 | struct nv50_fifo_chan *chan = (void *)object; | |
296 | nouveau_ramht_ref(NULL, &chan->ramht); | |
297 | nouveau_fifo_channel_destroy(&chan->base); | |
298 | } | |
299 | ||
c420b2dc | 300 | static int |
ebb945a9 | 301 | nv50_fifo_chan_init(struct nouveau_object *object) |
6ee73861 | 302 | { |
ebb945a9 BS |
303 | struct nv50_fifo_priv *priv = (void *)object->engine; |
304 | struct nv50_fifo_base *base = (void *)object->parent; | |
305 | struct nv50_fifo_chan *chan = (void *)object; | |
306 | struct nouveau_gpuobj *ramfc = base->ramfc; | |
307 | u32 chid = chan->base.chid; | |
308 | int ret; | |
6ee73861 | 309 | |
ebb945a9 BS |
310 | ret = nouveau_fifo_channel_init(&chan->base); |
311 | if (ret) | |
312 | return ret; | |
313 | ||
314 | nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); | |
315 | nv50_fifo_playlist_update(priv); | |
6ee73861 BS |
316 | return 0; |
317 | } | |
318 | ||
ebb945a9 BS |
319 | int |
320 | nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend) | |
56ac7475 | 321 | { |
ebb945a9 BS |
322 | struct nv50_fifo_priv *priv = (void *)object->engine; |
323 | struct nv50_fifo_chan *chan = (void *)object; | |
324 | u32 chid = chan->base.chid; | |
325 | ||
326 | /* remove channel from playlist, fifo will unload context */ | |
327 | nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000); | |
328 | nv50_fifo_playlist_update(priv); | |
329 | nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000); | |
330 | ||
331 | return nouveau_fifo_channel_fini(&chan->base, suspend); | |
56ac7475 | 332 | } |
c420b2dc | 333 | |
ebb945a9 | 334 | static struct nouveau_ofuncs |
368be5f1 BS |
335 | nv50_fifo_ofuncs_dma = { |
336 | .ctor = nv50_fifo_chan_ctor_dma, | |
337 | .dtor = nv50_fifo_chan_dtor, | |
338 | .init = nv50_fifo_chan_init, | |
339 | .fini = nv50_fifo_chan_fini, | |
340 | .rd32 = _nouveau_fifo_channel_rd32, | |
341 | .wr32 = _nouveau_fifo_channel_wr32, | |
342 | }; | |
343 | ||
344 | static struct nouveau_ofuncs | |
345 | nv50_fifo_ofuncs_ind = { | |
346 | .ctor = nv50_fifo_chan_ctor_ind, | |
ebb945a9 BS |
347 | .dtor = nv50_fifo_chan_dtor, |
348 | .init = nv50_fifo_chan_init, | |
349 | .fini = nv50_fifo_chan_fini, | |
350 | .rd32 = _nouveau_fifo_channel_rd32, | |
351 | .wr32 = _nouveau_fifo_channel_wr32, | |
352 | }; | |
353 | ||
354 | static struct nouveau_oclass | |
355 | nv50_fifo_sclass[] = { | |
c97f8c92 BS |
356 | { NV50_CHANNEL_DMA_CLASS, &nv50_fifo_ofuncs_dma }, |
357 | { NV50_CHANNEL_IND_CLASS, &nv50_fifo_ofuncs_ind }, | |
ebb945a9 BS |
358 | {} |
359 | }; | |
360 | ||
361 | /******************************************************************************* | |
362 | * FIFO context - basically just the instmem reserved for the channel | |
363 | ******************************************************************************/ | |
364 | ||
365 | static int | |
366 | nv50_fifo_context_ctor(struct nouveau_object *parent, | |
367 | struct nouveau_object *engine, | |
368 | struct nouveau_oclass *oclass, void *data, u32 size, | |
369 | struct nouveau_object **pobject) | |
c420b2dc | 370 | { |
ebb945a9 BS |
371 | struct nv50_fifo_base *base; |
372 | int ret; | |
c420b2dc | 373 | |
ebb945a9 BS |
374 | ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000, |
375 | 0x1000, NVOBJ_FLAG_HEAP, &base); | |
376 | *pobject = nv_object(base); | |
377 | if (ret) | |
378 | return ret; | |
c420b2dc | 379 | |
f50c8054 BS |
380 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200, |
381 | 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); | |
ebb945a9 BS |
382 | if (ret) |
383 | return ret; | |
384 | ||
f50c8054 | 385 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0, |
ebb945a9 BS |
386 | NVOBJ_FLAG_ZERO_ALLOC, &base->eng); |
387 | if (ret) | |
388 | return ret; | |
389 | ||
f50c8054 | 390 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0, |
ebb945a9 BS |
391 | &base->pgd); |
392 | if (ret) | |
393 | return ret; | |
394 | ||
395 | ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd); | |
396 | if (ret) | |
397 | return ret; | |
c420b2dc | 398 | |
ebb945a9 | 399 | return 0; |
c420b2dc BS |
400 | } |
401 | ||
ebb945a9 BS |
402 | void |
403 | nv50_fifo_context_dtor(struct nouveau_object *object) | |
404 | { | |
405 | struct nv50_fifo_base *base = (void *)object; | |
406 | nouveau_vm_ref(NULL, &base->vm, base->pgd); | |
407 | nouveau_gpuobj_ref(NULL, &base->pgd); | |
408 | nouveau_gpuobj_ref(NULL, &base->eng); | |
409 | nouveau_gpuobj_ref(NULL, &base->ramfc); | |
410 | nouveau_gpuobj_ref(NULL, &base->cache); | |
411 | nouveau_fifo_context_destroy(&base->base); | |
412 | } | |
413 | ||
414 | static struct nouveau_oclass | |
415 | nv50_fifo_cclass = { | |
416 | .handle = NV_ENGCTX(FIFO, 0x50), | |
417 | .ofuncs = &(struct nouveau_ofuncs) { | |
418 | .ctor = nv50_fifo_context_ctor, | |
419 | .dtor = nv50_fifo_context_dtor, | |
420 | .init = _nouveau_fifo_context_init, | |
421 | .fini = _nouveau_fifo_context_fini, | |
422 | .rd32 = _nouveau_fifo_context_rd32, | |
423 | .wr32 = _nouveau_fifo_context_wr32, | |
424 | }, | |
425 | }; | |
426 | ||
427 | /******************************************************************************* | |
428 | * PFIFO engine | |
429 | ******************************************************************************/ | |
430 | ||
431 | static int | |
432 | nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |
433 | struct nouveau_oclass *oclass, void *data, u32 size, | |
434 | struct nouveau_object **pobject) | |
c420b2dc | 435 | { |
c420b2dc BS |
436 | struct nv50_fifo_priv *priv; |
437 | int ret; | |
438 | ||
ebb945a9 BS |
439 | ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv); |
440 | *pobject = nv_object(priv); | |
c420b2dc | 441 | if (ret) |
ebb945a9 | 442 | return ret; |
c420b2dc | 443 | |
f50c8054 | 444 | ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, |
ebb945a9 | 445 | &priv->playlist[0]); |
c420b2dc | 446 | if (ret) |
ebb945a9 | 447 | return ret; |
c420b2dc | 448 | |
f50c8054 | 449 | ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, |
ebb945a9 | 450 | &priv->playlist[1]); |
c420b2dc | 451 | if (ret) |
ebb945a9 BS |
452 | return ret; |
453 | ||
454 | nv_subdev(priv)->unit = 0x00000100; | |
455 | nv_subdev(priv)->intr = nv04_fifo_intr; | |
456 | nv_engine(priv)->cclass = &nv50_fifo_cclass; | |
457 | nv_engine(priv)->sclass = nv50_fifo_sclass; | |
458 | return 0; | |
459 | } | |
460 | ||
461 | void | |
462 | nv50_fifo_dtor(struct nouveau_object *object) | |
463 | { | |
464 | struct nv50_fifo_priv *priv = (void *)object; | |
465 | ||
466 | nouveau_gpuobj_ref(NULL, &priv->playlist[1]); | |
467 | nouveau_gpuobj_ref(NULL, &priv->playlist[0]); | |
468 | ||
469 | nouveau_fifo_destroy(&priv->base); | |
c420b2dc | 470 | } |
ebb945a9 BS |
471 | |
472 | int | |
473 | nv50_fifo_init(struct nouveau_object *object) | |
474 | { | |
475 | struct nv50_fifo_priv *priv = (void *)object; | |
476 | int ret, i; | |
477 | ||
478 | ret = nouveau_fifo_init(&priv->base); | |
479 | if (ret) | |
480 | return ret; | |
481 | ||
482 | nv_mask(priv, 0x000200, 0x00000100, 0x00000000); | |
483 | nv_mask(priv, 0x000200, 0x00000100, 0x00000100); | |
484 | nv_wr32(priv, 0x00250c, 0x6f3cfc34); | |
485 | nv_wr32(priv, 0x002044, 0x01003fff); | |
486 | ||
487 | nv_wr32(priv, 0x002100, 0xffffffff); | |
750087f1 | 488 | nv_wr32(priv, 0x002140, 0xbfffffff); |
ebb945a9 BS |
489 | |
490 | for (i = 0; i < 128; i++) | |
491 | nv_wr32(priv, 0x002600 + (i * 4), 0x00000000); | |
492 | nv50_fifo_playlist_update(priv); | |
493 | ||
494 | nv_wr32(priv, 0x003200, 0x00000001); | |
495 | nv_wr32(priv, 0x003250, 0x00000001); | |
496 | nv_wr32(priv, 0x002500, 0x00000001); | |
497 | return 0; | |
498 | } | |
499 | ||
500 | struct nouveau_oclass | |
501 | nv50_fifo_oclass = { | |
502 | .handle = NV_ENGINE(FIFO, 0x50), | |
503 | .ofuncs = &(struct nouveau_ofuncs) { | |
504 | .ctor = nv50_fifo_ctor, | |
505 | .dtor = nv50_fifo_dtor, | |
506 | .init = nv50_fifo_init, | |
507 | .fini = _nouveau_fifo_fini, | |
508 | }, | |
509 | }; |