1 | /* $NetBSD: nouveau_engine_fifo_nv84.c,v 1.1.1.1 2014/08/06 12:36:24 riastradh Exp $ */ |
2 | |
3 | /* |
4 | * Copyright 2012 Red Hat Inc. |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
7 | * copy of this software and associated documentation files (the "Software"), |
8 | * to deal in the Software without restriction, including without limitation |
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
10 | * and/or sell copies of the Software, and to permit persons to whom the |
11 | * Software is furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
22 | * OTHER DEALINGS IN THE SOFTWARE. |
23 | * |
24 | * Authors: Ben Skeggs |
25 | */ |
26 | |
27 | #include <sys/cdefs.h> |
28 | __KERNEL_RCSID(0, "$NetBSD: nouveau_engine_fifo_nv84.c,v 1.1.1.1 2014/08/06 12:36:24 riastradh Exp $" ); |
29 | |
30 | #include <core/os.h> |
31 | #include <core/client.h> |
32 | #include <core/engctx.h> |
33 | #include <core/ramht.h> |
34 | #include <core/event.h> |
35 | #include <core/class.h> |
36 | |
37 | #include <subdev/timer.h> |
38 | #include <subdev/bar.h> |
39 | |
40 | #include <engine/dmaobj.h> |
41 | #include <engine/fifo.h> |
42 | |
43 | #include "nv04.h" |
44 | #include "nv50.h" |
45 | |
46 | /******************************************************************************* |
47 | * FIFO channel objects |
48 | ******************************************************************************/ |
49 | |
50 | static int |
51 | nv84_fifo_context_attach(struct nouveau_object *parent, |
52 | struct nouveau_object *object) |
53 | { |
54 | struct nouveau_bar *bar = nouveau_bar(parent); |
55 | struct nv50_fifo_base *base = (void *)parent->parent; |
56 | struct nouveau_gpuobj *ectx = (void *)object; |
57 | u64 limit = ectx->addr + ectx->size - 1; |
58 | u64 start = ectx->addr; |
59 | u32 addr; |
60 | |
61 | switch (nv_engidx(object->engine)) { |
62 | case NVDEV_ENGINE_SW : return 0; |
63 | case NVDEV_ENGINE_GR : addr = 0x0020; break; |
64 | case NVDEV_ENGINE_VP : addr = 0x0040; break; |
65 | case NVDEV_ENGINE_PPP : |
66 | case NVDEV_ENGINE_MPEG : addr = 0x0060; break; |
67 | case NVDEV_ENGINE_BSP : addr = 0x0080; break; |
68 | case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break; |
69 | case NVDEV_ENGINE_COPY0: addr = 0x00c0; break; |
70 | default: |
71 | return -EINVAL; |
72 | } |
73 | |
74 | nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; |
75 | nv_wo32(base->eng, addr + 0x00, 0x00190000); |
76 | nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); |
77 | nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); |
78 | nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | |
79 | upper_32_bits(start)); |
80 | nv_wo32(base->eng, addr + 0x10, 0x00000000); |
81 | nv_wo32(base->eng, addr + 0x14, 0x00000000); |
82 | bar->flush(bar); |
83 | return 0; |
84 | } |
85 | |
86 | static int |
87 | nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend, |
88 | struct nouveau_object *object) |
89 | { |
90 | struct nouveau_bar *bar = nouveau_bar(parent); |
91 | struct nv50_fifo_priv *priv = (void *)parent->engine; |
92 | struct nv50_fifo_base *base = (void *)parent->parent; |
93 | struct nv50_fifo_chan *chan = (void *)parent; |
94 | u32 addr, save, engn; |
95 | bool done; |
96 | |
97 | switch (nv_engidx(object->engine)) { |
98 | case NVDEV_ENGINE_SW : return 0; |
99 | case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break; |
100 | case NVDEV_ENGINE_VP : engn = 3; addr = 0x0040; break; |
101 | case NVDEV_ENGINE_PPP : |
102 | case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break; |
103 | case NVDEV_ENGINE_BSP : engn = 5; addr = 0x0080; break; |
104 | case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break; |
105 | case NVDEV_ENGINE_COPY0: engn = 2; addr = 0x00c0; break; |
106 | default: |
107 | return -EINVAL; |
108 | } |
109 | |
110 | save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn); |
111 | nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); |
112 | done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff); |
113 | nv_wr32(priv, 0x002520, save); |
114 | if (!done) { |
115 | nv_error(priv, "channel %d [%s] unload timeout\n" , |
116 | chan->base.chid, nouveau_client_name(chan)); |
117 | if (suspend) |
118 | return -EBUSY; |
119 | } |
120 | |
121 | nv_wo32(base->eng, addr + 0x00, 0x00000000); |
122 | nv_wo32(base->eng, addr + 0x04, 0x00000000); |
123 | nv_wo32(base->eng, addr + 0x08, 0x00000000); |
124 | nv_wo32(base->eng, addr + 0x0c, 0x00000000); |
125 | nv_wo32(base->eng, addr + 0x10, 0x00000000); |
126 | nv_wo32(base->eng, addr + 0x14, 0x00000000); |
127 | bar->flush(bar); |
128 | return 0; |
129 | } |
130 | |
131 | static int |
132 | nv84_fifo_object_attach(struct nouveau_object *parent, |
133 | struct nouveau_object *object, u32 handle) |
134 | { |
135 | struct nv50_fifo_chan *chan = (void *)parent; |
136 | u32 context; |
137 | |
138 | if (nv_iclass(object, NV_GPUOBJ_CLASS)) |
139 | context = nv_gpuobj(object)->node->offset >> 4; |
140 | else |
141 | context = 0x00000004; /* just non-zero */ |
142 | |
143 | switch (nv_engidx(object->engine)) { |
144 | case NVDEV_ENGINE_DMAOBJ: |
145 | case NVDEV_ENGINE_SW : context |= 0x00000000; break; |
146 | case NVDEV_ENGINE_GR : context |= 0x00100000; break; |
147 | case NVDEV_ENGINE_MPEG : |
148 | case NVDEV_ENGINE_PPP : context |= 0x00200000; break; |
149 | case NVDEV_ENGINE_ME : |
150 | case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break; |
151 | case NVDEV_ENGINE_VP : context |= 0x00400000; break; |
152 | case NVDEV_ENGINE_CRYPT : |
153 | case NVDEV_ENGINE_VIC : context |= 0x00500000; break; |
154 | case NVDEV_ENGINE_BSP : context |= 0x00600000; break; |
155 | default: |
156 | return -EINVAL; |
157 | } |
158 | |
159 | return nouveau_ramht_insert(chan->ramht, 0, handle, context); |
160 | } |
161 | |
162 | static int |
163 | nv84_fifo_chan_ctor_dma(struct nouveau_object *parent, |
164 | struct nouveau_object *engine, |
165 | struct nouveau_oclass *oclass, void *data, u32 size, |
166 | struct nouveau_object **pobject) |
167 | { |
168 | struct nouveau_bar *bar = nouveau_bar(parent); |
169 | struct nv50_fifo_base *base = (void *)parent; |
170 | struct nv50_fifo_chan *chan; |
171 | struct nv03_channel_dma_class *args = data; |
172 | int ret; |
173 | |
174 | if (size < sizeof(*args)) |
175 | return -EINVAL; |
176 | |
177 | ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, |
178 | 0x2000, args->pushbuf, |
179 | (1ULL << NVDEV_ENGINE_DMAOBJ) | |
180 | (1ULL << NVDEV_ENGINE_SW) | |
181 | (1ULL << NVDEV_ENGINE_GR) | |
182 | (1ULL << NVDEV_ENGINE_MPEG) | |
183 | (1ULL << NVDEV_ENGINE_ME) | |
184 | (1ULL << NVDEV_ENGINE_VP) | |
185 | (1ULL << NVDEV_ENGINE_CRYPT) | |
186 | (1ULL << NVDEV_ENGINE_BSP) | |
187 | (1ULL << NVDEV_ENGINE_PPP) | |
188 | (1ULL << NVDEV_ENGINE_COPY0) | |
189 | (1ULL << NVDEV_ENGINE_VIC), &chan); |
190 | *pobject = nv_object(chan); |
191 | if (ret) |
192 | return ret; |
193 | |
194 | ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, |
195 | &chan->ramht); |
196 | if (ret) |
197 | return ret; |
198 | |
199 | nv_parent(chan)->context_attach = nv84_fifo_context_attach; |
200 | nv_parent(chan)->context_detach = nv84_fifo_context_detach; |
201 | nv_parent(chan)->object_attach = nv84_fifo_object_attach; |
202 | nv_parent(chan)->object_detach = nv50_fifo_object_detach; |
203 | |
204 | nv_wo32(base->ramfc, 0x08, lower_32_bits(args->offset)); |
205 | nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->offset)); |
206 | nv_wo32(base->ramfc, 0x10, lower_32_bits(args->offset)); |
207 | nv_wo32(base->ramfc, 0x14, upper_32_bits(args->offset)); |
208 | nv_wo32(base->ramfc, 0x3c, 0x003f6078); |
209 | nv_wo32(base->ramfc, 0x44, 0x01003fff); |
210 | nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); |
211 | nv_wo32(base->ramfc, 0x4c, 0xffffffff); |
212 | nv_wo32(base->ramfc, 0x60, 0x7fffffff); |
213 | nv_wo32(base->ramfc, 0x78, 0x00000000); |
214 | nv_wo32(base->ramfc, 0x7c, 0x30000001); |
215 | nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | |
216 | (4 << 24) /* SEARCH_FULL */ | |
217 | (chan->ramht->base.node->offset >> 4)); |
218 | nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10); |
219 | nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); |
220 | bar->flush(bar); |
221 | return 0; |
222 | } |
223 | |
224 | static int |
225 | nv84_fifo_chan_ctor_ind(struct nouveau_object *parent, |
226 | struct nouveau_object *engine, |
227 | struct nouveau_oclass *oclass, void *data, u32 size, |
228 | struct nouveau_object **pobject) |
229 | { |
230 | struct nouveau_bar *bar = nouveau_bar(parent); |
231 | struct nv50_fifo_base *base = (void *)parent; |
232 | struct nv50_fifo_chan *chan; |
233 | struct nv50_channel_ind_class *args = data; |
234 | u64 ioffset, ilength; |
235 | int ret; |
236 | |
237 | if (size < sizeof(*args)) |
238 | return -EINVAL; |
239 | |
240 | ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, |
241 | 0x2000, args->pushbuf, |
242 | (1ULL << NVDEV_ENGINE_DMAOBJ) | |
243 | (1ULL << NVDEV_ENGINE_SW) | |
244 | (1ULL << NVDEV_ENGINE_GR) | |
245 | (1ULL << NVDEV_ENGINE_MPEG) | |
246 | (1ULL << NVDEV_ENGINE_ME) | |
247 | (1ULL << NVDEV_ENGINE_VP) | |
248 | (1ULL << NVDEV_ENGINE_CRYPT) | |
249 | (1ULL << NVDEV_ENGINE_BSP) | |
250 | (1ULL << NVDEV_ENGINE_PPP) | |
251 | (1ULL << NVDEV_ENGINE_COPY0) | |
252 | (1ULL << NVDEV_ENGINE_VIC), &chan); |
253 | *pobject = nv_object(chan); |
254 | if (ret) |
255 | return ret; |
256 | |
257 | ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, |
258 | &chan->ramht); |
259 | if (ret) |
260 | return ret; |
261 | |
262 | nv_parent(chan)->context_attach = nv84_fifo_context_attach; |
263 | nv_parent(chan)->context_detach = nv84_fifo_context_detach; |
264 | nv_parent(chan)->object_attach = nv84_fifo_object_attach; |
265 | nv_parent(chan)->object_detach = nv50_fifo_object_detach; |
266 | |
267 | ioffset = args->ioffset; |
268 | ilength = order_base_2(args->ilength / 8); |
269 | |
270 | nv_wo32(base->ramfc, 0x3c, 0x403f6078); |
271 | nv_wo32(base->ramfc, 0x44, 0x01003fff); |
272 | nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); |
273 | nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); |
274 | nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); |
275 | nv_wo32(base->ramfc, 0x60, 0x7fffffff); |
276 | nv_wo32(base->ramfc, 0x78, 0x00000000); |
277 | nv_wo32(base->ramfc, 0x7c, 0x30000001); |
278 | nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | |
279 | (4 << 24) /* SEARCH_FULL */ | |
280 | (chan->ramht->base.node->offset >> 4)); |
281 | nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10); |
282 | nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); |
283 | bar->flush(bar); |
284 | return 0; |
285 | } |
286 | |
287 | static int |
288 | nv84_fifo_chan_init(struct nouveau_object *object) |
289 | { |
290 | struct nv50_fifo_priv *priv = (void *)object->engine; |
291 | struct nv50_fifo_base *base = (void *)object->parent; |
292 | struct nv50_fifo_chan *chan = (void *)object; |
293 | struct nouveau_gpuobj *ramfc = base->ramfc; |
294 | u32 chid = chan->base.chid; |
295 | int ret; |
296 | |
297 | ret = nouveau_fifo_channel_init(&chan->base); |
298 | if (ret) |
299 | return ret; |
300 | |
301 | nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); |
302 | nv50_fifo_playlist_update(priv); |
303 | return 0; |
304 | } |
305 | |
306 | static struct nouveau_ofuncs |
307 | nv84_fifo_ofuncs_dma = { |
308 | .ctor = nv84_fifo_chan_ctor_dma, |
309 | .dtor = nv50_fifo_chan_dtor, |
310 | .init = nv84_fifo_chan_init, |
311 | .fini = nv50_fifo_chan_fini, |
312 | .rd32 = _nouveau_fifo_channel_rd32, |
313 | .wr32 = _nouveau_fifo_channel_wr32, |
314 | }; |
315 | |
316 | static struct nouveau_ofuncs |
317 | nv84_fifo_ofuncs_ind = { |
318 | .ctor = nv84_fifo_chan_ctor_ind, |
319 | .dtor = nv50_fifo_chan_dtor, |
320 | .init = nv84_fifo_chan_init, |
321 | .fini = nv50_fifo_chan_fini, |
322 | .rd32 = _nouveau_fifo_channel_rd32, |
323 | .wr32 = _nouveau_fifo_channel_wr32, |
324 | }; |
325 | |
326 | static struct nouveau_oclass |
327 | nv84_fifo_sclass[] = { |
328 | { NV84_CHANNEL_DMA_CLASS, &nv84_fifo_ofuncs_dma }, |
329 | { NV84_CHANNEL_IND_CLASS, &nv84_fifo_ofuncs_ind }, |
330 | {} |
331 | }; |
332 | |
333 | /******************************************************************************* |
334 | * FIFO context - basically just the instmem reserved for the channel |
335 | ******************************************************************************/ |
336 | |
337 | static int |
338 | nv84_fifo_context_ctor(struct nouveau_object *parent, |
339 | struct nouveau_object *engine, |
340 | struct nouveau_oclass *oclass, void *data, u32 size, |
341 | struct nouveau_object **pobject) |
342 | { |
343 | struct nv50_fifo_base *base; |
344 | int ret; |
345 | |
346 | ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000, |
347 | 0x1000, NVOBJ_FLAG_HEAP, &base); |
348 | *pobject = nv_object(base); |
349 | if (ret) |
350 | return ret; |
351 | |
352 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200, 0, |
353 | NVOBJ_FLAG_ZERO_ALLOC, &base->eng); |
354 | if (ret) |
355 | return ret; |
356 | |
357 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, |
358 | 0, &base->pgd); |
359 | if (ret) |
360 | return ret; |
361 | |
362 | ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd); |
363 | if (ret) |
364 | return ret; |
365 | |
366 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1000, |
367 | 0x400, NVOBJ_FLAG_ZERO_ALLOC, &base->cache); |
368 | if (ret) |
369 | return ret; |
370 | |
371 | ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0100, |
372 | 0x100, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); |
373 | if (ret) |
374 | return ret; |
375 | |
376 | return 0; |
377 | } |
378 | |
379 | static struct nouveau_oclass |
380 | nv84_fifo_cclass = { |
381 | .handle = NV_ENGCTX(FIFO, 0x84), |
382 | .ofuncs = &(struct nouveau_ofuncs) { |
383 | .ctor = nv84_fifo_context_ctor, |
384 | .dtor = nv50_fifo_context_dtor, |
385 | .init = _nouveau_fifo_context_init, |
386 | .fini = _nouveau_fifo_context_fini, |
387 | .rd32 = _nouveau_fifo_context_rd32, |
388 | .wr32 = _nouveau_fifo_context_wr32, |
389 | }, |
390 | }; |
391 | |
392 | /******************************************************************************* |
393 | * PFIFO engine |
394 | ******************************************************************************/ |
395 | |
396 | static void |
397 | nv84_fifo_uevent_enable(struct nouveau_event *event, int index) |
398 | { |
399 | struct nv84_fifo_priv *priv = event->priv; |
400 | nv_mask(priv, 0x002140, 0x40000000, 0x40000000); |
401 | } |
402 | |
403 | static void |
404 | nv84_fifo_uevent_disable(struct nouveau_event *event, int index) |
405 | { |
406 | struct nv84_fifo_priv *priv = event->priv; |
407 | nv_mask(priv, 0x002140, 0x40000000, 0x00000000); |
408 | } |
409 | |
410 | static int |
411 | nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
412 | struct nouveau_oclass *oclass, void *data, u32 size, |
413 | struct nouveau_object **pobject) |
414 | { |
415 | struct nv50_fifo_priv *priv; |
416 | int ret; |
417 | |
418 | ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv); |
419 | *pobject = nv_object(priv); |
420 | if (ret) |
421 | return ret; |
422 | |
423 | ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, |
424 | &priv->playlist[0]); |
425 | if (ret) |
426 | return ret; |
427 | |
428 | ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, |
429 | &priv->playlist[1]); |
430 | if (ret) |
431 | return ret; |
432 | |
433 | priv->base.uevent->enable = nv84_fifo_uevent_enable; |
434 | priv->base.uevent->disable = nv84_fifo_uevent_disable; |
435 | priv->base.uevent->priv = priv; |
436 | |
437 | nv_subdev(priv)->unit = 0x00000100; |
438 | nv_subdev(priv)->intr = nv04_fifo_intr; |
439 | nv_engine(priv)->cclass = &nv84_fifo_cclass; |
440 | nv_engine(priv)->sclass = nv84_fifo_sclass; |
441 | priv->base.pause = nv04_fifo_pause; |
442 | priv->base.start = nv04_fifo_start; |
443 | return 0; |
444 | } |
445 | |
446 | struct nouveau_oclass * |
447 | nv84_fifo_oclass = &(struct nouveau_oclass) { |
448 | .handle = NV_ENGINE(FIFO, 0x84), |
449 | .ofuncs = &(struct nouveau_ofuncs) { |
450 | .ctor = nv84_fifo_ctor, |
451 | .dtor = nv50_fifo_dtor, |
452 | .init = nv50_fifo_init, |
453 | .fini = _nouveau_fifo_fini, |
454 | }, |
455 | }; |
456 | |