Commit | Line | Data |
---|---|---|
4b223eef | 1 | /* |
ebb945a9 | 2 | * Copyright 2012 Red Hat Inc. |
4b223eef BS |
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 | ||
02a841d4 BS |
25 | #include "nvc0.h" |
26 | #include "fuc/hubnvc0.fuc.h" | |
27 | #include "fuc/gpcnvc0.fuc.h" | |
0411de85 | 28 | |
ebb945a9 BS |
29 | /******************************************************************************* |
30 | * Graphics object classes | |
31 | ******************************************************************************/ | |
32 | ||
33 | static struct nouveau_oclass | |
34 | nvc0_graph_sclass[] = { | |
35 | { 0x902d, &nouveau_object_ofuncs }, | |
36 | { 0x9039, &nouveau_object_ofuncs }, | |
37 | { 0x9097, &nouveau_object_ofuncs }, | |
38 | { 0x90c0, &nouveau_object_ofuncs }, | |
39 | {} | |
40 | }; | |
41 | ||
42 | static struct nouveau_oclass | |
43 | nvc1_graph_sclass[] = { | |
44 | { 0x902d, &nouveau_object_ofuncs }, | |
45 | { 0x9039, &nouveau_object_ofuncs }, | |
46 | { 0x9097, &nouveau_object_ofuncs }, | |
47 | { 0x90c0, &nouveau_object_ofuncs }, | |
48 | { 0x9197, &nouveau_object_ofuncs }, | |
49 | {} | |
50 | }; | |
51 | ||
52 | static struct nouveau_oclass | |
53 | nvc8_graph_sclass[] = { | |
54 | { 0x902d, &nouveau_object_ofuncs }, | |
55 | { 0x9039, &nouveau_object_ofuncs }, | |
56 | { 0x9097, &nouveau_object_ofuncs }, | |
57 | { 0x90c0, &nouveau_object_ofuncs }, | |
58 | { 0x9197, &nouveau_object_ofuncs }, | |
59 | { 0x9297, &nouveau_object_ofuncs }, | |
60 | {} | |
61 | }; | |
62 | ||
63 | /******************************************************************************* | |
64 | * PGRAPH context | |
65 | ******************************************************************************/ | |
966a5b7d | 66 | |
ac1499d9 | 67 | int |
ebb945a9 BS |
68 | nvc0_graph_context_ctor(struct nouveau_object *parent, |
69 | struct nouveau_object *engine, | |
70 | struct nouveau_oclass *oclass, void *args, u32 size, | |
71 | struct nouveau_object **pobject) | |
966a5b7d | 72 | { |
ebb945a9 BS |
73 | struct nouveau_vm *vm = nouveau_client(parent)->vm; |
74 | struct nvc0_graph_priv *priv = (void *)engine; | |
ac1499d9 BS |
75 | struct nvc0_graph_data *data = priv->mmio_data; |
76 | struct nvc0_graph_mmio *mmio = priv->mmio_list; | |
ebb945a9 | 77 | struct nvc0_graph_chan *chan; |
966a5b7d | 78 | int ret, i; |
966a5b7d | 79 | |
ebb945a9 BS |
80 | /* allocate memory for context, and fill with default values */ |
81 | ret = nouveau_graph_context_create(parent, engine, oclass, NULL, | |
82 | priv->size, 0x100, | |
83 | NVOBJ_FLAG_ZERO_ALLOC, &chan); | |
84 | *pobject = nv_object(chan); | |
966a5b7d BS |
85 | if (ret) |
86 | return ret; | |
87 | ||
ac1499d9 BS |
88 | /* allocate memory for a "mmio list" buffer that's used by the HUB |
89 | * fuc to modify some per-context register settings on first load | |
90 | * of the context. | |
91 | */ | |
ebb945a9 | 92 | ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 0x100, 0, &chan->mmio); |
73a60c0d BS |
93 | if (ret) |
94 | return ret; | |
95 | ||
ebb945a9 | 96 | ret = nouveau_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm, |
3863c9bc | 97 | NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, |
ebb945a9 | 98 | &chan->mmio_vma); |
73a60c0d BS |
99 | if (ret) |
100 | return ret; | |
101 | ||
ac1499d9 BS |
102 | /* allocate buffers referenced by mmio list */ |
103 | for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) { | |
ebb945a9 BS |
104 | ret = nouveau_gpuobj_new(parent, NULL, data->size, data->align, |
105 | 0, &chan->data[i].mem); | |
ac1499d9 BS |
106 | if (ret) |
107 | return ret; | |
73a60c0d | 108 | |
ebb945a9 BS |
109 | ret = nouveau_gpuobj_map_vm(chan->data[i].mem, vm, data->access, |
110 | &chan->data[i].vma); | |
ac1499d9 BS |
111 | if (ret) |
112 | return ret; | |
966a5b7d | 113 | |
ac1499d9 | 114 | data++; |
966a5b7d BS |
115 | } |
116 | ||
ac1499d9 BS |
117 | /* finally, fill in the mmio list and point the context at it */ |
118 | for (i = 0; mmio->addr && i < ARRAY_SIZE(priv->mmio_list); i++) { | |
119 | u32 addr = mmio->addr; | |
120 | u32 data = mmio->data; | |
966a5b7d | 121 | |
ac1499d9 | 122 | if (mmio->shift) { |
ebb945a9 | 123 | u64 info = chan->data[mmio->buffer].vma.offset; |
ac1499d9 BS |
124 | data |= info >> mmio->shift; |
125 | } | |
73a60c0d | 126 | |
ebb945a9 BS |
127 | nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); |
128 | nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data); | |
ac1499d9 BS |
129 | mmio++; |
130 | } | |
73a60c0d | 131 | |
ac1499d9 | 132 | for (i = 0; i < priv->size; i += 4) |
ebb945a9 | 133 | nv_wo32(chan, i, priv->data[i / 4]); |
966a5b7d | 134 | |
ac1499d9 | 135 | if (!priv->firmware) { |
ebb945a9 BS |
136 | nv_wo32(chan, 0x00, chan->mmio_nr / 2); |
137 | nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8); | |
0411de85 | 138 | } else { |
ebb945a9 BS |
139 | nv_wo32(chan, 0xf4, 0); |
140 | nv_wo32(chan, 0xf8, 0); | |
141 | nv_wo32(chan, 0x10, chan->mmio_nr / 2); | |
142 | nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset)); | |
143 | nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset)); | |
144 | nv_wo32(chan, 0x1c, 1); | |
145 | nv_wo32(chan, 0x20, 0); | |
146 | nv_wo32(chan, 0x28, 0); | |
147 | nv_wo32(chan, 0x2c, 0); | |
0411de85 | 148 | } |
966a5b7d | 149 | |
ebb945a9 | 150 | return 0; |
4b223eef BS |
151 | } |
152 | ||
ac1499d9 | 153 | void |
ebb945a9 | 154 | nvc0_graph_context_dtor(struct nouveau_object *object) |
4b223eef | 155 | { |
ebb945a9 | 156 | struct nvc0_graph_chan *chan = (void *)object; |
ac1499d9 BS |
157 | int i; |
158 | ||
ebb945a9 BS |
159 | for (i = 0; i < ARRAY_SIZE(chan->data); i++) { |
160 | nouveau_gpuobj_unmap(&chan->data[i].vma); | |
161 | nouveau_gpuobj_ref(NULL, &chan->data[i].mem); | |
ac1499d9 | 162 | } |
966a5b7d | 163 | |
ebb945a9 BS |
164 | nouveau_gpuobj_unmap(&chan->mmio_vma); |
165 | nouveau_gpuobj_ref(NULL, &chan->mmio); | |
ac1499d9 | 166 | |
ebb945a9 | 167 | nouveau_graph_context_destroy(&chan->base); |
4b223eef BS |
168 | } |
169 | ||
ebb945a9 BS |
170 | static struct nouveau_oclass |
171 | nvc0_graph_cclass = { | |
172 | .ofuncs = &(struct nouveau_ofuncs) { | |
173 | .ctor = nvc0_graph_context_ctor, | |
174 | .dtor = nvc0_graph_context_dtor, | |
175 | .init = _nouveau_graph_context_init, | |
176 | .fini = _nouveau_graph_context_fini, | |
177 | .rd32 = _nouveau_graph_context_rd32, | |
178 | .wr32 = _nouveau_graph_context_wr32, | |
179 | }, | |
180 | }; | |
181 | ||
182 | /******************************************************************************* | |
183 | * PGRAPH engine/subdev functions | |
184 | ******************************************************************************/ | |
185 | ||
186 | static void | |
187 | nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base) | |
4b223eef | 188 | { |
ebb945a9 BS |
189 | nv_error(priv, "%06x - done 0x%08x\n", base, |
190 | nv_rd32(priv, base + 0x400)); | |
191 | nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, | |
192 | nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804), | |
193 | nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c)); | |
194 | nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, | |
195 | nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814), | |
196 | nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c)); | |
197 | } | |
198 | ||
199 | void | |
200 | nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv) | |
201 | { | |
202 | u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff; | |
203 | u32 gpc; | |
204 | ||
205 | nvc0_graph_ctxctl_debug_unit(priv, 0x409000); | |
206 | for (gpc = 0; gpc < gpcnr; gpc++) | |
207 | nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000)); | |
208 | } | |
209 | ||
210 | static void | |
211 | nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv) | |
212 | { | |
213 | u32 ustat = nv_rd32(priv, 0x409c18); | |
214 | ||
215 | if (ustat & 0x00000001) | |
216 | nv_error(priv, "CTXCTRL ucode error\n"); | |
217 | if (ustat & 0x00080000) | |
218 | nv_error(priv, "CTXCTRL watchdog timeout\n"); | |
219 | if (ustat & ~0x00080001) | |
220 | nv_error(priv, "CTXCTRL 0x%08x\n", ustat); | |
221 | ||
222 | nvc0_graph_ctxctl_debug(priv); | |
223 | nv_wr32(priv, 0x409c20, ustat); | |
224 | } | |
225 | ||
f73221e4 BS |
226 | static void |
227 | nvc0_graph_trap_tpc(struct nvc0_graph_priv *priv, int gpc, int tpc) | |
228 | { | |
229 | u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0508)); | |
230 | ||
231 | if (stat & 0x00000001) { | |
232 | u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224)); | |
233 | nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap); | |
234 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); | |
235 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000001); | |
236 | stat &= ~0x00000001; | |
237 | } | |
238 | ||
239 | if (stat & 0x00000002) { | |
240 | u32 trap0 = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0644)); | |
241 | u32 trap1 = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x064c)); | |
242 | nv_error(priv, "GPC%d/TPC%d/MP: 0x%08x 0x%08x\n", | |
243 | gpc, tpc, trap0, trap1); | |
244 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0644), 0x001ffffe); | |
245 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x064c), 0x0000000f); | |
246 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000002); | |
247 | stat &= ~0x00000002; | |
248 | } | |
249 | ||
250 | if (stat & 0x00000004) { | |
251 | u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084)); | |
252 | nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap); | |
253 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); | |
254 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000004); | |
255 | stat &= ~0x00000004; | |
256 | } | |
257 | ||
258 | if (stat & 0x00000008) { | |
259 | u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c)); | |
260 | nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap); | |
261 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); | |
262 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000008); | |
263 | stat &= ~0x00000008; | |
264 | } | |
265 | ||
266 | if (stat) { | |
267 | nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat); | |
268 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), stat); | |
269 | } | |
270 | } | |
271 | ||
272 | static void | |
273 | nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc) | |
274 | { | |
275 | u32 stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90)); | |
276 | int tpc; | |
277 | ||
278 | if (stat & 0x00000001) { | |
279 | u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0420)); | |
280 | nv_error(priv, "GPC%d/PROP: 0x%08x\n", gpc, trap); | |
281 | nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); | |
282 | nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000001); | |
283 | stat &= ~0x00000001; | |
284 | } | |
285 | ||
286 | if (stat & 0x00000002) { | |
287 | u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900)); | |
288 | nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap); | |
289 | nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); | |
290 | nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000002); | |
291 | stat &= ~0x00000002; | |
292 | } | |
293 | ||
294 | if (stat & 0x00000004) { | |
295 | u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028)); | |
296 | nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap); | |
297 | nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); | |
298 | nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000004); | |
299 | stat &= ~0x00000004; | |
300 | } | |
301 | ||
302 | if (stat & 0x00000008) { | |
303 | u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824)); | |
304 | nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap); | |
305 | nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); | |
306 | nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000008); | |
307 | stat &= ~0x00000009; | |
308 | } | |
309 | ||
310 | for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { | |
311 | u32 mask = 0x00010000 << tpc; | |
312 | if (stat & mask) { | |
313 | nvc0_graph_trap_tpc(priv, gpc, tpc); | |
314 | nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), mask); | |
315 | stat &= ~mask; | |
316 | } | |
317 | } | |
318 | ||
319 | if (stat) { | |
320 | nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat); | |
321 | nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), stat); | |
322 | } | |
323 | } | |
324 | ||
325 | static void | |
326 | nvc0_graph_trap_intr(struct nvc0_graph_priv *priv) | |
327 | { | |
328 | u32 trap = nv_rd32(priv, 0x400108); | |
329 | int rop, gpc; | |
330 | ||
331 | if (trap & 0x00000001) { | |
332 | u32 stat = nv_rd32(priv, 0x404000); | |
333 | nv_error(priv, "DISPATCH 0x%08x\n", stat); | |
334 | nv_wr32(priv, 0x404000, 0xc0000000); | |
335 | nv_wr32(priv, 0x400108, 0x00000001); | |
336 | trap &= ~0x00000001; | |
337 | } | |
338 | ||
339 | if (trap & 0x00000002) { | |
340 | u32 stat = nv_rd32(priv, 0x404600); | |
341 | nv_error(priv, "M2MF 0x%08x\n", stat); | |
342 | nv_wr32(priv, 0x404600, 0xc0000000); | |
343 | nv_wr32(priv, 0x400108, 0x00000002); | |
344 | trap &= ~0x00000002; | |
345 | } | |
346 | ||
347 | if (trap & 0x00000008) { | |
348 | u32 stat = nv_rd32(priv, 0x408030); | |
349 | nv_error(priv, "CCACHE 0x%08x\n", stat); | |
350 | nv_wr32(priv, 0x408030, 0xc0000000); | |
351 | nv_wr32(priv, 0x400108, 0x00000008); | |
352 | trap &= ~0x00000008; | |
353 | } | |
354 | ||
355 | if (trap & 0x00000010) { | |
356 | u32 stat = nv_rd32(priv, 0x405840); | |
357 | nv_error(priv, "SHADER 0x%08x\n", stat); | |
358 | nv_wr32(priv, 0x405840, 0xc0000000); | |
359 | nv_wr32(priv, 0x400108, 0x00000010); | |
360 | trap &= ~0x00000010; | |
361 | } | |
362 | ||
363 | if (trap & 0x00000040) { | |
364 | u32 stat = nv_rd32(priv, 0x40601c); | |
365 | nv_error(priv, "UNK6 0x%08x\n", stat); | |
366 | nv_wr32(priv, 0x40601c, 0xc0000000); | |
367 | nv_wr32(priv, 0x400108, 0x00000040); | |
368 | trap &= ~0x00000040; | |
369 | } | |
370 | ||
371 | if (trap & 0x00000080) { | |
372 | u32 stat = nv_rd32(priv, 0x404490); | |
373 | nv_error(priv, "MACRO 0x%08x\n", stat); | |
374 | nv_wr32(priv, 0x404490, 0xc0000000); | |
375 | nv_wr32(priv, 0x400108, 0x00000080); | |
376 | trap &= ~0x00000080; | |
377 | } | |
378 | ||
379 | if (trap & 0x01000000) { | |
380 | u32 stat = nv_rd32(priv, 0x400118); | |
381 | for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) { | |
382 | u32 mask = 0x00000001 << gpc; | |
383 | if (stat & mask) { | |
384 | nvc0_graph_trap_gpc(priv, gpc); | |
385 | nv_wr32(priv, 0x400118, mask); | |
386 | stat &= ~mask; | |
387 | } | |
388 | } | |
389 | nv_wr32(priv, 0x400108, 0x01000000); | |
390 | trap &= ~0x01000000; | |
391 | } | |
392 | ||
393 | if (trap & 0x02000000) { | |
394 | for (rop = 0; rop < priv->rop_nr; rop++) { | |
395 | u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070)); | |
396 | u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144)); | |
397 | nv_error(priv, "ROP%d 0x%08x 0x%08x\n", | |
398 | rop, statz, statc); | |
399 | nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); | |
400 | nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); | |
401 | } | |
402 | nv_wr32(priv, 0x400108, 0x02000000); | |
403 | trap &= ~0x02000000; | |
404 | } | |
405 | ||
406 | if (trap) { | |
407 | nv_error(priv, "TRAP UNHANDLED 0x%08x\n", trap); | |
408 | nv_wr32(priv, 0x400108, trap); | |
409 | } | |
410 | } | |
411 | ||
ebb945a9 BS |
412 | static void |
413 | nvc0_graph_intr(struct nouveau_subdev *subdev) | |
414 | { | |
72a14827 | 415 | struct nouveau_fifo *pfifo = nouveau_fifo(subdev); |
ebb945a9 | 416 | struct nouveau_engine *engine = nv_engine(subdev); |
72a14827 BS |
417 | struct nouveau_object *engctx; |
418 | struct nouveau_handle *handle; | |
419 | struct nvc0_graph_priv *priv = (void *)subdev; | |
420 | u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff; | |
ebb945a9 BS |
421 | u32 stat = nv_rd32(priv, 0x400100); |
422 | u32 addr = nv_rd32(priv, 0x400704); | |
423 | u32 mthd = (addr & 0x00003ffc); | |
424 | u32 subc = (addr & 0x00070000) >> 16; | |
425 | u32 data = nv_rd32(priv, 0x400708); | |
426 | u32 code = nv_rd32(priv, 0x400110); | |
427 | u32 class = nv_rd32(priv, 0x404200 + (subc * 4)); | |
72a14827 BS |
428 | int chid; |
429 | ||
430 | engctx = nouveau_engctx_get(engine, inst); | |
431 | chid = pfifo->chid(pfifo, engctx); | |
ebb945a9 BS |
432 | |
433 | if (stat & 0x00000010) { | |
72a14827 | 434 | handle = nouveau_handle_get_class(engctx, class); |
ebb945a9 | 435 | if (!handle || nv_call(handle->object, mthd, data)) { |
93260d3c MS |
436 | nv_error(priv, |
437 | "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", | |
438 | chid, inst << 12, nouveau_client_name(engctx), | |
439 | subc, class, mthd, data); | |
ebb945a9 | 440 | } |
72a14827 | 441 | nouveau_handle_put(handle); |
ebb945a9 BS |
442 | nv_wr32(priv, 0x400100, 0x00000010); |
443 | stat &= ~0x00000010; | |
444 | } | |
445 | ||
446 | if (stat & 0x00000020) { | |
93260d3c MS |
447 | nv_error(priv, |
448 | "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", | |
449 | chid, inst << 12, nouveau_client_name(engctx), subc, | |
450 | class, mthd, data); | |
ebb945a9 BS |
451 | nv_wr32(priv, 0x400100, 0x00000020); |
452 | stat &= ~0x00000020; | |
453 | } | |
454 | ||
455 | if (stat & 0x00100000) { | |
456 | nv_error(priv, "DATA_ERROR ["); | |
457 | nouveau_enum_print(nv50_data_error_names, code); | |
93260d3c MS |
458 | pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", |
459 | chid, inst << 12, nouveau_client_name(engctx), subc, | |
460 | class, mthd, data); | |
ebb945a9 BS |
461 | nv_wr32(priv, 0x400100, 0x00100000); |
462 | stat &= ~0x00100000; | |
463 | } | |
464 | ||
465 | if (stat & 0x00200000) { | |
93260d3c MS |
466 | nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12, |
467 | nouveau_client_name(engctx)); | |
f73221e4 | 468 | nvc0_graph_trap_intr(priv); |
ebb945a9 BS |
469 | nv_wr32(priv, 0x400100, 0x00200000); |
470 | stat &= ~0x00200000; | |
471 | } | |
472 | ||
473 | if (stat & 0x00080000) { | |
474 | nvc0_graph_ctxctl_isr(priv); | |
475 | nv_wr32(priv, 0x400100, 0x00080000); | |
476 | stat &= ~0x00080000; | |
477 | } | |
478 | ||
479 | if (stat) { | |
480 | nv_error(priv, "unknown stat 0x%08x\n", stat); | |
481 | nv_wr32(priv, 0x400100, stat); | |
482 | } | |
483 | ||
484 | nv_wr32(priv, 0x400500, 0x00010001); | |
72a14827 | 485 | nouveau_engctx_put(engctx); |
ebb945a9 BS |
486 | } |
487 | ||
488 | int | |
489 | nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname, | |
490 | struct nvc0_graph_fuc *fuc) | |
491 | { | |
492 | struct nouveau_device *device = nv_device(priv); | |
493 | const struct firmware *fw; | |
494 | char f[32]; | |
495 | int ret; | |
496 | ||
497 | snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname); | |
498 | ret = request_firmware(&fw, f, &device->pdev->dev); | |
499 | if (ret) { | |
500 | snprintf(f, sizeof(f), "nouveau/%s", fwname); | |
501 | ret = request_firmware(&fw, f, &device->pdev->dev); | |
502 | if (ret) { | |
503 | nv_error(priv, "failed to load %s\n", fwname); | |
504 | return ret; | |
505 | } | |
506 | } | |
507 | ||
508 | fuc->size = fw->size; | |
509 | fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); | |
510 | release_firmware(fw); | |
511 | return (fuc->data != NULL) ? 0 : -ENOMEM; | |
966a5b7d BS |
512 | } |
513 | ||
514 | static int | |
ebb945a9 BS |
515 | nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, |
516 | struct nouveau_oclass *oclass, void *data, u32 size, | |
517 | struct nouveau_object **pobject) | |
966a5b7d | 518 | { |
ebb945a9 BS |
519 | struct nouveau_device *device = nv_device(parent); |
520 | struct nvc0_graph_priv *priv; | |
ebb945a9 BS |
521 | int ret, i; |
522 | ||
90253069 | 523 | ret = nouveau_graph_create(parent, engine, oclass, true, &priv); |
ebb945a9 BS |
524 | *pobject = nv_object(priv); |
525 | if (ret) | |
526 | return ret; | |
527 | ||
528 | nv_subdev(priv)->unit = 0x18001000; | |
529 | nv_subdev(priv)->intr = nvc0_graph_intr; | |
530 | nv_engine(priv)->cclass = &nvc0_graph_cclass; | |
531 | ||
532 | if (nouveau_boolopt(device->cfgopt, "NvGrUseFW", false)) { | |
533 | nv_info(priv, "using external firmware\n"); | |
534 | if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) || | |
535 | nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) || | |
536 | nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) || | |
537 | nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad)) | |
538 | return -EINVAL; | |
539 | priv->firmware = true; | |
540 | } | |
541 | ||
542 | switch (nvc0_graph_class(priv)) { | |
543 | case 0x9097: | |
544 | nv_engine(priv)->sclass = nvc0_graph_sclass; | |
545 | break; | |
546 | case 0x9197: | |
547 | nv_engine(priv)->sclass = nvc1_graph_sclass; | |
548 | break; | |
549 | case 0x9297: | |
550 | nv_engine(priv)->sclass = nvc8_graph_sclass; | |
551 | break; | |
552 | } | |
553 | ||
554 | ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4); | |
555 | if (ret) | |
556 | return ret; | |
557 | ||
558 | ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8); | |
559 | if (ret) | |
560 | return ret; | |
561 | ||
562 | for (i = 0; i < 0x1000; i += 4) { | |
563 | nv_wo32(priv->unk4188b4, i, 0x00000010); | |
564 | nv_wo32(priv->unk4188b8, i, 0x00000010); | |
565 | } | |
566 | ||
567 | priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16; | |
568 | priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f; | |
569 | for (i = 0; i < priv->gpc_nr; i++) { | |
570 | priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608)); | |
571 | priv->tpc_total += priv->tpc_nr[i]; | |
572 | } | |
573 | ||
574 | /*XXX: these need figuring out... though it might not even matter */ | |
575 | switch (nv_device(priv)->chipset) { | |
576 | case 0xc0: | |
577 | if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ | |
578 | priv->magic_not_rop_nr = 0x07; | |
579 | } else | |
580 | if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ | |
581 | priv->magic_not_rop_nr = 0x05; | |
582 | } else | |
583 | if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ | |
584 | priv->magic_not_rop_nr = 0x06; | |
585 | } | |
586 | break; | |
587 | case 0xc3: /* 450, 4/0/0/0, 2 */ | |
588 | priv->magic_not_rop_nr = 0x03; | |
589 | break; | |
590 | case 0xc4: /* 460, 3/4/0/0, 4 */ | |
591 | priv->magic_not_rop_nr = 0x01; | |
592 | break; | |
593 | case 0xc1: /* 2/0/0/0, 1 */ | |
594 | priv->magic_not_rop_nr = 0x01; | |
595 | break; | |
596 | case 0xc8: /* 4/4/3/4, 5 */ | |
597 | priv->magic_not_rop_nr = 0x06; | |
598 | break; | |
599 | case 0xce: /* 4/4/0/0, 4 */ | |
600 | priv->magic_not_rop_nr = 0x03; | |
601 | break; | |
602 | case 0xcf: /* 4/0/0/0, 3 */ | |
603 | priv->magic_not_rop_nr = 0x03; | |
604 | break; | |
605 | case 0xd9: /* 1/0/0/0, 1 */ | |
606 | priv->magic_not_rop_nr = 0x01; | |
607 | break; | |
608 | } | |
609 | ||
4b223eef BS |
610 | return 0; |
611 | } | |
612 | ||
966a5b7d | 613 | static void |
ebb945a9 BS |
614 | nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc) |
615 | { | |
fd69aee4 MS |
616 | kfree(fuc->data); |
617 | fuc->data = NULL; | |
ebb945a9 BS |
618 | } |
619 | ||
620 | void | |
621 | nvc0_graph_dtor(struct nouveau_object *object) | |
622 | { | |
623 | struct nvc0_graph_priv *priv = (void *)object; | |
624 | ||
fd69aee4 | 625 | kfree(priv->data); |
ebb945a9 BS |
626 | |
627 | nvc0_graph_dtor_fw(&priv->fuc409c); | |
628 | nvc0_graph_dtor_fw(&priv->fuc409d); | |
629 | nvc0_graph_dtor_fw(&priv->fuc41ac); | |
630 | nvc0_graph_dtor_fw(&priv->fuc41ad); | |
631 | ||
632 | nouveau_gpuobj_ref(NULL, &priv->unk4188b8); | |
633 | nouveau_gpuobj_ref(NULL, &priv->unk4188b4); | |
634 | ||
635 | nouveau_graph_destroy(&priv->base); | |
636 | } | |
637 | ||
638 | static void | |
639 | nvc0_graph_init_obj418880(struct nvc0_graph_priv *priv) | |
966a5b7d | 640 | { |
966a5b7d BS |
641 | int i; |
642 | ||
ebb945a9 BS |
643 | nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); |
644 | nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); | |
966a5b7d | 645 | for (i = 0; i < 4; i++) |
ebb945a9 BS |
646 | nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000); |
647 | nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); | |
648 | nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); | |
966a5b7d BS |
649 | } |
650 | ||
651 | static void | |
ebb945a9 | 652 | nvc0_graph_init_regs(struct nvc0_graph_priv *priv) |
966a5b7d | 653 | { |
ebb945a9 BS |
654 | nv_wr32(priv, 0x400080, 0x003083c2); |
655 | nv_wr32(priv, 0x400088, 0x00006fe7); | |
656 | nv_wr32(priv, 0x40008c, 0x00000000); | |
657 | nv_wr32(priv, 0x400090, 0x00000030); | |
658 | nv_wr32(priv, 0x40013c, 0x013901f7); | |
659 | nv_wr32(priv, 0x400140, 0x00000100); | |
660 | nv_wr32(priv, 0x400144, 0x00000000); | |
661 | nv_wr32(priv, 0x400148, 0x00000110); | |
662 | nv_wr32(priv, 0x400138, 0x00000000); | |
663 | nv_wr32(priv, 0x400130, 0x00000000); | |
664 | nv_wr32(priv, 0x400134, 0x00000000); | |
665 | nv_wr32(priv, 0x400124, 0x00000002); | |
966a5b7d BS |
666 | } |
667 | ||
668 | static void | |
ebb945a9 | 669 | nvc0_graph_init_gpc_0(struct nvc0_graph_priv *priv) |
966a5b7d | 670 | { |
c4afbe74 BS |
671 | const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); |
672 | u32 data[TPC_MAX / 8]; | |
ebb945a9 | 673 | u8 tpcnr[GPC_MAX]; |
aa58c405 | 674 | int i, gpc, tpc; |
f212949c | 675 | |
ebb945a9 | 676 | nv_wr32(priv, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */ |
ffe2dee4 | 677 | |
f212949c EV |
678 | /* |
679 | * TP ROP UNKVAL(magic_not_rop_nr) | |
680 | * 450: 4/0/0/0 2 3 | |
681 | * 460: 3/4/0/0 4 1 | |
682 | * 465: 3/4/4/0 4 7 | |
683 | * 470: 3/3/4/4 5 5 | |
684 | * 480: 3/4/4/4 6 6 | |
f212949c EV |
685 | */ |
686 | ||
aa58c405 | 687 | memset(data, 0x00, sizeof(data)); |
ebb945a9 | 688 | memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); |
c4afbe74 | 689 | for (i = 0, gpc = -1; i < priv->tpc_total; i++) { |
aa58c405 BS |
690 | do { |
691 | gpc = (gpc + 1) % priv->gpc_nr; | |
ebb945a9 BS |
692 | } while (!tpcnr[gpc]); |
693 | tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; | |
aa58c405 BS |
694 | |
695 | data[i / 8] |= tpc << ((i % 8) * 4); | |
696 | } | |
697 | ||
ebb945a9 BS |
698 | nv_wr32(priv, GPC_BCAST(0x0980), data[0]); |
699 | nv_wr32(priv, GPC_BCAST(0x0984), data[1]); | |
700 | nv_wr32(priv, GPC_BCAST(0x0988), data[2]); | |
701 | nv_wr32(priv, GPC_BCAST(0x098c), data[3]); | |
966a5b7d BS |
702 | |
703 | for (gpc = 0; gpc < priv->gpc_nr; gpc++) { | |
ebb945a9 | 704 | nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | |
c4afbe74 | 705 | priv->tpc_nr[gpc]); |
ebb945a9 BS |
706 | nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total); |
707 | nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); | |
966a5b7d BS |
708 | } |
709 | ||
ebb945a9 BS |
710 | nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918); |
711 | nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); | |
966a5b7d BS |
712 | } |
713 | ||
714 | static void | |
ebb945a9 | 715 | nvc0_graph_init_units(struct nvc0_graph_priv *priv) |
966a5b7d | 716 | { |
ebb945a9 BS |
717 | nv_wr32(priv, 0x409c24, 0x000f0000); |
718 | nv_wr32(priv, 0x404000, 0xc0000000); /* DISPATCH */ | |
719 | nv_wr32(priv, 0x404600, 0xc0000000); /* M2MF */ | |
720 | nv_wr32(priv, 0x408030, 0xc0000000); | |
721 | nv_wr32(priv, 0x40601c, 0xc0000000); | |
722 | nv_wr32(priv, 0x404490, 0xc0000000); /* MACRO */ | |
723 | nv_wr32(priv, 0x406018, 0xc0000000); | |
724 | nv_wr32(priv, 0x405840, 0xc0000000); | |
725 | nv_wr32(priv, 0x405844, 0x00ffffff); | |
726 | nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); | |
727 | nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000); | |
966a5b7d BS |
728 | } |
729 | ||
730 | static void | |
ebb945a9 | 731 | nvc0_graph_init_gpc_1(struct nvc0_graph_priv *priv) |
966a5b7d | 732 | { |
ebb945a9 | 733 | int gpc, tpc; |
966a5b7d BS |
734 | |
735 | for (gpc = 0; gpc < priv->gpc_nr; gpc++) { | |
ebb945a9 BS |
736 | nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); |
737 | nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); | |
738 | nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); | |
739 | nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); | |
740 | for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { | |
741 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); | |
742 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); | |
743 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); | |
744 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); | |
745 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); | |
746 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); | |
747 | nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); | |
966a5b7d | 748 | } |
ebb945a9 BS |
749 | nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); |
750 | nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); | |
966a5b7d BS |
751 | } |
752 | } | |
753 | ||
754 | static void | |
ebb945a9 | 755 | nvc0_graph_init_rop(struct nvc0_graph_priv *priv) |
966a5b7d | 756 | { |
966a5b7d BS |
757 | int rop; |
758 | ||
759 | for (rop = 0; rop < priv->rop_nr; rop++) { | |
ebb945a9 BS |
760 | nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); |
761 | nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); | |
762 | nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); | |
763 | nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); | |
966a5b7d BS |
764 | } |
765 | } | |
766 | ||
ebb945a9 BS |
767 | void |
768 | nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base, | |
769 | struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data) | |
966a5b7d | 770 | { |
fe799114 | 771 | int i; |
966a5b7d | 772 | |
ebb945a9 | 773 | nv_wr32(priv, fuc_base + 0x01c0, 0x01000000); |
fe799114 | 774 | for (i = 0; i < data->size / 4; i++) |
ebb945a9 | 775 | nv_wr32(priv, fuc_base + 0x01c4, data->data[i]); |
966a5b7d | 776 | |
ebb945a9 | 777 | nv_wr32(priv, fuc_base + 0x0180, 0x01000000); |
fe799114 | 778 | for (i = 0; i < code->size / 4; i++) { |
966a5b7d | 779 | if ((i & 0x3f) == 0) |
ebb945a9 BS |
780 | nv_wr32(priv, fuc_base + 0x0188, i >> 6); |
781 | nv_wr32(priv, fuc_base + 0x0184, code->data[i]); | |
966a5b7d | 782 | } |
966a5b7d BS |
783 | } |
784 | ||
785 | static int | |
ebb945a9 | 786 | nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) |
966a5b7d | 787 | { |
966a5b7d | 788 | u32 r000260; |
0411de85 BS |
789 | int i; |
790 | ||
ac1499d9 BS |
791 | if (priv->firmware) { |
792 | /* load fuc microcode */ | |
ebb945a9 BS |
793 | r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000); |
794 | nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, | |
ac1499d9 | 795 | &priv->fuc409d); |
ebb945a9 | 796 | nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, |
ac1499d9 | 797 | &priv->fuc41ad); |
ebb945a9 | 798 | nv_wr32(priv, 0x000260, r000260); |
0411de85 | 799 | |
ac1499d9 | 800 | /* start both of them running */ |
ebb945a9 BS |
801 | nv_wr32(priv, 0x409840, 0xffffffff); |
802 | nv_wr32(priv, 0x41a10c, 0x00000000); | |
803 | nv_wr32(priv, 0x40910c, 0x00000000); | |
804 | nv_wr32(priv, 0x41a100, 0x00000002); | |
805 | nv_wr32(priv, 0x409100, 0x00000002); | |
806 | if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001)) | |
ae4ba737 | 807 | nv_warn(priv, "0x409800 wait failed\n"); |
ebb945a9 BS |
808 | |
809 | nv_wr32(priv, 0x409840, 0xffffffff); | |
810 | nv_wr32(priv, 0x409500, 0x7fffffff); | |
811 | nv_wr32(priv, 0x409504, 0x00000021); | |
812 | ||
813 | nv_wr32(priv, 0x409840, 0xffffffff); | |
814 | nv_wr32(priv, 0x409500, 0x00000000); | |
815 | nv_wr32(priv, 0x409504, 0x00000010); | |
816 | if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { | |
817 | nv_error(priv, "fuc09 req 0x10 timeout\n"); | |
0411de85 BS |
818 | return -EBUSY; |
819 | } | |
ebb945a9 | 820 | priv->size = nv_rd32(priv, 0x409800); |
0411de85 | 821 | |
ebb945a9 BS |
822 | nv_wr32(priv, 0x409840, 0xffffffff); |
823 | nv_wr32(priv, 0x409500, 0x00000000); | |
824 | nv_wr32(priv, 0x409504, 0x00000016); | |
825 | if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { | |
826 | nv_error(priv, "fuc09 req 0x16 timeout\n"); | |
ac1499d9 BS |
827 | return -EBUSY; |
828 | } | |
829 | ||
ebb945a9 BS |
830 | nv_wr32(priv, 0x409840, 0xffffffff); |
831 | nv_wr32(priv, 0x409500, 0x00000000); | |
832 | nv_wr32(priv, 0x409504, 0x00000025); | |
833 | if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { | |
834 | nv_error(priv, "fuc09 req 0x25 timeout\n"); | |
ac1499d9 BS |
835 | return -EBUSY; |
836 | } | |
837 | ||
ebb945a9 BS |
838 | if (priv->data == NULL) { |
839 | int ret = nvc0_grctx_generate(priv); | |
840 | if (ret) { | |
841 | nv_error(priv, "failed to construct context\n"); | |
842 | return ret; | |
843 | } | |
844 | } | |
845 | ||
846 | return 0; | |
0411de85 | 847 | } |
966a5b7d | 848 | |
ac1499d9 | 849 | /* load HUB microcode */ |
ebb945a9 BS |
850 | r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000); |
851 | nv_wr32(priv, 0x4091c0, 0x01000000); | |
ac1499d9 | 852 | for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++) |
ebb945a9 | 853 | nv_wr32(priv, 0x4091c4, nvc0_grhub_data[i]); |
ac1499d9 | 854 | |
ebb945a9 | 855 | nv_wr32(priv, 0x409180, 0x01000000); |
ac1499d9 BS |
856 | for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) { |
857 | if ((i & 0x3f) == 0) | |
ebb945a9 BS |
858 | nv_wr32(priv, 0x409188, i >> 6); |
859 | nv_wr32(priv, 0x409184, nvc0_grhub_code[i]); | |
ac1499d9 BS |
860 | } |
861 | ||
862 | /* load GPC microcode */ | |
ebb945a9 | 863 | nv_wr32(priv, 0x41a1c0, 0x01000000); |
ac1499d9 | 864 | for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++) |
ebb945a9 | 865 | nv_wr32(priv, 0x41a1c4, nvc0_grgpc_data[i]); |
ac1499d9 | 866 | |
ebb945a9 | 867 | nv_wr32(priv, 0x41a180, 0x01000000); |
ac1499d9 BS |
868 | for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) { |
869 | if ((i & 0x3f) == 0) | |
ebb945a9 BS |
870 | nv_wr32(priv, 0x41a188, i >> 6); |
871 | nv_wr32(priv, 0x41a184, nvc0_grgpc_code[i]); | |
ac1499d9 | 872 | } |
ebb945a9 | 873 | nv_wr32(priv, 0x000260, r000260); |
966a5b7d | 874 | |
ac1499d9 | 875 | /* start HUB ucode running, it'll init the GPCs */ |
ebb945a9 BS |
876 | nv_wr32(priv, 0x409800, nv_device(priv)->chipset); |
877 | nv_wr32(priv, 0x40910c, 0x00000000); | |
878 | nv_wr32(priv, 0x409100, 0x00000002); | |
879 | if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) { | |
880 | nv_error(priv, "HUB_INIT timed out\n"); | |
881 | nvc0_graph_ctxctl_debug(priv); | |
966a5b7d BS |
882 | return -EBUSY; |
883 | } | |
966a5b7d | 884 | |
ebb945a9 | 885 | priv->size = nv_rd32(priv, 0x409804); |
ac1499d9 | 886 | if (priv->data == NULL) { |
ebb945a9 | 887 | int ret = nvc0_grctx_generate(priv); |
ac1499d9 | 888 | if (ret) { |
ebb945a9 | 889 | nv_error(priv, "failed to construct context\n"); |
ac1499d9 BS |
890 | return ret; |
891 | } | |
966a5b7d BS |
892 | } |
893 | ||
894 | return 0; | |
4b223eef BS |
895 | } |
896 | ||
7a45cd19 | 897 | static int |
ebb945a9 | 898 | nvc0_graph_init(struct nouveau_object *object) |
4b223eef | 899 | { |
ebb945a9 | 900 | struct nvc0_graph_priv *priv = (void *)object; |
966a5b7d BS |
901 | int ret; |
902 | ||
ebb945a9 BS |
903 | ret = nouveau_graph_init(&priv->base); |
904 | if (ret) | |
905 | return ret; | |
906 | ||
907 | nvc0_graph_init_obj418880(priv); | |
908 | nvc0_graph_init_regs(priv); | |
909 | /*nvc0_graph_init_unitplemented_magics(priv);*/ | |
910 | nvc0_graph_init_gpc_0(priv); | |
911 | /*nvc0_graph_init_unitplemented_c242(priv);*/ | |
912 | ||
913 | nv_wr32(priv, 0x400500, 0x00010001); | |
914 | nv_wr32(priv, 0x400100, 0xffffffff); | |
915 | nv_wr32(priv, 0x40013c, 0xffffffff); | |
916 | ||
917 | nvc0_graph_init_units(priv); | |
918 | nvc0_graph_init_gpc_1(priv); | |
919 | nvc0_graph_init_rop(priv); | |
920 | ||
921 | nv_wr32(priv, 0x400108, 0xffffffff); | |
922 | nv_wr32(priv, 0x400138, 0xffffffff); | |
923 | nv_wr32(priv, 0x400118, 0xffffffff); | |
924 | nv_wr32(priv, 0x400130, 0xffffffff); | |
925 | nv_wr32(priv, 0x40011c, 0xffffffff); | |
926 | nv_wr32(priv, 0x400134, 0xffffffff); | |
927 | nv_wr32(priv, 0x400054, 0x34ce3464); | |
928 | ||
929 | ret = nvc0_graph_init_ctxctl(priv); | |
b10f20d5 | 930 | if (ret) |
a82dd49f BS |
931 | return ret; |
932 | ||
4b223eef BS |
933 | return 0; |
934 | } | |
935 | ||
ebb945a9 BS |
936 | struct nouveau_oclass |
937 | nvc0_graph_oclass = { | |
938 | .handle = NV_ENGINE(GR, 0xc0), | |
939 | .ofuncs = &(struct nouveau_ofuncs) { | |
940 | .ctor = nvc0_graph_ctor, | |
941 | .dtor = nvc0_graph_dtor, | |
942 | .init = nvc0_graph_init, | |
943 | .fini = _nouveau_graph_fini, | |
944 | }, | |
945 | }; |