Commit | Line | Data |
---|---|---|
c420b2dc | 1 | /* |
ebb945a9 | 2 | * Copyright 2012 Red Hat Inc. |
c420b2dc | 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: | |
c420b2dc | 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. | |
c420b2dc | 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. | |
c420b2dc | 21 | * |
ebb945a9 | 22 | * Authors: Ben Skeggs |
c420b2dc BS |
23 | */ |
24 | ||
ebb945a9 BS |
25 | #include <core/os.h> |
26 | #include <core/client.h> | |
27 | #include <core/engctx.h> | |
02a841d4 | 28 | #include <core/ramht.h> |
ebb945a9 BS |
29 | #include <core/class.h> |
30 | #include <core/math.h> | |
c420b2dc | 31 | |
ebb945a9 BS |
32 | #include <subdev/timer.h> |
33 | #include <subdev/bar.h> | |
c420b2dc | 34 | |
ebb945a9 BS |
35 | #include <engine/dmaobj.h> |
36 | #include <engine/fifo.h> | |
37 | ||
38 | #include "nv50.h" | |
39 | ||
40 | /******************************************************************************* | |
41 | * FIFO channel objects | |
42 | ******************************************************************************/ | |
c420b2dc BS |
43 | |
44 | static int | |
ebb945a9 BS |
45 | nv84_fifo_context_attach(struct nouveau_object *parent, |
46 | struct nouveau_object *object) | |
c420b2dc | 47 | { |
ebb945a9 BS |
48 | struct nouveau_bar *bar = nouveau_bar(parent); |
49 | struct nv50_fifo_base *base = (void *)parent->parent; | |
50 | struct nouveau_gpuobj *ectx = (void *)object; | |
51 | u64 limit = ectx->addr + ectx->size - 1; | |
52 | u64 start = ectx->addr; | |
53 | u32 addr; | |
54 | ||
55 | switch (nv_engidx(object->engine)) { | |
56 | case NVDEV_ENGINE_SW : return 0; | |
57 | case NVDEV_ENGINE_GR : addr = 0x0020; break; | |
58 | case NVDEV_ENGINE_MPEG : addr = 0x0060; break; | |
59 | case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break; | |
60 | case NVDEV_ENGINE_COPY0: addr = 0x00c0; break; | |
61 | default: | |
62 | return -EINVAL; | |
63 | } | |
c420b2dc | 64 | |
ebb945a9 BS |
65 | nv_wo32(base->eng, addr + 0x00, 0x00190000); |
66 | nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); | |
67 | nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); | |
68 | nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | | |
69 | upper_32_bits(start)); | |
70 | nv_wo32(base->eng, addr + 0x10, 0x00000000); | |
71 | nv_wo32(base->eng, addr + 0x14, 0x00000000); | |
72 | bar->flush(bar); | |
73 | return 0; | |
74 | } | |
c420b2dc | 75 | |
ebb945a9 BS |
76 | static int |
77 | nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend, | |
78 | struct nouveau_object *object) | |
79 | { | |
80 | struct nouveau_bar *bar = nouveau_bar(parent); | |
81 | struct nv50_fifo_priv *priv = (void *)parent->engine; | |
82 | struct nv50_fifo_base *base = (void *)parent->parent; | |
83 | struct nv50_fifo_chan *chan = (void *)parent; | |
84 | u32 addr; | |
85 | ||
86 | switch (nv_engidx(object->engine)) { | |
87 | case NVDEV_ENGINE_SW : return 0; | |
88 | case NVDEV_ENGINE_GR : addr = 0x0020; break; | |
89 | case NVDEV_ENGINE_MPEG : addr = 0x0060; break; | |
90 | case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break; | |
91 | case NVDEV_ENGINE_COPY0: addr = 0x00c0; break; | |
92 | default: | |
93 | return -EINVAL; | |
c420b2dc BS |
94 | } |
95 | ||
ebb945a9 BS |
96 | nv_wo32(base->eng, addr + 0x00, 0x00000000); |
97 | nv_wo32(base->eng, addr + 0x04, 0x00000000); | |
98 | nv_wo32(base->eng, addr + 0x08, 0x00000000); | |
99 | nv_wo32(base->eng, addr + 0x0c, 0x00000000); | |
100 | nv_wo32(base->eng, addr + 0x10, 0x00000000); | |
101 | nv_wo32(base->eng, addr + 0x14, 0x00000000); | |
102 | bar->flush(bar); | |
103 | ||
104 | nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); | |
105 | if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { | |
106 | nv_error(priv, "channel %d unload timeout\n", chan->base.chid); | |
107 | if (suspend) | |
108 | return -EBUSY; | |
109 | } | |
110 | return 0; | |
111 | } | |
c420b2dc | 112 | |
ebb945a9 BS |
113 | static int |
114 | nv84_fifo_object_attach(struct nouveau_object *parent, | |
115 | struct nouveau_object *object, u32 handle) | |
116 | { | |
117 | struct nv50_fifo_chan *chan = (void *)parent; | |
118 | u32 context; | |
119 | ||
120 | if (nv_iclass(object, NV_GPUOBJ_CLASS)) | |
121 | context = nv_gpuobj(object)->node->offset >> 4; | |
122 | else | |
123 | context = 0x00000004; /* just non-zero */ | |
124 | ||
125 | switch (nv_engidx(object->engine)) { | |
126 | case NVDEV_ENGINE_DMAOBJ: | |
127 | case NVDEV_ENGINE_SW : context |= 0x00000000; break; | |
128 | case NVDEV_ENGINE_GR : context |= 0x00100000; break; | |
129 | case NVDEV_ENGINE_MPEG : | |
130 | case NVDEV_ENGINE_PPP : context |= 0x00200000; break; | |
131 | case NVDEV_ENGINE_ME : | |
132 | case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break; | |
133 | case NVDEV_ENGINE_VP : context |= 0x00400000; break; | |
134 | case NVDEV_ENGINE_CRYPT : | |
135 | case NVDEV_ENGINE_UNK1C1: context |= 0x00500000; break; | |
136 | case NVDEV_ENGINE_BSP : context |= 0x00600000; break; | |
137 | default: | |
138 | return -EINVAL; | |
139 | } | |
c420b2dc | 140 | |
ebb945a9 BS |
141 | return nouveau_ramht_insert(chan->ramht, 0, handle, context); |
142 | } | |
c420b2dc | 143 | |
ebb945a9 BS |
144 | static int |
145 | nv84_fifo_chan_ctor(struct nouveau_object *parent, | |
146 | struct nouveau_object *engine, | |
147 | struct nouveau_oclass *oclass, void *data, u32 size, | |
148 | struct nouveau_object **pobject) | |
149 | { | |
150 | struct nouveau_bar *bar = nouveau_bar(parent); | |
151 | struct nv50_fifo_base *base = (void *)parent; | |
152 | struct nv50_fifo_chan *chan; | |
153 | struct nv_channel_ind_class *args = data; | |
154 | u64 ioffset, ilength; | |
155 | int ret; | |
c420b2dc | 156 | |
ebb945a9 BS |
157 | if (size < sizeof(*args)) |
158 | return -EINVAL; | |
159 | ||
160 | ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, | |
161 | 0x2000, args->pushbuf, | |
162 | (1 << NVDEV_ENGINE_DMAOBJ) | | |
163 | (1 << NVDEV_ENGINE_SW) | | |
164 | (1 << NVDEV_ENGINE_GR) | | |
165 | (1 << NVDEV_ENGINE_MPEG) | | |
166 | (1 << NVDEV_ENGINE_ME) | | |
167 | (1 << NVDEV_ENGINE_VP) | | |
168 | (1 << NVDEV_ENGINE_CRYPT) | | |
169 | (1 << NVDEV_ENGINE_BSP) | | |
170 | (1 << NVDEV_ENGINE_PPP) | | |
171 | (1 << NVDEV_ENGINE_COPY0) | | |
172 | (1 << NVDEV_ENGINE_UNK1C1), &chan); | |
173 | *pobject = nv_object(chan); | |
174 | if (ret) | |
175 | return ret; | |
c420b2dc | 176 | |
ebb945a9 | 177 | ret = nouveau_ramht_new(parent, parent, 0x8000, 16, &chan->ramht); |
c420b2dc | 178 | if (ret) |
ebb945a9 BS |
179 | return ret; |
180 | ||
181 | nv_parent(chan)->context_attach = nv84_fifo_context_attach; | |
182 | nv_parent(chan)->context_detach = nv84_fifo_context_detach; | |
183 | nv_parent(chan)->object_attach = nv84_fifo_object_attach; | |
184 | nv_parent(chan)->object_detach = nv50_fifo_object_detach; | |
185 | ||
186 | ioffset = args->ioffset; | |
187 | ilength = log2i(args->ilength / 8); | |
188 | ||
189 | nv_wo32(base->ramfc, 0x3c, 0x403f6078); | |
190 | nv_wo32(base->ramfc, 0x44, 0x01003fff); | |
191 | nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); | |
192 | nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); | |
193 | nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); | |
194 | nv_wo32(base->ramfc, 0x60, 0x7fffffff); | |
195 | nv_wo32(base->ramfc, 0x78, 0x00000000); | |
196 | nv_wo32(base->ramfc, 0x7c, 0x30000001); | |
197 | nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | | |
198 | (4 << 24) /* SEARCH_FULL */ | | |
199 | (chan->ramht->base.node->offset >> 4)); | |
200 | nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10); | |
201 | nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); | |
202 | bar->flush(bar); | |
203 | return 0; | |
c420b2dc BS |
204 | } |
205 | ||
ebb945a9 BS |
206 | static int |
207 | nv84_fifo_chan_init(struct nouveau_object *object) | |
c420b2dc | 208 | { |
ebb945a9 BS |
209 | struct nv50_fifo_priv *priv = (void *)object->engine; |
210 | struct nv50_fifo_base *base = (void *)object->parent; | |
211 | struct nv50_fifo_chan *chan = (void *)object; | |
212 | struct nouveau_gpuobj *ramfc = base->ramfc; | |
213 | u32 chid = chan->base.chid; | |
214 | int ret; | |
215 | ||
216 | ret = nouveau_fifo_channel_init(&chan->base); | |
217 | if (ret) | |
218 | return ret; | |
c420b2dc | 219 | |
ebb945a9 BS |
220 | nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); |
221 | nv50_fifo_playlist_update(priv); | |
222 | return 0; | |
223 | } | |
c420b2dc | 224 | |
ebb945a9 BS |
225 | static struct nouveau_ofuncs |
226 | nv84_fifo_ofuncs = { | |
227 | .ctor = nv84_fifo_chan_ctor, | |
228 | .dtor = nv50_fifo_chan_dtor, | |
229 | .init = nv84_fifo_chan_init, | |
230 | .fini = nv50_fifo_chan_fini, | |
231 | .rd32 = _nouveau_fifo_channel_rd32, | |
232 | .wr32 = _nouveau_fifo_channel_wr32, | |
233 | }; | |
2064db72 | 234 | |
ebb945a9 BS |
235 | static struct nouveau_oclass |
236 | nv84_fifo_sclass[] = { | |
237 | { 0x826f, &nv84_fifo_ofuncs }, | |
238 | {} | |
239 | }; | |
c420b2dc | 240 | |
ebb945a9 BS |
241 | /******************************************************************************* |
242 | * FIFO context - basically just the instmem reserved for the channel | |
243 | ******************************************************************************/ | |
2064db72 | 244 | |
ebb945a9 BS |
245 | int |
246 | nv84_fifo_context_ctor(struct nouveau_object *parent, | |
247 | struct nouveau_object *engine, | |
248 | struct nouveau_oclass *oclass, void *data, u32 size, | |
249 | struct nouveau_object **pobject) | |
250 | { | |
251 | struct nv50_fifo_base *base; | |
252 | int ret; | |
c420b2dc | 253 | |
ebb945a9 BS |
254 | ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000, |
255 | 0x1000, NVOBJ_FLAG_HEAP, &base); | |
256 | *pobject = nv_object(base); | |
257 | if (ret) | |
258 | return ret; | |
c420b2dc | 259 | |
ebb945a9 BS |
260 | ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0200, 0, |
261 | NVOBJ_FLAG_ZERO_ALLOC, &base->eng); | |
262 | if (ret) | |
263 | return ret; | |
c420b2dc | 264 | |
ebb945a9 BS |
265 | ret = nouveau_gpuobj_new(parent, nv_object(base), 0x4000, 0, |
266 | 0, &base->pgd); | |
267 | if (ret) | |
268 | return ret; | |
c420b2dc | 269 | |
ebb945a9 BS |
270 | ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd); |
271 | if (ret) | |
272 | return ret; | |
c420b2dc | 273 | |
ebb945a9 BS |
274 | ret = nouveau_gpuobj_new(parent, nv_object(base), 0x1000, 0x400, |
275 | NVOBJ_FLAG_ZERO_ALLOC, &base->cache); | |
276 | if (ret) | |
277 | return ret; | |
278 | ||
279 | ret = nouveau_gpuobj_new(parent, nv_object(base), 0x0100, 0x100, | |
280 | NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); | |
281 | if (ret) | |
282 | return ret; | |
c420b2dc | 283 | |
c420b2dc BS |
284 | return 0; |
285 | } | |
286 | ||
ebb945a9 BS |
287 | static struct nouveau_oclass |
288 | nv84_fifo_cclass = { | |
289 | .handle = NV_ENGCTX(FIFO, 0x84), | |
290 | .ofuncs = &(struct nouveau_ofuncs) { | |
291 | .ctor = nv84_fifo_context_ctor, | |
292 | .dtor = nv50_fifo_context_dtor, | |
293 | .init = _nouveau_fifo_context_init, | |
294 | .fini = _nouveau_fifo_context_fini, | |
295 | .rd32 = _nouveau_fifo_context_rd32, | |
296 | .wr32 = _nouveau_fifo_context_wr32, | |
297 | }, | |
298 | }; | |
c420b2dc | 299 | |
ebb945a9 BS |
300 | /******************************************************************************* |
301 | * PFIFO engine | |
302 | ******************************************************************************/ | |
c420b2dc | 303 | |
ebb945a9 BS |
304 | static int |
305 | nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |
306 | struct nouveau_oclass *oclass, void *data, u32 size, | |
307 | struct nouveau_object **pobject) | |
c420b2dc | 308 | { |
ebb945a9 | 309 | struct nv50_fifo_priv *priv; |
c420b2dc BS |
310 | int ret; |
311 | ||
ebb945a9 BS |
312 | ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv); |
313 | *pobject = nv_object(priv); | |
c420b2dc | 314 | if (ret) |
ebb945a9 | 315 | return ret; |
c420b2dc | 316 | |
ebb945a9 BS |
317 | ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, |
318 | &priv->playlist[0]); | |
c420b2dc | 319 | if (ret) |
ebb945a9 | 320 | return ret; |
c420b2dc | 321 | |
ebb945a9 BS |
322 | ret = nouveau_gpuobj_new(parent, NULL, 128 * 4, 0x1000, 0, |
323 | &priv->playlist[1]); | |
c420b2dc | 324 | if (ret) |
ebb945a9 BS |
325 | return ret; |
326 | ||
327 | nv_subdev(priv)->unit = 0x00000100; | |
328 | nv_subdev(priv)->intr = nv04_fifo_intr; | |
329 | nv_engine(priv)->cclass = &nv84_fifo_cclass; | |
330 | nv_engine(priv)->sclass = nv84_fifo_sclass; | |
331 | return 0; | |
c420b2dc | 332 | } |
ebb945a9 BS |
333 | |
334 | struct nouveau_oclass | |
335 | nv84_fifo_oclass = { | |
336 | .handle = NV_ENGINE(FIFO, 0x84), | |
337 | .ofuncs = &(struct nouveau_ofuncs) { | |
338 | .ctor = nv84_fifo_ctor, | |
339 | .dtor = nv50_fifo_dtor, | |
340 | .init = nv50_fifo_init, | |
341 | .fini = _nouveau_fifo_fini, | |
342 | }, | |
343 | }; |