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 | */ | |
e3c71eb2 BS |
24 | #include "gf100.h" |
25 | #include "ctxgf100.h" | |
26 | #include "fuc/os.h" | |
27 | ||
28 | #include <core/client.h> | |
e3c71eb2 | 29 | #include <core/option.h> |
e3c71eb2 BS |
30 | #include <subdev/fb.h> |
31 | #include <subdev/mc.h> | |
32 | #include <subdev/timer.h> | |
a65955e1 | 33 | #include <engine/fifo.h> |
e3c71eb2 BS |
34 | |
35 | #include <nvif/class.h> | |
36 | #include <nvif/unpack.h> | |
0411de85 | 37 | |
ac9738bb BS |
38 | /******************************************************************************* |
39 | * Zero Bandwidth Clear | |
40 | ******************************************************************************/ | |
41 | ||
42 | static void | |
bfee3f3d | 43 | gf100_gr_zbc_clear_color(struct gf100_gr *gr, int zbc) |
ac9738bb | 44 | { |
276836d4 | 45 | struct nvkm_device *device = gr->base.engine.subdev.device; |
bfee3f3d | 46 | if (gr->zbc_color[zbc].format) { |
276836d4 BS |
47 | nvkm_wr32(device, 0x405804, gr->zbc_color[zbc].ds[0]); |
48 | nvkm_wr32(device, 0x405808, gr->zbc_color[zbc].ds[1]); | |
49 | nvkm_wr32(device, 0x40580c, gr->zbc_color[zbc].ds[2]); | |
50 | nvkm_wr32(device, 0x405810, gr->zbc_color[zbc].ds[3]); | |
51 | } | |
52 | nvkm_wr32(device, 0x405814, gr->zbc_color[zbc].format); | |
53 | nvkm_wr32(device, 0x405820, zbc); | |
54 | nvkm_wr32(device, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */ | |
ac9738bb BS |
55 | } |
56 | ||
57 | static int | |
bfee3f3d | 58 | gf100_gr_zbc_color_get(struct gf100_gr *gr, int format, |
e3c71eb2 | 59 | const u32 ds[4], const u32 l2[4]) |
ac9738bb | 60 | { |
bfee3f3d | 61 | struct nvkm_ltc *ltc = nvkm_ltc(gr); |
ac9738bb BS |
62 | int zbc = -ENOSPC, i; |
63 | ||
64 | for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { | |
bfee3f3d BS |
65 | if (gr->zbc_color[i].format) { |
66 | if (gr->zbc_color[i].format != format) | |
ac9738bb | 67 | continue; |
bfee3f3d BS |
68 | if (memcmp(gr->zbc_color[i].ds, ds, sizeof( |
69 | gr->zbc_color[i].ds))) | |
ac9738bb | 70 | continue; |
bfee3f3d BS |
71 | if (memcmp(gr->zbc_color[i].l2, l2, sizeof( |
72 | gr->zbc_color[i].l2))) { | |
ac9738bb BS |
73 | WARN_ON(1); |
74 | return -EINVAL; | |
75 | } | |
76 | return i; | |
77 | } else { | |
78 | zbc = (zbc < 0) ? i : zbc; | |
79 | } | |
80 | } | |
81 | ||
da7c74ea BS |
82 | if (zbc < 0) |
83 | return zbc; | |
84 | ||
bfee3f3d BS |
85 | memcpy(gr->zbc_color[zbc].ds, ds, sizeof(gr->zbc_color[zbc].ds)); |
86 | memcpy(gr->zbc_color[zbc].l2, l2, sizeof(gr->zbc_color[zbc].l2)); | |
87 | gr->zbc_color[zbc].format = format; | |
ac9738bb | 88 | ltc->zbc_color_get(ltc, zbc, l2); |
bfee3f3d | 89 | gf100_gr_zbc_clear_color(gr, zbc); |
ac9738bb BS |
90 | return zbc; |
91 | } | |
92 | ||
93 | static void | |
bfee3f3d | 94 | gf100_gr_zbc_clear_depth(struct gf100_gr *gr, int zbc) |
ac9738bb | 95 | { |
276836d4 | 96 | struct nvkm_device *device = gr->base.engine.subdev.device; |
bfee3f3d | 97 | if (gr->zbc_depth[zbc].format) |
276836d4 BS |
98 | nvkm_wr32(device, 0x405818, gr->zbc_depth[zbc].ds); |
99 | nvkm_wr32(device, 0x40581c, gr->zbc_depth[zbc].format); | |
100 | nvkm_wr32(device, 0x405820, zbc); | |
101 | nvkm_wr32(device, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */ | |
ac9738bb BS |
102 | } |
103 | ||
104 | static int | |
bfee3f3d | 105 | gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format, |
e3c71eb2 | 106 | const u32 ds, const u32 l2) |
ac9738bb | 107 | { |
bfee3f3d | 108 | struct nvkm_ltc *ltc = nvkm_ltc(gr); |
ac9738bb BS |
109 | int zbc = -ENOSPC, i; |
110 | ||
111 | for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { | |
bfee3f3d BS |
112 | if (gr->zbc_depth[i].format) { |
113 | if (gr->zbc_depth[i].format != format) | |
ac9738bb | 114 | continue; |
bfee3f3d | 115 | if (gr->zbc_depth[i].ds != ds) |
ac9738bb | 116 | continue; |
bfee3f3d | 117 | if (gr->zbc_depth[i].l2 != l2) { |
ac9738bb BS |
118 | WARN_ON(1); |
119 | return -EINVAL; | |
120 | } | |
121 | return i; | |
122 | } else { | |
123 | zbc = (zbc < 0) ? i : zbc; | |
124 | } | |
125 | } | |
126 | ||
da7c74ea BS |
127 | if (zbc < 0) |
128 | return zbc; | |
129 | ||
bfee3f3d BS |
130 | gr->zbc_depth[zbc].format = format; |
131 | gr->zbc_depth[zbc].ds = ds; | |
132 | gr->zbc_depth[zbc].l2 = l2; | |
ac9738bb | 133 | ltc->zbc_depth_get(ltc, zbc, l2); |
bfee3f3d | 134 | gf100_gr_zbc_clear_depth(gr, zbc); |
ac9738bb BS |
135 | return zbc; |
136 | } | |
137 | ||
ebb945a9 BS |
138 | /******************************************************************************* |
139 | * Graphics object classes | |
140 | ******************************************************************************/ | |
141 | ||
ac9738bb | 142 | static int |
e3c71eb2 | 143 | gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) |
ac9738bb | 144 | { |
bfee3f3d | 145 | struct gf100_gr *gr = (void *)object->engine; |
ac9738bb BS |
146 | union { |
147 | struct fermi_a_zbc_color_v0 v0; | |
148 | } *args = data; | |
149 | int ret; | |
150 | ||
151 | if (nvif_unpack(args->v0, 0, 0, false)) { | |
152 | switch (args->v0.format) { | |
153 | case FERMI_A_ZBC_COLOR_V0_FMT_ZERO: | |
154 | case FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE: | |
155 | case FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32: | |
156 | case FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16: | |
157 | case FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16: | |
158 | case FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16: | |
159 | case FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16: | |
160 | case FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16: | |
161 | case FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8: | |
162 | case FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8: | |
163 | case FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10: | |
164 | case FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10: | |
165 | case FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8: | |
166 | case FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8: | |
167 | case FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8: | |
168 | case FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8: | |
169 | case FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8: | |
170 | case FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10: | |
171 | case FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11: | |
bfee3f3d | 172 | ret = gf100_gr_zbc_color_get(gr, args->v0.format, |
e3c71eb2 BS |
173 | args->v0.ds, |
174 | args->v0.l2); | |
ac9738bb BS |
175 | if (ret >= 0) { |
176 | args->v0.index = ret; | |
177 | return 0; | |
178 | } | |
179 | break; | |
180 | default: | |
181 | return -EINVAL; | |
182 | } | |
183 | } | |
184 | ||
185 | return ret; | |
186 | } | |
187 | ||
188 | static int | |
e3c71eb2 | 189 | gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size) |
ac9738bb | 190 | { |
bfee3f3d | 191 | struct gf100_gr *gr = (void *)object->engine; |
ac9738bb BS |
192 | union { |
193 | struct fermi_a_zbc_depth_v0 v0; | |
194 | } *args = data; | |
195 | int ret; | |
196 | ||
197 | if (nvif_unpack(args->v0, 0, 0, false)) { | |
198 | switch (args->v0.format) { | |
199 | case FERMI_A_ZBC_DEPTH_V0_FMT_FP32: | |
bfee3f3d | 200 | ret = gf100_gr_zbc_depth_get(gr, args->v0.format, |
e3c71eb2 BS |
201 | args->v0.ds, |
202 | args->v0.l2); | |
ac9738bb BS |
203 | return (ret >= 0) ? 0 : -ENOSPC; |
204 | default: | |
205 | return -EINVAL; | |
206 | } | |
207 | } | |
208 | ||
209 | return ret; | |
210 | } | |
211 | ||
212 | static int | |
e3c71eb2 | 213 | gf100_fermi_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) |
ac9738bb BS |
214 | { |
215 | switch (mthd) { | |
216 | case FERMI_A_ZBC_COLOR: | |
e3c71eb2 | 217 | return gf100_fermi_mthd_zbc_color(object, data, size); |
ac9738bb | 218 | case FERMI_A_ZBC_DEPTH: |
e3c71eb2 | 219 | return gf100_fermi_mthd_zbc_depth(object, data, size); |
ac9738bb BS |
220 | default: |
221 | break; | |
222 | } | |
223 | return -EINVAL; | |
224 | } | |
225 | ||
27f3d6cf BS |
226 | const struct nvkm_object_func |
227 | gf100_fermi = { | |
e3c71eb2 | 228 | .mthd = gf100_fermi_mthd, |
ac9738bb BS |
229 | }; |
230 | ||
a65955e1 BS |
231 | static void |
232 | gf100_gr_mthd_set_shader_exceptions(struct nvkm_device *device, u32 data) | |
d6bd3803 | 233 | { |
a65955e1 BS |
234 | nvkm_wr32(device, 0x419e44, data ? 0xffffffff : 0x00000000); |
235 | nvkm_wr32(device, 0x419e4c, data ? 0xffffffff : 0x00000000); | |
d6bd3803 BS |
236 | } |
237 | ||
a65955e1 BS |
238 | static bool |
239 | gf100_gr_mthd_sw(struct nvkm_device *device, u16 class, u32 mthd, u32 data) | |
240 | { | |
241 | switch (class & 0x00ff) { | |
242 | case 0x97: | |
243 | case 0xc0: | |
244 | switch (mthd) { | |
245 | case 0x1528: | |
246 | gf100_gr_mthd_set_shader_exceptions(device, data); | |
247 | return true; | |
248 | default: | |
249 | break; | |
250 | } | |
251 | break; | |
252 | default: | |
253 | break; | |
254 | } | |
255 | return false; | |
256 | } | |
d6bd3803 | 257 | |
27f3d6cf BS |
258 | static int |
259 | gf100_gr_object_get(struct nvkm_gr *base, int index, struct nvkm_sclass *sclass) | |
260 | { | |
261 | struct gf100_gr *gr = gf100_gr(base); | |
262 | int c = 0; | |
263 | ||
264 | while (gr->func->sclass[c].oclass) { | |
265 | if (c++ == index) { | |
266 | *sclass = gr->func->sclass[index]; | |
267 | return index; | |
268 | } | |
269 | } | |
270 | ||
271 | return c; | |
272 | } | |
ebb945a9 | 273 | |
ebb945a9 BS |
274 | /******************************************************************************* |
275 | * PGRAPH context | |
276 | ******************************************************************************/ | |
966a5b7d | 277 | |
27f3d6cf BS |
278 | static int |
279 | gf100_gr_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, | |
280 | int align, struct nvkm_gpuobj **pgpuobj) | |
966a5b7d | 281 | { |
27f3d6cf BS |
282 | struct gf100_gr_chan *chan = gf100_gr_chan(object); |
283 | struct gf100_gr *gr = chan->gr; | |
284 | int ret, i; | |
285 | ||
286 | ret = nvkm_gpuobj_new(gr->base.engine.subdev.device, gr->size, | |
287 | align, false, parent, pgpuobj); | |
288 | if (ret) | |
289 | return ret; | |
290 | ||
291 | nvkm_kmap(*pgpuobj); | |
292 | for (i = 0; i < gr->size; i += 4) | |
293 | nvkm_wo32(*pgpuobj, i, gr->data[i / 4]); | |
294 | ||
295 | if (!gr->firmware) { | |
296 | nvkm_wo32(*pgpuobj, 0x00, chan->mmio_nr / 2); | |
297 | nvkm_wo32(*pgpuobj, 0x04, chan->mmio_vma.offset >> 8); | |
298 | } else { | |
299 | nvkm_wo32(*pgpuobj, 0xf4, 0); | |
300 | nvkm_wo32(*pgpuobj, 0xf8, 0); | |
301 | nvkm_wo32(*pgpuobj, 0x10, chan->mmio_nr / 2); | |
302 | nvkm_wo32(*pgpuobj, 0x14, lower_32_bits(chan->mmio_vma.offset)); | |
303 | nvkm_wo32(*pgpuobj, 0x18, upper_32_bits(chan->mmio_vma.offset)); | |
304 | nvkm_wo32(*pgpuobj, 0x1c, 1); | |
305 | nvkm_wo32(*pgpuobj, 0x20, 0); | |
306 | nvkm_wo32(*pgpuobj, 0x28, 0); | |
307 | nvkm_wo32(*pgpuobj, 0x2c, 0); | |
308 | } | |
309 | nvkm_done(*pgpuobj); | |
310 | return 0; | |
311 | } | |
312 | ||
313 | static void * | |
314 | gf100_gr_chan_dtor(struct nvkm_object *object) | |
315 | { | |
316 | struct gf100_gr_chan *chan = gf100_gr_chan(object); | |
317 | int i; | |
318 | ||
319 | for (i = 0; i < ARRAY_SIZE(chan->data); i++) { | |
320 | if (chan->data[i].vma.node) { | |
321 | nvkm_vm_unmap(&chan->data[i].vma); | |
322 | nvkm_vm_put(&chan->data[i].vma); | |
323 | } | |
324 | nvkm_memory_del(&chan->data[i].mem); | |
325 | } | |
326 | ||
327 | if (chan->mmio_vma.node) { | |
328 | nvkm_vm_unmap(&chan->mmio_vma); | |
329 | nvkm_vm_put(&chan->mmio_vma); | |
330 | } | |
331 | nvkm_memory_del(&chan->mmio); | |
332 | return chan; | |
333 | } | |
334 | ||
335 | static const struct nvkm_object_func | |
336 | gf100_gr_chan = { | |
337 | .dtor = gf100_gr_chan_dtor, | |
338 | .bind = gf100_gr_chan_bind, | |
339 | }; | |
340 | ||
341 | static int | |
342 | gf100_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, | |
343 | const struct nvkm_oclass *oclass, | |
344 | struct nvkm_object **pobject) | |
345 | { | |
346 | struct gf100_gr *gr = gf100_gr(base); | |
bfee3f3d BS |
347 | struct gf100_gr_data *data = gr->mmio_data; |
348 | struct gf100_gr_mmio *mmio = gr->mmio_list; | |
e3c71eb2 | 349 | struct gf100_gr_chan *chan; |
227c95d9 | 350 | struct nvkm_device *device = gr->base.engine.subdev.device; |
966a5b7d | 351 | int ret, i; |
966a5b7d | 352 | |
27f3d6cf BS |
353 | if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) |
354 | return -ENOMEM; | |
355 | nvkm_object_ctor(&gf100_gr_chan, oclass, &chan->object); | |
356 | chan->gr = gr; | |
357 | *pobject = &chan->object; | |
966a5b7d | 358 | |
ac1499d9 BS |
359 | /* allocate memory for a "mmio list" buffer that's used by the HUB |
360 | * fuc to modify some per-context register settings on first load | |
361 | * of the context. | |
362 | */ | |
227c95d9 BS |
363 | ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x100, |
364 | false, &chan->mmio); | |
73a60c0d BS |
365 | if (ret) |
366 | return ret; | |
367 | ||
27f3d6cf | 368 | ret = nvkm_vm_get(fifoch->vm, 0x1000, 12, NV_MEM_ACCESS_RW | |
227c95d9 | 369 | NV_MEM_ACCESS_SYS, &chan->mmio_vma); |
73a60c0d BS |
370 | if (ret) |
371 | return ret; | |
372 | ||
227c95d9 BS |
373 | nvkm_memory_map(chan->mmio, &chan->mmio_vma, 0); |
374 | ||
ac1499d9 | 375 | /* allocate buffers referenced by mmio list */ |
bfee3f3d | 376 | for (i = 0; data->size && i < ARRAY_SIZE(gr->mmio_data); i++) { |
227c95d9 BS |
377 | ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, |
378 | data->size, data->align, false, | |
379 | &chan->data[i].mem); | |
ac1499d9 BS |
380 | if (ret) |
381 | return ret; | |
73a60c0d | 382 | |
27f3d6cf BS |
383 | ret = nvkm_vm_get(fifoch->vm, |
384 | nvkm_memory_size(chan->data[i].mem), 12, | |
385 | data->access, &chan->data[i].vma); | |
ac1499d9 BS |
386 | if (ret) |
387 | return ret; | |
966a5b7d | 388 | |
227c95d9 | 389 | nvkm_memory_map(chan->data[i].mem, &chan->data[i].vma, 0); |
ac1499d9 | 390 | data++; |
966a5b7d BS |
391 | } |
392 | ||
ac1499d9 | 393 | /* finally, fill in the mmio list and point the context at it */ |
142ea05f | 394 | nvkm_kmap(chan->mmio); |
bfee3f3d | 395 | for (i = 0; mmio->addr && i < ARRAY_SIZE(gr->mmio_list); i++) { |
ac1499d9 BS |
396 | u32 addr = mmio->addr; |
397 | u32 data = mmio->data; | |
966a5b7d | 398 | |
694c6caf | 399 | if (mmio->buffer >= 0) { |
ebb945a9 | 400 | u64 info = chan->data[mmio->buffer].vma.offset; |
ac1499d9 BS |
401 | data |= info >> mmio->shift; |
402 | } | |
73a60c0d | 403 | |
142ea05f BS |
404 | nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); |
405 | nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, data); | |
ac1499d9 BS |
406 | mmio++; |
407 | } | |
142ea05f | 408 | nvkm_done(chan->mmio); |
ebb945a9 | 409 | return 0; |
4b223eef BS |
410 | } |
411 | ||
ebb945a9 | 412 | /******************************************************************************* |
c33b1e8c | 413 | * PGRAPH register lists |
ebb945a9 BS |
414 | ******************************************************************************/ |
415 | ||
e3c71eb2 BS |
416 | const struct gf100_gr_init |
417 | gf100_gr_init_main_0[] = { | |
30f4e087 BS |
418 | { 0x400080, 1, 0x04, 0x003083c2 }, |
419 | { 0x400088, 1, 0x04, 0x00006fe7 }, | |
420 | { 0x40008c, 1, 0x04, 0x00000000 }, | |
421 | { 0x400090, 1, 0x04, 0x00000030 }, | |
422 | { 0x40013c, 1, 0x04, 0x013901f7 }, | |
423 | { 0x400140, 1, 0x04, 0x00000100 }, | |
424 | { 0x400144, 1, 0x04, 0x00000000 }, | |
425 | { 0x400148, 1, 0x04, 0x00000110 }, | |
426 | { 0x400138, 1, 0x04, 0x00000000 }, | |
427 | { 0x400130, 2, 0x04, 0x00000000 }, | |
428 | { 0x400124, 1, 0x04, 0x00000002 }, | |
429 | {} | |
430 | }; | |
431 | ||
e3c71eb2 BS |
432 | const struct gf100_gr_init |
433 | gf100_gr_init_fe_0[] = { | |
30f4e087 BS |
434 | { 0x40415c, 1, 0x04, 0x00000000 }, |
435 | { 0x404170, 1, 0x04, 0x00000000 }, | |
436 | {} | |
437 | }; | |
438 | ||
e3c71eb2 BS |
439 | const struct gf100_gr_init |
440 | gf100_gr_init_pri_0[] = { | |
30f4e087 BS |
441 | { 0x404488, 2, 0x04, 0x00000000 }, |
442 | {} | |
443 | }; | |
444 | ||
e3c71eb2 BS |
445 | const struct gf100_gr_init |
446 | gf100_gr_init_rstr2d_0[] = { | |
30f4e087 BS |
447 | { 0x407808, 1, 0x04, 0x00000000 }, |
448 | {} | |
449 | }; | |
450 | ||
e3c71eb2 BS |
451 | const struct gf100_gr_init |
452 | gf100_gr_init_pd_0[] = { | |
30f4e087 BS |
453 | { 0x406024, 1, 0x04, 0x00000000 }, |
454 | {} | |
455 | }; | |
456 | ||
e3c71eb2 BS |
457 | const struct gf100_gr_init |
458 | gf100_gr_init_ds_0[] = { | |
30f4e087 BS |
459 | { 0x405844, 1, 0x04, 0x00ffffff }, |
460 | { 0x405850, 1, 0x04, 0x00000000 }, | |
461 | { 0x405908, 1, 0x04, 0x00000000 }, | |
462 | {} | |
463 | }; | |
464 | ||
e3c71eb2 BS |
465 | const struct gf100_gr_init |
466 | gf100_gr_init_scc_0[] = { | |
30f4e087 BS |
467 | { 0x40803c, 1, 0x04, 0x00000000 }, |
468 | {} | |
469 | }; | |
470 | ||
e3c71eb2 BS |
471 | const struct gf100_gr_init |
472 | gf100_gr_init_prop_0[] = { | |
30f4e087 | 473 | { 0x4184a0, 1, 0x04, 0x00000000 }, |
97af71fa BS |
474 | {} |
475 | }; | |
476 | ||
e3c71eb2 BS |
477 | const struct gf100_gr_init |
478 | gf100_gr_init_gpc_unk_0[] = { | |
30f4e087 BS |
479 | { 0x418604, 1, 0x04, 0x00000000 }, |
480 | { 0x418680, 1, 0x04, 0x00000000 }, | |
481 | { 0x418714, 1, 0x04, 0x80000000 }, | |
482 | { 0x418384, 1, 0x04, 0x00000000 }, | |
97af71fa BS |
483 | {} |
484 | }; | |
485 | ||
e3c71eb2 BS |
486 | const struct gf100_gr_init |
487 | gf100_gr_init_setup_0[] = { | |
30f4e087 | 488 | { 0x418814, 3, 0x04, 0x00000000 }, |
97af71fa BS |
489 | {} |
490 | }; | |
491 | ||
e3c71eb2 BS |
492 | const struct gf100_gr_init |
493 | gf100_gr_init_crstr_0[] = { | |
30f4e087 | 494 | { 0x418b04, 1, 0x04, 0x00000000 }, |
97af71fa BS |
495 | {} |
496 | }; | |
497 | ||
e3c71eb2 BS |
498 | const struct gf100_gr_init |
499 | gf100_gr_init_setup_1[] = { | |
30f4e087 BS |
500 | { 0x4188c8, 1, 0x04, 0x80000000 }, |
501 | { 0x4188cc, 1, 0x04, 0x00000000 }, | |
502 | { 0x4188d0, 1, 0x04, 0x00010000 }, | |
503 | { 0x4188d4, 1, 0x04, 0x00000001 }, | |
97af71fa BS |
504 | {} |
505 | }; | |
506 | ||
e3c71eb2 BS |
507 | const struct gf100_gr_init |
508 | gf100_gr_init_zcull_0[] = { | |
30f4e087 BS |
509 | { 0x418910, 1, 0x04, 0x00010001 }, |
510 | { 0x418914, 1, 0x04, 0x00000301 }, | |
511 | { 0x418918, 1, 0x04, 0x00800000 }, | |
512 | { 0x418980, 1, 0x04, 0x77777770 }, | |
513 | { 0x418984, 3, 0x04, 0x77777777 }, | |
97af71fa BS |
514 | {} |
515 | }; | |
516 | ||
e3c71eb2 BS |
517 | const struct gf100_gr_init |
518 | gf100_gr_init_gpm_0[] = { | |
30f4e087 BS |
519 | { 0x418c04, 1, 0x04, 0x00000000 }, |
520 | { 0x418c88, 1, 0x04, 0x00000000 }, | |
97af71fa BS |
521 | {} |
522 | }; | |
523 | ||
e3c71eb2 BS |
524 | const struct gf100_gr_init |
525 | gf100_gr_init_gpc_unk_1[] = { | |
30f4e087 BS |
526 | { 0x418d00, 1, 0x04, 0x00000000 }, |
527 | { 0x418f08, 1, 0x04, 0x00000000 }, | |
528 | { 0x418e00, 1, 0x04, 0x00000050 }, | |
529 | { 0x418e08, 1, 0x04, 0x00000000 }, | |
97af71fa BS |
530 | {} |
531 | }; | |
532 | ||
e3c71eb2 BS |
533 | const struct gf100_gr_init |
534 | gf100_gr_init_gcc_0[] = { | |
30f4e087 BS |
535 | { 0x41900c, 1, 0x04, 0x00000000 }, |
536 | { 0x419018, 1, 0x04, 0x00000000 }, | |
537 | {} | |
538 | }; | |
539 | ||
e3c71eb2 BS |
540 | const struct gf100_gr_init |
541 | gf100_gr_init_tpccs_0[] = { | |
30f4e087 BS |
542 | { 0x419d08, 2, 0x04, 0x00000000 }, |
543 | { 0x419d10, 1, 0x04, 0x00000014 }, | |
7e194533 BS |
544 | {} |
545 | }; | |
546 | ||
e3c71eb2 BS |
547 | const struct gf100_gr_init |
548 | gf100_gr_init_tex_0[] = { | |
30f4e087 BS |
549 | { 0x419ab0, 1, 0x04, 0x00000000 }, |
550 | { 0x419ab8, 1, 0x04, 0x000000e7 }, | |
551 | { 0x419abc, 2, 0x04, 0x00000000 }, | |
7e194533 BS |
552 | {} |
553 | }; | |
554 | ||
e3c71eb2 BS |
555 | const struct gf100_gr_init |
556 | gf100_gr_init_pe_0[] = { | |
30f4e087 BS |
557 | { 0x41980c, 3, 0x04, 0x00000000 }, |
558 | { 0x419844, 1, 0x04, 0x00000000 }, | |
559 | { 0x41984c, 1, 0x04, 0x00005bc5 }, | |
560 | { 0x419850, 4, 0x04, 0x00000000 }, | |
7e194533 BS |
561 | {} |
562 | }; | |
563 | ||
e3c71eb2 BS |
564 | const struct gf100_gr_init |
565 | gf100_gr_init_l1c_0[] = { | |
30f4e087 BS |
566 | { 0x419c98, 1, 0x04, 0x00000000 }, |
567 | { 0x419ca8, 1, 0x04, 0x80000000 }, | |
568 | { 0x419cb4, 1, 0x04, 0x00000000 }, | |
569 | { 0x419cb8, 1, 0x04, 0x00008bf4 }, | |
570 | { 0x419cbc, 1, 0x04, 0x28137606 }, | |
571 | { 0x419cc0, 2, 0x04, 0x00000000 }, | |
7e194533 BS |
572 | {} |
573 | }; | |
574 | ||
e3c71eb2 BS |
575 | const struct gf100_gr_init |
576 | gf100_gr_init_wwdx_0[] = { | |
30f4e087 BS |
577 | { 0x419bd4, 1, 0x04, 0x00800000 }, |
578 | { 0x419bdc, 1, 0x04, 0x00000000 }, | |
7e194533 BS |
579 | {} |
580 | }; | |
581 | ||
e3c71eb2 BS |
582 | const struct gf100_gr_init |
583 | gf100_gr_init_tpccs_1[] = { | |
30f4e087 | 584 | { 0x419d2c, 1, 0x04, 0x00000000 }, |
7e194533 BS |
585 | {} |
586 | }; | |
587 | ||
e3c71eb2 BS |
588 | const struct gf100_gr_init |
589 | gf100_gr_init_mpc_0[] = { | |
30f4e087 | 590 | { 0x419c0c, 1, 0x04, 0x00000000 }, |
7e194533 BS |
591 | {} |
592 | }; | |
593 | ||
e3c71eb2 BS |
594 | static const struct gf100_gr_init |
595 | gf100_gr_init_sm_0[] = { | |
30f4e087 BS |
596 | { 0x419e00, 1, 0x04, 0x00000000 }, |
597 | { 0x419ea0, 1, 0x04, 0x00000000 }, | |
598 | { 0x419ea4, 1, 0x04, 0x00000100 }, | |
599 | { 0x419ea8, 1, 0x04, 0x00001100 }, | |
600 | { 0x419eac, 1, 0x04, 0x11100702 }, | |
601 | { 0x419eb0, 1, 0x04, 0x00000003 }, | |
602 | { 0x419eb4, 4, 0x04, 0x00000000 }, | |
603 | { 0x419ec8, 1, 0x04, 0x06060618 }, | |
604 | { 0x419ed0, 1, 0x04, 0x0eff0e38 }, | |
605 | { 0x419ed4, 1, 0x04, 0x011104f1 }, | |
606 | { 0x419edc, 1, 0x04, 0x00000000 }, | |
607 | { 0x419f00, 1, 0x04, 0x00000000 }, | |
608 | { 0x419f2c, 1, 0x04, 0x00000000 }, | |
609 | {} | |
610 | }; | |
611 | ||
e3c71eb2 BS |
612 | const struct gf100_gr_init |
613 | gf100_gr_init_be_0[] = { | |
30f4e087 BS |
614 | { 0x40880c, 1, 0x04, 0x00000000 }, |
615 | { 0x408910, 9, 0x04, 0x00000000 }, | |
616 | { 0x408950, 1, 0x04, 0x00000000 }, | |
617 | { 0x408954, 1, 0x04, 0x0000ffff }, | |
618 | { 0x408984, 1, 0x04, 0x00000000 }, | |
619 | { 0x408988, 1, 0x04, 0x08040201 }, | |
620 | { 0x40898c, 1, 0x04, 0x80402010 }, | |
621 | {} | |
622 | }; | |
623 | ||
e3c71eb2 BS |
624 | const struct gf100_gr_init |
625 | gf100_gr_init_fe_1[] = { | |
c33b1e8c BS |
626 | { 0x4040f0, 1, 0x04, 0x00000000 }, |
627 | {} | |
628 | }; | |
629 | ||
e3c71eb2 BS |
630 | const struct gf100_gr_init |
631 | gf100_gr_init_pe_1[] = { | |
c33b1e8c BS |
632 | { 0x419880, 1, 0x04, 0x00000002 }, |
633 | {} | |
634 | }; | |
635 | ||
e3c71eb2 BS |
636 | static const struct gf100_gr_pack |
637 | gf100_gr_pack_mmio[] = { | |
638 | { gf100_gr_init_main_0 }, | |
639 | { gf100_gr_init_fe_0 }, | |
640 | { gf100_gr_init_pri_0 }, | |
641 | { gf100_gr_init_rstr2d_0 }, | |
642 | { gf100_gr_init_pd_0 }, | |
643 | { gf100_gr_init_ds_0 }, | |
644 | { gf100_gr_init_scc_0 }, | |
645 | { gf100_gr_init_prop_0 }, | |
646 | { gf100_gr_init_gpc_unk_0 }, | |
647 | { gf100_gr_init_setup_0 }, | |
648 | { gf100_gr_init_crstr_0 }, | |
649 | { gf100_gr_init_setup_1 }, | |
650 | { gf100_gr_init_zcull_0 }, | |
651 | { gf100_gr_init_gpm_0 }, | |
652 | { gf100_gr_init_gpc_unk_1 }, | |
653 | { gf100_gr_init_gcc_0 }, | |
654 | { gf100_gr_init_tpccs_0 }, | |
655 | { gf100_gr_init_tex_0 }, | |
656 | { gf100_gr_init_pe_0 }, | |
657 | { gf100_gr_init_l1c_0 }, | |
658 | { gf100_gr_init_wwdx_0 }, | |
659 | { gf100_gr_init_tpccs_1 }, | |
660 | { gf100_gr_init_mpc_0 }, | |
661 | { gf100_gr_init_sm_0 }, | |
662 | { gf100_gr_init_be_0 }, | |
663 | { gf100_gr_init_fe_1 }, | |
664 | { gf100_gr_init_pe_1 }, | |
26410c67 ML |
665 | {} |
666 | }; | |
667 | ||
c33b1e8c BS |
668 | /******************************************************************************* |
669 | * PGRAPH engine/subdev functions | |
670 | ******************************************************************************/ | |
671 | ||
ac9738bb | 672 | void |
bfee3f3d | 673 | gf100_gr_zbc_init(struct gf100_gr *gr) |
ac9738bb BS |
674 | { |
675 | const u32 zero[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
676 | 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; | |
677 | const u32 one[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, | |
678 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; | |
679 | const u32 f32_0[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, | |
680 | 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; | |
681 | const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, | |
682 | 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; | |
bfee3f3d | 683 | struct nvkm_ltc *ltc = nvkm_ltc(gr); |
ac9738bb BS |
684 | int index; |
685 | ||
bfee3f3d BS |
686 | if (!gr->zbc_color[0].format) { |
687 | gf100_gr_zbc_color_get(gr, 1, & zero[0], &zero[4]); | |
688 | gf100_gr_zbc_color_get(gr, 2, & one[0], &one[4]); | |
689 | gf100_gr_zbc_color_get(gr, 4, &f32_0[0], &f32_0[4]); | |
690 | gf100_gr_zbc_color_get(gr, 4, &f32_1[0], &f32_1[4]); | |
691 | gf100_gr_zbc_depth_get(gr, 1, 0x00000000, 0x00000000); | |
692 | gf100_gr_zbc_depth_get(gr, 1, 0x3f800000, 0x3f800000); | |
ac9738bb BS |
693 | } |
694 | ||
695 | for (index = ltc->zbc_min; index <= ltc->zbc_max; index++) | |
bfee3f3d | 696 | gf100_gr_zbc_clear_color(gr, index); |
ac9738bb | 697 | for (index = ltc->zbc_min; index <= ltc->zbc_max; index++) |
bfee3f3d | 698 | gf100_gr_zbc_clear_depth(gr, index); |
ac9738bb BS |
699 | } |
700 | ||
4a8cf451 AC |
701 | /** |
702 | * Wait until GR goes idle. GR is considered idle if it is disabled by the | |
703 | * MC (0x200) register, or GR is not busy and a context switch is not in | |
704 | * progress. | |
705 | */ | |
706 | int | |
bfee3f3d | 707 | gf100_gr_wait_idle(struct gf100_gr *gr) |
4a8cf451 | 708 | { |
109c2f2f BS |
709 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
710 | struct nvkm_device *device = subdev->device; | |
4a8cf451 AC |
711 | unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000); |
712 | bool gr_enabled, ctxsw_active, gr_busy; | |
713 | ||
714 | do { | |
715 | /* | |
716 | * required to make sure FIFO_ENGINE_STATUS (0x2640) is | |
717 | * up-to-date | |
718 | */ | |
276836d4 | 719 | nvkm_rd32(device, 0x400700); |
4a8cf451 | 720 | |
276836d4 BS |
721 | gr_enabled = nvkm_rd32(device, 0x200) & 0x1000; |
722 | ctxsw_active = nvkm_rd32(device, 0x2640) & 0x8000; | |
723 | gr_busy = nvkm_rd32(device, 0x40060c) & 0x1; | |
4a8cf451 AC |
724 | |
725 | if (!gr_enabled || (!gr_busy && !ctxsw_active)) | |
726 | return 0; | |
727 | } while (time_before(jiffies, end_jiffies)); | |
728 | ||
109c2f2f BS |
729 | nvkm_error(subdev, |
730 | "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n", | |
731 | gr_enabled, ctxsw_active, gr_busy); | |
4a8cf451 AC |
732 | return -EAGAIN; |
733 | } | |
734 | ||
30f4e087 | 735 | void |
bfee3f3d | 736 | gf100_gr_mmio(struct gf100_gr *gr, const struct gf100_gr_pack *p) |
4b223eef | 737 | { |
276836d4 | 738 | struct nvkm_device *device = gr->base.engine.subdev.device; |
e3c71eb2 BS |
739 | const struct gf100_gr_pack *pack; |
740 | const struct gf100_gr_init *init; | |
c33b1e8c BS |
741 | |
742 | pack_for_each_init(init, pack, p) { | |
743 | u32 next = init->addr + init->count * init->pitch; | |
744 | u32 addr = init->addr; | |
745 | while (addr < next) { | |
276836d4 | 746 | nvkm_wr32(device, addr, init->data); |
30f4e087 BS |
747 | addr += init->pitch; |
748 | } | |
749 | } | |
ebb945a9 BS |
750 | } |
751 | ||
752 | void | |
bfee3f3d | 753 | gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p) |
ebb945a9 | 754 | { |
276836d4 | 755 | struct nvkm_device *device = gr->base.engine.subdev.device; |
e3c71eb2 BS |
756 | const struct gf100_gr_pack *pack; |
757 | const struct gf100_gr_init *init; | |
c33b1e8c | 758 | u32 data = 0; |
30f4e087 | 759 | |
276836d4 | 760 | nvkm_wr32(device, 0x400208, 0x80000000); |
c33b1e8c BS |
761 | |
762 | pack_for_each_init(init, pack, p) { | |
763 | u32 next = init->addr + init->count * init->pitch; | |
764 | u32 addr = init->addr; | |
765 | ||
766 | if ((pack == p && init == p->init) || data != init->data) { | |
276836d4 | 767 | nvkm_wr32(device, 0x400204, init->data); |
30f4e087 BS |
768 | data = init->data; |
769 | } | |
ebb945a9 | 770 | |
c33b1e8c | 771 | while (addr < next) { |
276836d4 | 772 | nvkm_wr32(device, 0x400200, addr); |
4a8cf451 AC |
773 | /** |
774 | * Wait for GR to go idle after submitting a | |
775 | * GO_IDLE bundle | |
776 | */ | |
777 | if ((addr & 0xffff) == 0xe100) | |
bfee3f3d | 778 | gf100_gr_wait_idle(gr); |
c4584adc BS |
779 | nvkm_msec(device, 2000, |
780 | if (!(nvkm_rd32(device, 0x400700) & 0x00000004)) | |
781 | break; | |
782 | ); | |
30f4e087 | 783 | addr += init->pitch; |
30f4e087 BS |
784 | } |
785 | } | |
c33b1e8c | 786 | |
276836d4 | 787 | nvkm_wr32(device, 0x400208, 0x00000000); |
30f4e087 BS |
788 | } |
789 | ||
790 | void | |
bfee3f3d | 791 | gf100_gr_mthd(struct gf100_gr *gr, const struct gf100_gr_pack *p) |
30f4e087 | 792 | { |
276836d4 | 793 | struct nvkm_device *device = gr->base.engine.subdev.device; |
e3c71eb2 BS |
794 | const struct gf100_gr_pack *pack; |
795 | const struct gf100_gr_init *init; | |
c33b1e8c | 796 | u32 data = 0; |
30f4e087 | 797 | |
c33b1e8c BS |
798 | pack_for_each_init(init, pack, p) { |
799 | u32 ctrl = 0x80000000 | pack->type; | |
800 | u32 next = init->addr + init->count * init->pitch; | |
801 | u32 addr = init->addr; | |
802 | ||
803 | if ((pack == p && init == p->init) || data != init->data) { | |
276836d4 | 804 | nvkm_wr32(device, 0x40448c, init->data); |
c33b1e8c BS |
805 | data = init->data; |
806 | } | |
807 | ||
808 | while (addr < next) { | |
276836d4 | 809 | nvkm_wr32(device, 0x404488, ctrl | (addr << 14)); |
c33b1e8c | 810 | addr += init->pitch; |
30f4e087 BS |
811 | } |
812 | } | |
813 | } | |
814 | ||
815 | u64 | |
bfee3f3d | 816 | gf100_gr_units(struct nvkm_gr *obj) |
30f4e087 | 817 | { |
bfee3f3d | 818 | struct gf100_gr *gr = container_of(obj, typeof(*gr), base); |
30f4e087 BS |
819 | u64 cfg; |
820 | ||
bfee3f3d BS |
821 | cfg = (u32)gr->gpc_nr; |
822 | cfg |= (u32)gr->tpc_total << 8; | |
823 | cfg |= (u64)gr->rop_nr << 32; | |
30f4e087 BS |
824 | |
825 | return cfg; | |
ebb945a9 BS |
826 | } |
827 | ||
109c2f2f BS |
828 | static const struct nvkm_bitfield gk104_sked_error[] = { |
829 | { 0x00000080, "CONSTANT_BUFFER_SIZE" }, | |
830 | { 0x00000200, "LOCAL_MEMORY_SIZE_POS" }, | |
831 | { 0x00000400, "LOCAL_MEMORY_SIZE_NEG" }, | |
832 | { 0x00000800, "WARP_CSTACK_SIZE" }, | |
833 | { 0x00001000, "TOTAL_TEMP_SIZE" }, | |
834 | { 0x00002000, "REGISTER_COUNT" }, | |
835 | { 0x00040000, "TOTAL_THREADS" }, | |
836 | { 0x00100000, "PROGRAM_OFFSET" }, | |
837 | { 0x00200000, "SHARED_MEMORY_SIZE" }, | |
838 | { 0x02000000, "SHARED_CONFIG_TOO_SMALL" }, | |
839 | { 0x04000000, "TOTAL_REGISTER_COUNT" }, | |
30f4e087 BS |
840 | {} |
841 | }; | |
842 | ||
109c2f2f BS |
843 | static const struct nvkm_bitfield gf100_gpc_rop_error[] = { |
844 | { 0x00000002, "RT_PITCH_OVERRUN" }, | |
845 | { 0x00000010, "RT_WIDTH_OVERRUN" }, | |
846 | { 0x00000020, "RT_HEIGHT_OVERRUN" }, | |
847 | { 0x00000080, "ZETA_STORAGE_TYPE_MISMATCH" }, | |
848 | { 0x00000100, "RT_STORAGE_TYPE_MISMATCH" }, | |
849 | { 0x00000400, "RT_LINEAR_MISMATCH" }, | |
30f4e087 BS |
850 | {} |
851 | }; | |
852 | ||
ebb945a9 | 853 | static void |
bfee3f3d | 854 | gf100_gr_trap_gpc_rop(struct gf100_gr *gr, int gpc) |
ebb945a9 | 855 | { |
109c2f2f BS |
856 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
857 | struct nvkm_device *device = subdev->device; | |
858 | char error[128]; | |
30f4e087 | 859 | u32 trap[4]; |
ebb945a9 | 860 | |
109c2f2f | 861 | trap[0] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0420)) & 0x3fffffff; |
276836d4 BS |
862 | trap[1] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0434)); |
863 | trap[2] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0438)); | |
864 | trap[3] = nvkm_rd32(device, GPC_UNIT(gpc, 0x043c)); | |
ebb945a9 | 865 | |
109c2f2f | 866 | nvkm_snprintbf(error, sizeof(error), gf100_gpc_rop_error, trap[0]); |
30f4e087 | 867 | |
109c2f2f BS |
868 | nvkm_error(subdev, "GPC%d/PROP trap: %08x [%s] x = %u, y = %u, " |
869 | "format = %x, storage type = %x\n", | |
870 | gpc, trap[0], error, trap[1] & 0xffff, trap[1] >> 16, | |
871 | (trap[2] >> 8) & 0x3f, trap[3] & 0xff); | |
276836d4 | 872 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); |
ebb945a9 BS |
873 | } |
874 | ||
e3c71eb2 | 875 | static const struct nvkm_enum gf100_mp_warp_error[] = { |
fec43a72 BS |
876 | { 0x00, "NO_ERROR" }, |
877 | { 0x01, "STACK_MISMATCH" }, | |
878 | { 0x05, "MISALIGNED_PC" }, | |
879 | { 0x08, "MISALIGNED_GPR" }, | |
880 | { 0x09, "INVALID_OPCODE" }, | |
881 | { 0x0d, "GPR_OUT_OF_BOUNDS" }, | |
882 | { 0x0e, "MEM_OUT_OF_BOUNDS" }, | |
883 | { 0x0f, "UNALIGNED_MEM_ACCESS" }, | |
884 | { 0x11, "INVALID_PARAM" }, | |
885 | {} | |
886 | }; | |
887 | ||
e3c71eb2 | 888 | static const struct nvkm_bitfield gf100_mp_global_error[] = { |
fec43a72 BS |
889 | { 0x00000004, "MULTIPLE_WARP_ERRORS" }, |
890 | { 0x00000008, "OUT_OF_STACK_SPACE" }, | |
891 | {} | |
892 | }; | |
893 | ||
894 | static void | |
bfee3f3d | 895 | gf100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) |
fec43a72 | 896 | { |
109c2f2f BS |
897 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
898 | struct nvkm_device *device = subdev->device; | |
276836d4 BS |
899 | u32 werr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x648)); |
900 | u32 gerr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x650)); | |
109c2f2f BS |
901 | const struct nvkm_enum *warp; |
902 | char glob[128]; | |
fec43a72 | 903 | |
109c2f2f BS |
904 | nvkm_snprintbf(glob, sizeof(glob), gf100_mp_global_error, gerr); |
905 | warp = nvkm_enum_find(gf100_mp_warp_error, werr & 0xffff); | |
906 | ||
907 | nvkm_error(subdev, "GPC%i/TPC%i/MP trap: " | |
908 | "global %08x [%s] warp %04x [%s]\n", | |
909 | gpc, tpc, gerr, glob, werr, warp ? warp->name : ""); | |
fec43a72 | 910 | |
276836d4 BS |
911 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x648), 0x00000000); |
912 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x650), gerr); | |
fec43a72 BS |
913 | } |
914 | ||
f73221e4 | 915 | static void |
bfee3f3d | 916 | gf100_gr_trap_tpc(struct gf100_gr *gr, int gpc, int tpc) |
f73221e4 | 917 | { |
109c2f2f BS |
918 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
919 | struct nvkm_device *device = subdev->device; | |
276836d4 | 920 | u32 stat = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0508)); |
f73221e4 BS |
921 | |
922 | if (stat & 0x00000001) { | |
276836d4 | 923 | u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0224)); |
109c2f2f | 924 | nvkm_error(subdev, "GPC%d/TPC%d/TEX: %08x\n", gpc, tpc, trap); |
276836d4 | 925 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); |
f73221e4 BS |
926 | stat &= ~0x00000001; |
927 | } | |
928 | ||
929 | if (stat & 0x00000002) { | |
bfee3f3d | 930 | gf100_gr_trap_mp(gr, gpc, tpc); |
f73221e4 BS |
931 | stat &= ~0x00000002; |
932 | } | |
933 | ||
934 | if (stat & 0x00000004) { | |
276836d4 | 935 | u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0084)); |
109c2f2f | 936 | nvkm_error(subdev, "GPC%d/TPC%d/POLY: %08x\n", gpc, tpc, trap); |
276836d4 | 937 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); |
f73221e4 BS |
938 | stat &= ~0x00000004; |
939 | } | |
940 | ||
941 | if (stat & 0x00000008) { | |
276836d4 | 942 | u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x048c)); |
109c2f2f | 943 | nvkm_error(subdev, "GPC%d/TPC%d/L1C: %08x\n", gpc, tpc, trap); |
276836d4 | 944 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); |
f73221e4 BS |
945 | stat &= ~0x00000008; |
946 | } | |
947 | ||
948 | if (stat) { | |
109c2f2f | 949 | nvkm_error(subdev, "GPC%d/TPC%d/%08x: unknown\n", gpc, tpc, stat); |
f73221e4 BS |
950 | } |
951 | } | |
952 | ||
953 | static void | |
bfee3f3d | 954 | gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) |
f73221e4 | 955 | { |
109c2f2f BS |
956 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
957 | struct nvkm_device *device = subdev->device; | |
276836d4 | 958 | u32 stat = nvkm_rd32(device, GPC_UNIT(gpc, 0x2c90)); |
f73221e4 BS |
959 | int tpc; |
960 | ||
961 | if (stat & 0x00000001) { | |
bfee3f3d | 962 | gf100_gr_trap_gpc_rop(gr, gpc); |
f73221e4 BS |
963 | stat &= ~0x00000001; |
964 | } | |
965 | ||
966 | if (stat & 0x00000002) { | |
276836d4 | 967 | u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x0900)); |
109c2f2f | 968 | nvkm_error(subdev, "GPC%d/ZCULL: %08x\n", gpc, trap); |
276836d4 | 969 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); |
f73221e4 BS |
970 | stat &= ~0x00000002; |
971 | } | |
972 | ||
973 | if (stat & 0x00000004) { | |
276836d4 | 974 | u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x1028)); |
109c2f2f | 975 | nvkm_error(subdev, "GPC%d/CCACHE: %08x\n", gpc, trap); |
276836d4 | 976 | nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); |
f73221e4 BS |
977 | stat &= ~0x00000004; |
978 | } | |
979 | ||
980 | if (stat & 0x00000008) { | |
276836d4 | 981 | u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x0824)); |
109c2f2f | 982 | nvkm_error(subdev, "GPC%d/ESETUP: %08x\n", gpc, trap); |
276836d4 | 983 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); |
f73221e4 BS |
984 | stat &= ~0x00000009; |
985 | } | |
986 | ||
bfee3f3d | 987 | for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { |
f73221e4 BS |
988 | u32 mask = 0x00010000 << tpc; |
989 | if (stat & mask) { | |
bfee3f3d | 990 | gf100_gr_trap_tpc(gr, gpc, tpc); |
276836d4 | 991 | nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), mask); |
f73221e4 BS |
992 | stat &= ~mask; |
993 | } | |
994 | } | |
995 | ||
996 | if (stat) { | |
109c2f2f | 997 | nvkm_error(subdev, "GPC%d/%08x: unknown\n", gpc, stat); |
f73221e4 BS |
998 | } |
999 | } | |
1000 | ||
1001 | static void | |
bfee3f3d | 1002 | gf100_gr_trap_intr(struct gf100_gr *gr) |
f73221e4 | 1003 | { |
109c2f2f BS |
1004 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
1005 | struct nvkm_device *device = subdev->device; | |
276836d4 | 1006 | u32 trap = nvkm_rd32(device, 0x400108); |
109c2f2f | 1007 | int rop, gpc; |
f73221e4 BS |
1008 | |
1009 | if (trap & 0x00000001) { | |
276836d4 | 1010 | u32 stat = nvkm_rd32(device, 0x404000); |
109c2f2f | 1011 | nvkm_error(subdev, "DISPATCH %08x\n", stat); |
276836d4 BS |
1012 | nvkm_wr32(device, 0x404000, 0xc0000000); |
1013 | nvkm_wr32(device, 0x400108, 0x00000001); | |
f73221e4 BS |
1014 | trap &= ~0x00000001; |
1015 | } | |
1016 | ||
1017 | if (trap & 0x00000002) { | |
276836d4 | 1018 | u32 stat = nvkm_rd32(device, 0x404600); |
109c2f2f | 1019 | nvkm_error(subdev, "M2MF %08x\n", stat); |
276836d4 BS |
1020 | nvkm_wr32(device, 0x404600, 0xc0000000); |
1021 | nvkm_wr32(device, 0x400108, 0x00000002); | |
f73221e4 BS |
1022 | trap &= ~0x00000002; |
1023 | } | |
1024 | ||
1025 | if (trap & 0x00000008) { | |
276836d4 | 1026 | u32 stat = nvkm_rd32(device, 0x408030); |
109c2f2f | 1027 | nvkm_error(subdev, "CCACHE %08x\n", stat); |
276836d4 BS |
1028 | nvkm_wr32(device, 0x408030, 0xc0000000); |
1029 | nvkm_wr32(device, 0x400108, 0x00000008); | |
f73221e4 BS |
1030 | trap &= ~0x00000008; |
1031 | } | |
1032 | ||
1033 | if (trap & 0x00000010) { | |
276836d4 | 1034 | u32 stat = nvkm_rd32(device, 0x405840); |
109c2f2f | 1035 | nvkm_error(subdev, "SHADER %08x\n", stat); |
276836d4 BS |
1036 | nvkm_wr32(device, 0x405840, 0xc0000000); |
1037 | nvkm_wr32(device, 0x400108, 0x00000010); | |
f73221e4 BS |
1038 | trap &= ~0x00000010; |
1039 | } | |
1040 | ||
1041 | if (trap & 0x00000040) { | |
276836d4 | 1042 | u32 stat = nvkm_rd32(device, 0x40601c); |
109c2f2f | 1043 | nvkm_error(subdev, "UNK6 %08x\n", stat); |
276836d4 BS |
1044 | nvkm_wr32(device, 0x40601c, 0xc0000000); |
1045 | nvkm_wr32(device, 0x400108, 0x00000040); | |
f73221e4 BS |
1046 | trap &= ~0x00000040; |
1047 | } | |
1048 | ||
1049 | if (trap & 0x00000080) { | |
276836d4 | 1050 | u32 stat = nvkm_rd32(device, 0x404490); |
109c2f2f | 1051 | nvkm_error(subdev, "MACRO %08x\n", stat); |
276836d4 BS |
1052 | nvkm_wr32(device, 0x404490, 0xc0000000); |
1053 | nvkm_wr32(device, 0x400108, 0x00000080); | |
f73221e4 BS |
1054 | trap &= ~0x00000080; |
1055 | } | |
1056 | ||
30f4e087 | 1057 | if (trap & 0x00000100) { |
109c2f2f BS |
1058 | u32 stat = nvkm_rd32(device, 0x407020) & 0x3fffffff; |
1059 | char sked[128]; | |
30f4e087 | 1060 | |
109c2f2f BS |
1061 | nvkm_snprintbf(sked, sizeof(sked), gk104_sked_error, stat); |
1062 | nvkm_error(subdev, "SKED: %08x [%s]\n", stat, sked); | |
30f4e087 | 1063 | |
109c2f2f | 1064 | if (stat) |
276836d4 BS |
1065 | nvkm_wr32(device, 0x407020, 0x40000000); |
1066 | nvkm_wr32(device, 0x400108, 0x00000100); | |
30f4e087 BS |
1067 | trap &= ~0x00000100; |
1068 | } | |
1069 | ||
f73221e4 | 1070 | if (trap & 0x01000000) { |
276836d4 | 1071 | u32 stat = nvkm_rd32(device, 0x400118); |
bfee3f3d | 1072 | for (gpc = 0; stat && gpc < gr->gpc_nr; gpc++) { |
f73221e4 BS |
1073 | u32 mask = 0x00000001 << gpc; |
1074 | if (stat & mask) { | |
bfee3f3d | 1075 | gf100_gr_trap_gpc(gr, gpc); |
276836d4 | 1076 | nvkm_wr32(device, 0x400118, mask); |
f73221e4 BS |
1077 | stat &= ~mask; |
1078 | } | |
1079 | } | |
276836d4 | 1080 | nvkm_wr32(device, 0x400108, 0x01000000); |
f73221e4 BS |
1081 | trap &= ~0x01000000; |
1082 | } | |
1083 | ||
1084 | if (trap & 0x02000000) { | |
bfee3f3d | 1085 | for (rop = 0; rop < gr->rop_nr; rop++) { |
276836d4 BS |
1086 | u32 statz = nvkm_rd32(device, ROP_UNIT(rop, 0x070)); |
1087 | u32 statc = nvkm_rd32(device, ROP_UNIT(rop, 0x144)); | |
109c2f2f | 1088 | nvkm_error(subdev, "ROP%d %08x %08x\n", |
f73221e4 | 1089 | rop, statz, statc); |
276836d4 BS |
1090 | nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); |
1091 | nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); | |
f73221e4 | 1092 | } |
276836d4 | 1093 | nvkm_wr32(device, 0x400108, 0x02000000); |
f73221e4 BS |
1094 | trap &= ~0x02000000; |
1095 | } | |
1096 | ||
1097 | if (trap) { | |
109c2f2f | 1098 | nvkm_error(subdev, "TRAP UNHANDLED %08x\n", trap); |
276836d4 | 1099 | nvkm_wr32(device, 0x400108, trap); |
f73221e4 BS |
1100 | } |
1101 | } | |
1102 | ||
30f4e087 | 1103 | static void |
bfee3f3d | 1104 | gf100_gr_ctxctl_debug_unit(struct gf100_gr *gr, u32 base) |
30f4e087 | 1105 | { |
109c2f2f BS |
1106 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
1107 | struct nvkm_device *device = subdev->device; | |
1108 | nvkm_error(subdev, "%06x - done %08x\n", base, | |
1109 | nvkm_rd32(device, base + 0x400)); | |
1110 | nvkm_error(subdev, "%06x - stat %08x %08x %08x %08x\n", base, | |
1111 | nvkm_rd32(device, base + 0x800), | |
1112 | nvkm_rd32(device, base + 0x804), | |
1113 | nvkm_rd32(device, base + 0x808), | |
1114 | nvkm_rd32(device, base + 0x80c)); | |
1115 | nvkm_error(subdev, "%06x - stat %08x %08x %08x %08x\n", base, | |
1116 | nvkm_rd32(device, base + 0x810), | |
1117 | nvkm_rd32(device, base + 0x814), | |
1118 | nvkm_rd32(device, base + 0x818), | |
1119 | nvkm_rd32(device, base + 0x81c)); | |
30f4e087 BS |
1120 | } |
1121 | ||
1122 | void | |
bfee3f3d | 1123 | gf100_gr_ctxctl_debug(struct gf100_gr *gr) |
30f4e087 | 1124 | { |
276836d4 BS |
1125 | struct nvkm_device *device = gr->base.engine.subdev.device; |
1126 | u32 gpcnr = nvkm_rd32(device, 0x409604) & 0xffff; | |
30f4e087 BS |
1127 | u32 gpc; |
1128 | ||
bfee3f3d | 1129 | gf100_gr_ctxctl_debug_unit(gr, 0x409000); |
30f4e087 | 1130 | for (gpc = 0; gpc < gpcnr; gpc++) |
bfee3f3d | 1131 | gf100_gr_ctxctl_debug_unit(gr, 0x502000 + (gpc * 0x8000)); |
30f4e087 BS |
1132 | } |
1133 | ||
1134 | static void | |
bfee3f3d | 1135 | gf100_gr_ctxctl_isr(struct gf100_gr *gr) |
30f4e087 | 1136 | { |
109c2f2f BS |
1137 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
1138 | struct nvkm_device *device = subdev->device; | |
276836d4 | 1139 | u32 stat = nvkm_rd32(device, 0x409c18); |
30f4e087 | 1140 | |
23f67841 | 1141 | if (stat & 0x00000001) { |
276836d4 | 1142 | u32 code = nvkm_rd32(device, 0x409814); |
23f67841 | 1143 | if (code == E_BAD_FWMTHD) { |
276836d4 BS |
1144 | u32 class = nvkm_rd32(device, 0x409808); |
1145 | u32 addr = nvkm_rd32(device, 0x40980c); | |
23f67841 BS |
1146 | u32 subc = (addr & 0x00070000) >> 16; |
1147 | u32 mthd = (addr & 0x00003ffc); | |
276836d4 | 1148 | u32 data = nvkm_rd32(device, 0x409810); |
23f67841 | 1149 | |
109c2f2f BS |
1150 | nvkm_error(subdev, "FECS MTHD subc %d class %04x " |
1151 | "mthd %04x data %08x\n", | |
1152 | subc, class, mthd, data); | |
23f67841 | 1153 | |
276836d4 | 1154 | nvkm_wr32(device, 0x409c20, 0x00000001); |
23f67841 BS |
1155 | stat &= ~0x00000001; |
1156 | } else { | |
109c2f2f | 1157 | nvkm_error(subdev, "FECS ucode error %d\n", code); |
23f67841 BS |
1158 | } |
1159 | } | |
30f4e087 | 1160 | |
23f67841 | 1161 | if (stat & 0x00080000) { |
109c2f2f | 1162 | nvkm_error(subdev, "FECS watchdog timeout\n"); |
bfee3f3d | 1163 | gf100_gr_ctxctl_debug(gr); |
276836d4 | 1164 | nvkm_wr32(device, 0x409c20, 0x00080000); |
23f67841 BS |
1165 | stat &= ~0x00080000; |
1166 | } | |
1167 | ||
1168 | if (stat) { | |
109c2f2f | 1169 | nvkm_error(subdev, "FECS %08x\n", stat); |
bfee3f3d | 1170 | gf100_gr_ctxctl_debug(gr); |
276836d4 | 1171 | nvkm_wr32(device, 0x409c20, stat); |
23f67841 | 1172 | } |
30f4e087 BS |
1173 | } |
1174 | ||
ebb945a9 | 1175 | static void |
e3c71eb2 | 1176 | gf100_gr_intr(struct nvkm_subdev *subdev) |
ebb945a9 | 1177 | { |
276836d4 BS |
1178 | struct gf100_gr *gr = (void *)subdev; |
1179 | struct nvkm_device *device = gr->base.engine.subdev.device; | |
a65955e1 BS |
1180 | struct nvkm_fifo_chan *chan; |
1181 | unsigned long flags; | |
276836d4 BS |
1182 | u64 inst = nvkm_rd32(device, 0x409b00) & 0x0fffffff; |
1183 | u32 stat = nvkm_rd32(device, 0x400100); | |
1184 | u32 addr = nvkm_rd32(device, 0x400704); | |
ebb945a9 BS |
1185 | u32 mthd = (addr & 0x00003ffc); |
1186 | u32 subc = (addr & 0x00070000) >> 16; | |
276836d4 BS |
1187 | u32 data = nvkm_rd32(device, 0x400708); |
1188 | u32 code = nvkm_rd32(device, 0x400110); | |
91c772ec | 1189 | u32 class; |
8f0649b5 BS |
1190 | const char *name = "unknown"; |
1191 | int chid = -1; | |
72a14827 | 1192 | |
a65955e1 | 1193 | chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); |
8f0649b5 BS |
1194 | if (chan) { |
1195 | name = chan->object.client->name; | |
1196 | chid = chan->chid; | |
1197 | } | |
a65955e1 | 1198 | |
bfee3f3d | 1199 | if (nv_device(gr)->card_type < NV_E0 || subc < 4) |
276836d4 | 1200 | class = nvkm_rd32(device, 0x404200 + (subc * 4)); |
91c772ec BS |
1201 | else |
1202 | class = 0x0000; | |
1203 | ||
c6a7b026 LP |
1204 | if (stat & 0x00000001) { |
1205 | /* | |
1206 | * notifier interrupt, only needed for cyclestats | |
1207 | * can be safely ignored | |
1208 | */ | |
276836d4 | 1209 | nvkm_wr32(device, 0x400100, 0x00000001); |
c6a7b026 LP |
1210 | stat &= ~0x00000001; |
1211 | } | |
1212 | ||
ebb945a9 | 1213 | if (stat & 0x00000010) { |
a65955e1 | 1214 | if (!gf100_gr_mthd_sw(device, class, mthd, data)) { |
109c2f2f BS |
1215 | nvkm_error(subdev, "ILLEGAL_MTHD ch %d [%010llx %s] " |
1216 | "subc %d class %04x mthd %04x data %08x\n", | |
8f0649b5 BS |
1217 | chid, inst << 12, name, subc, |
1218 | class, mthd, data); | |
ebb945a9 | 1219 | } |
276836d4 | 1220 | nvkm_wr32(device, 0x400100, 0x00000010); |
ebb945a9 BS |
1221 | stat &= ~0x00000010; |
1222 | } | |
1223 | ||
1224 | if (stat & 0x00000020) { | |
109c2f2f BS |
1225 | nvkm_error(subdev, "ILLEGAL_CLASS ch %d [%010llx %s] " |
1226 | "subc %d class %04x mthd %04x data %08x\n", | |
8f0649b5 | 1227 | chid, inst << 12, name, subc, class, mthd, data); |
276836d4 | 1228 | nvkm_wr32(device, 0x400100, 0x00000020); |
ebb945a9 BS |
1229 | stat &= ~0x00000020; |
1230 | } | |
1231 | ||
1232 | if (stat & 0x00100000) { | |
109c2f2f BS |
1233 | const struct nvkm_enum *en = |
1234 | nvkm_enum_find(nv50_data_error_names, code); | |
1235 | nvkm_error(subdev, "DATA_ERROR %08x [%s] ch %d [%010llx %s] " | |
1236 | "subc %d class %04x mthd %04x data %08x\n", | |
1237 | code, en ? en->name : "", chid, inst << 12, | |
8f0649b5 | 1238 | name, subc, class, mthd, data); |
276836d4 | 1239 | nvkm_wr32(device, 0x400100, 0x00100000); |
ebb945a9 BS |
1240 | stat &= ~0x00100000; |
1241 | } | |
1242 | ||
1243 | if (stat & 0x00200000) { | |
109c2f2f | 1244 | nvkm_error(subdev, "TRAP ch %d [%010llx %s]\n", |
8f0649b5 | 1245 | chid, inst << 12, name); |
bfee3f3d | 1246 | gf100_gr_trap_intr(gr); |
276836d4 | 1247 | nvkm_wr32(device, 0x400100, 0x00200000); |
ebb945a9 BS |
1248 | stat &= ~0x00200000; |
1249 | } | |
1250 | ||
1251 | if (stat & 0x00080000) { | |
bfee3f3d | 1252 | gf100_gr_ctxctl_isr(gr); |
276836d4 | 1253 | nvkm_wr32(device, 0x400100, 0x00080000); |
ebb945a9 BS |
1254 | stat &= ~0x00080000; |
1255 | } | |
1256 | ||
1257 | if (stat) { | |
109c2f2f | 1258 | nvkm_error(subdev, "intr %08x\n", stat); |
276836d4 | 1259 | nvkm_wr32(device, 0x400100, stat); |
ebb945a9 BS |
1260 | } |
1261 | ||
276836d4 | 1262 | nvkm_wr32(device, 0x400500, 0x00010001); |
a65955e1 | 1263 | nvkm_fifo_chan_put(device->fifo, flags, &chan); |
ebb945a9 BS |
1264 | } |
1265 | ||
30f4e087 | 1266 | void |
bfee3f3d | 1267 | gf100_gr_init_fw(struct gf100_gr *gr, u32 fuc_base, |
e3c71eb2 | 1268 | struct gf100_gr_fuc *code, struct gf100_gr_fuc *data) |
ebb945a9 | 1269 | { |
276836d4 | 1270 | struct nvkm_device *device = gr->base.engine.subdev.device; |
30f4e087 | 1271 | int i; |
ebb945a9 | 1272 | |
276836d4 | 1273 | nvkm_wr32(device, fuc_base + 0x01c0, 0x01000000); |
30f4e087 | 1274 | for (i = 0; i < data->size / 4; i++) |
276836d4 | 1275 | nvkm_wr32(device, fuc_base + 0x01c4, data->data[i]); |
ebb945a9 | 1276 | |
276836d4 | 1277 | nvkm_wr32(device, fuc_base + 0x0180, 0x01000000); |
30f4e087 BS |
1278 | for (i = 0; i < code->size / 4; i++) { |
1279 | if ((i & 0x3f) == 0) | |
276836d4 BS |
1280 | nvkm_wr32(device, fuc_base + 0x0188, i >> 6); |
1281 | nvkm_wr32(device, fuc_base + 0x0184, code->data[i]); | |
30f4e087 | 1282 | } |
370eec76 AC |
1283 | |
1284 | /* code must be padded to 0x40 words */ | |
1285 | for (; i & 0x3f; i++) | |
276836d4 | 1286 | nvkm_wr32(device, fuc_base + 0x0184, 0); |
966a5b7d BS |
1287 | } |
1288 | ||
a32b2ffb | 1289 | static void |
bfee3f3d | 1290 | gf100_gr_init_csdata(struct gf100_gr *gr, |
e3c71eb2 BS |
1291 | const struct gf100_gr_pack *pack, |
1292 | u32 falcon, u32 starstar, u32 base) | |
a32b2ffb | 1293 | { |
276836d4 | 1294 | struct nvkm_device *device = gr->base.engine.subdev.device; |
e3c71eb2 BS |
1295 | const struct gf100_gr_pack *iter; |
1296 | const struct gf100_gr_init *init; | |
c33b1e8c | 1297 | u32 addr = ~0, prev = ~0, xfer = 0; |
a32b2ffb BS |
1298 | u32 star, temp; |
1299 | ||
276836d4 BS |
1300 | nvkm_wr32(device, falcon + 0x01c0, 0x02000000 + starstar); |
1301 | star = nvkm_rd32(device, falcon + 0x01c4); | |
1302 | temp = nvkm_rd32(device, falcon + 0x01c4); | |
a32b2ffb BS |
1303 | if (temp > star) |
1304 | star = temp; | |
276836d4 | 1305 | nvkm_wr32(device, falcon + 0x01c0, 0x01000000 + star); |
a32b2ffb | 1306 | |
c33b1e8c BS |
1307 | pack_for_each_init(init, iter, pack) { |
1308 | u32 head = init->addr - base; | |
1309 | u32 tail = head + init->count * init->pitch; | |
1310 | while (head < tail) { | |
1311 | if (head != prev + 4 || xfer >= 32) { | |
1312 | if (xfer) { | |
1313 | u32 data = ((--xfer << 26) | addr); | |
276836d4 | 1314 | nvkm_wr32(device, falcon + 0x01c4, data); |
c33b1e8c BS |
1315 | star += 4; |
1316 | } | |
1317 | addr = head; | |
1318 | xfer = 0; | |
a32b2ffb | 1319 | } |
c33b1e8c BS |
1320 | prev = head; |
1321 | xfer = xfer + 1; | |
1322 | head = head + init->pitch; | |
a32b2ffb | 1323 | } |
c33b1e8c | 1324 | } |
a32b2ffb | 1325 | |
276836d4 BS |
1326 | nvkm_wr32(device, falcon + 0x01c4, (--xfer << 26) | addr); |
1327 | nvkm_wr32(device, falcon + 0x01c0, 0x01000004 + starstar); | |
1328 | nvkm_wr32(device, falcon + 0x01c4, star + 4); | |
a32b2ffb BS |
1329 | } |
1330 | ||
30f4e087 | 1331 | int |
bfee3f3d | 1332 | gf100_gr_init_ctxctl(struct gf100_gr *gr) |
966a5b7d | 1333 | { |
27f3d6cf | 1334 | const struct gf100_grctx_func *grctx = gr->func->grctx; |
109c2f2f BS |
1335 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
1336 | struct nvkm_device *device = subdev->device; | |
bfee3f3d | 1337 | struct gf100_gr_oclass *oclass = (void *)nv_object(gr)->oclass; |
30f4e087 | 1338 | int i; |
ebb945a9 | 1339 | |
bfee3f3d | 1340 | if (gr->firmware) { |
30f4e087 | 1341 | /* load fuc microcode */ |
bfee3f3d BS |
1342 | nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); |
1343 | gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, | |
1344 | &gr->fuc409d); | |
1345 | gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, | |
1346 | &gr->fuc41ad); | |
1347 | nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); | |
ebb945a9 | 1348 | |
30f4e087 | 1349 | /* start both of them running */ |
276836d4 BS |
1350 | nvkm_wr32(device, 0x409840, 0xffffffff); |
1351 | nvkm_wr32(device, 0x41a10c, 0x00000000); | |
1352 | nvkm_wr32(device, 0x40910c, 0x00000000); | |
1353 | nvkm_wr32(device, 0x41a100, 0x00000002); | |
1354 | nvkm_wr32(device, 0x409100, 0x00000002); | |
c4584adc BS |
1355 | if (nvkm_msec(device, 2000, |
1356 | if (nvkm_rd32(device, 0x409800) & 0x00000001) | |
1357 | break; | |
1358 | ) < 0) | |
1359 | return -EBUSY; | |
bfee3f3d | 1360 | |
276836d4 BS |
1361 | nvkm_wr32(device, 0x409840, 0xffffffff); |
1362 | nvkm_wr32(device, 0x409500, 0x7fffffff); | |
1363 | nvkm_wr32(device, 0x409504, 0x00000021); | |
bfee3f3d | 1364 | |
276836d4 BS |
1365 | nvkm_wr32(device, 0x409840, 0xffffffff); |
1366 | nvkm_wr32(device, 0x409500, 0x00000000); | |
1367 | nvkm_wr32(device, 0x409504, 0x00000010); | |
c4584adc BS |
1368 | if (nvkm_msec(device, 2000, |
1369 | if ((gr->size = nvkm_rd32(device, 0x409800))) | |
1370 | break; | |
1371 | ) < 0) | |
30f4e087 | 1372 | return -EBUSY; |
0411de85 | 1373 | |
276836d4 BS |
1374 | nvkm_wr32(device, 0x409840, 0xffffffff); |
1375 | nvkm_wr32(device, 0x409500, 0x00000000); | |
1376 | nvkm_wr32(device, 0x409504, 0x00000016); | |
c4584adc BS |
1377 | if (nvkm_msec(device, 2000, |
1378 | if (nvkm_rd32(device, 0x409800)) | |
1379 | break; | |
1380 | ) < 0) | |
ac1499d9 | 1381 | return -EBUSY; |
ac1499d9 | 1382 | |
276836d4 BS |
1383 | nvkm_wr32(device, 0x409840, 0xffffffff); |
1384 | nvkm_wr32(device, 0x409500, 0x00000000); | |
1385 | nvkm_wr32(device, 0x409504, 0x00000025); | |
c4584adc BS |
1386 | if (nvkm_msec(device, 2000, |
1387 | if (nvkm_rd32(device, 0x409800)) | |
1388 | break; | |
1389 | ) < 0) | |
ac1499d9 | 1390 | return -EBUSY; |
ac1499d9 | 1391 | |
bfee3f3d | 1392 | if (nv_device(gr)->chipset >= 0xe0) { |
276836d4 BS |
1393 | nvkm_wr32(device, 0x409800, 0x00000000); |
1394 | nvkm_wr32(device, 0x409500, 0x00000001); | |
1395 | nvkm_wr32(device, 0x409504, 0x00000030); | |
c4584adc BS |
1396 | if (nvkm_msec(device, 2000, |
1397 | if (nvkm_rd32(device, 0x409800)) | |
1398 | break; | |
1399 | ) < 0) | |
30f4e087 | 1400 | return -EBUSY; |
30f4e087 | 1401 | |
276836d4 BS |
1402 | nvkm_wr32(device, 0x409810, 0xb00095c8); |
1403 | nvkm_wr32(device, 0x409800, 0x00000000); | |
1404 | nvkm_wr32(device, 0x409500, 0x00000001); | |
1405 | nvkm_wr32(device, 0x409504, 0x00000031); | |
c4584adc BS |
1406 | if (nvkm_msec(device, 2000, |
1407 | if (nvkm_rd32(device, 0x409800)) | |
1408 | break; | |
1409 | ) < 0) | |
30f4e087 | 1410 | return -EBUSY; |
30f4e087 | 1411 | |
276836d4 BS |
1412 | nvkm_wr32(device, 0x409810, 0x00080420); |
1413 | nvkm_wr32(device, 0x409800, 0x00000000); | |
1414 | nvkm_wr32(device, 0x409500, 0x00000001); | |
1415 | nvkm_wr32(device, 0x409504, 0x00000032); | |
c4584adc BS |
1416 | if (nvkm_msec(device, 2000, |
1417 | if (nvkm_rd32(device, 0x409800)) | |
1418 | break; | |
1419 | ) < 0) | |
30f4e087 | 1420 | return -EBUSY; |
30f4e087 | 1421 | |
276836d4 BS |
1422 | nvkm_wr32(device, 0x409614, 0x00000070); |
1423 | nvkm_wr32(device, 0x409614, 0x00000770); | |
1424 | nvkm_wr32(device, 0x40802c, 0x00000001); | |
30f4e087 BS |
1425 | } |
1426 | ||
bfee3f3d BS |
1427 | if (gr->data == NULL) { |
1428 | int ret = gf100_grctx_generate(gr); | |
ebb945a9 | 1429 | if (ret) { |
109c2f2f | 1430 | nvkm_error(subdev, "failed to construct context\n"); |
ebb945a9 BS |
1431 | return ret; |
1432 | } | |
1433 | } | |
1434 | ||
1435 | return 0; | |
96616b4c BS |
1436 | } else |
1437 | if (!oclass->fecs.ucode) { | |
1438 | return -ENOSYS; | |
0411de85 | 1439 | } |
966a5b7d | 1440 | |
ac1499d9 | 1441 | /* load HUB microcode */ |
bfee3f3d | 1442 | nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); |
276836d4 | 1443 | nvkm_wr32(device, 0x4091c0, 0x01000000); |
30f4e087 | 1444 | for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++) |
276836d4 | 1445 | nvkm_wr32(device, 0x4091c4, oclass->fecs.ucode->data.data[i]); |
ac1499d9 | 1446 | |
276836d4 | 1447 | nvkm_wr32(device, 0x409180, 0x01000000); |
30f4e087 | 1448 | for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) { |
ac1499d9 | 1449 | if ((i & 0x3f) == 0) |
276836d4 BS |
1450 | nvkm_wr32(device, 0x409188, i >> 6); |
1451 | nvkm_wr32(device, 0x409184, oclass->fecs.ucode->code.data[i]); | |
ac1499d9 BS |
1452 | } |
1453 | ||
1454 | /* load GPC microcode */ | |
276836d4 | 1455 | nvkm_wr32(device, 0x41a1c0, 0x01000000); |
30f4e087 | 1456 | for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++) |
276836d4 | 1457 | nvkm_wr32(device, 0x41a1c4, oclass->gpccs.ucode->data.data[i]); |
ac1499d9 | 1458 | |
276836d4 | 1459 | nvkm_wr32(device, 0x41a180, 0x01000000); |
30f4e087 | 1460 | for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) { |
ac1499d9 | 1461 | if ((i & 0x3f) == 0) |
276836d4 BS |
1462 | nvkm_wr32(device, 0x41a188, i >> 6); |
1463 | nvkm_wr32(device, 0x41a184, oclass->gpccs.ucode->code.data[i]); | |
ac1499d9 | 1464 | } |
bfee3f3d | 1465 | nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); |
966a5b7d | 1466 | |
c33b1e8c | 1467 | /* load register lists */ |
27f3d6cf BS |
1468 | gf100_gr_init_csdata(gr, grctx->hub, 0x409000, 0x000, 0x000000); |
1469 | gf100_gr_init_csdata(gr, grctx->gpc, 0x41a000, 0x000, 0x418000); | |
1470 | gf100_gr_init_csdata(gr, grctx->tpc, 0x41a000, 0x004, 0x419800); | |
1471 | gf100_gr_init_csdata(gr, grctx->ppc, 0x41a000, 0x008, 0x41be00); | |
a32b2ffb | 1472 | |
ac1499d9 | 1473 | /* start HUB ucode running, it'll init the GPCs */ |
276836d4 BS |
1474 | nvkm_wr32(device, 0x40910c, 0x00000000); |
1475 | nvkm_wr32(device, 0x409100, 0x00000002); | |
c4584adc BS |
1476 | if (nvkm_msec(device, 2000, |
1477 | if (nvkm_rd32(device, 0x409800) & 0x80000000) | |
1478 | break; | |
1479 | ) < 0) { | |
bfee3f3d | 1480 | gf100_gr_ctxctl_debug(gr); |
966a5b7d BS |
1481 | return -EBUSY; |
1482 | } | |
966a5b7d | 1483 | |
276836d4 | 1484 | gr->size = nvkm_rd32(device, 0x409804); |
bfee3f3d BS |
1485 | if (gr->data == NULL) { |
1486 | int ret = gf100_grctx_generate(gr); | |
ac1499d9 | 1487 | if (ret) { |
109c2f2f | 1488 | nvkm_error(subdev, "failed to construct context\n"); |
ac1499d9 BS |
1489 | return ret; |
1490 | } | |
966a5b7d BS |
1491 | } |
1492 | ||
1493 | return 0; | |
4b223eef BS |
1494 | } |
1495 | ||
30f4e087 | 1496 | int |
e3c71eb2 | 1497 | gf100_gr_init(struct nvkm_object *object) |
4b223eef | 1498 | { |
bfee3f3d | 1499 | struct gf100_gr *gr = (void *)object; |
276836d4 BS |
1500 | struct nvkm_device *device = gr->base.engine.subdev.device; |
1501 | struct gf100_gr_oclass *oclass = (void *)object->oclass; | |
bfee3f3d | 1502 | const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); |
30f4e087 BS |
1503 | u32 data[TPC_MAX / 8] = {}; |
1504 | u8 tpcnr[GPC_MAX]; | |
1505 | int gpc, tpc, rop; | |
1506 | int ret, i; | |
966a5b7d | 1507 | |
bfee3f3d | 1508 | ret = nvkm_gr_init(&gr->base); |
ebb945a9 BS |
1509 | if (ret) |
1510 | return ret; | |
1511 | ||
276836d4 BS |
1512 | nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); |
1513 | nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000); | |
1514 | nvkm_wr32(device, GPC_BCAST(0x0888), 0x00000000); | |
1515 | nvkm_wr32(device, GPC_BCAST(0x088c), 0x00000000); | |
1516 | nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); | |
1517 | nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); | |
227c95d9 BS |
1518 | nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); |
1519 | nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); | |
30f4e087 | 1520 | |
bfee3f3d | 1521 | gf100_gr_mmio(gr, oclass->mmio); |
30f4e087 | 1522 | |
bfee3f3d BS |
1523 | memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); |
1524 | for (i = 0, gpc = -1; i < gr->tpc_total; i++) { | |
30f4e087 | 1525 | do { |
bfee3f3d | 1526 | gpc = (gpc + 1) % gr->gpc_nr; |
30f4e087 | 1527 | } while (!tpcnr[gpc]); |
bfee3f3d | 1528 | tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; |
30f4e087 BS |
1529 | |
1530 | data[i / 8] |= tpc << ((i % 8) * 4); | |
1531 | } | |
1532 | ||
276836d4 BS |
1533 | nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); |
1534 | nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); | |
1535 | nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); | |
1536 | nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); | |
30f4e087 | 1537 | |
bfee3f3d | 1538 | for (gpc = 0; gpc < gr->gpc_nr; gpc++) { |
276836d4 | 1539 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), |
bfee3f3d | 1540 | gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); |
276836d4 | 1541 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | |
bfee3f3d | 1542 | gr->tpc_total); |
276836d4 | 1543 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); |
30f4e087 BS |
1544 | } |
1545 | ||
bfee3f3d | 1546 | if (nv_device(gr)->chipset != 0xd7) |
276836d4 | 1547 | nvkm_wr32(device, GPC_BCAST(0x1bd4), magicgpc918); |
26410c67 | 1548 | else |
276836d4 | 1549 | nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); |
bfee3f3d | 1550 | |
276836d4 | 1551 | nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); |
bfee3f3d | 1552 | |
276836d4 | 1553 | nvkm_wr32(device, 0x400500, 0x00010001); |
bfee3f3d | 1554 | |
276836d4 BS |
1555 | nvkm_wr32(device, 0x400100, 0xffffffff); |
1556 | nvkm_wr32(device, 0x40013c, 0xffffffff); | |
bfee3f3d | 1557 | |
276836d4 BS |
1558 | nvkm_wr32(device, 0x409c24, 0x000f0000); |
1559 | nvkm_wr32(device, 0x404000, 0xc0000000); | |
1560 | nvkm_wr32(device, 0x404600, 0xc0000000); | |
1561 | nvkm_wr32(device, 0x408030, 0xc0000000); | |
1562 | nvkm_wr32(device, 0x40601c, 0xc0000000); | |
1563 | nvkm_wr32(device, 0x404490, 0xc0000000); | |
1564 | nvkm_wr32(device, 0x406018, 0xc0000000); | |
1565 | nvkm_wr32(device, 0x405840, 0xc0000000); | |
1566 | nvkm_wr32(device, 0x405844, 0x00ffffff); | |
1567 | nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); | |
1568 | nvkm_mask(device, 0x419eb4, 0x00001000, 0x00001000); | |
bfee3f3d BS |
1569 | |
1570 | for (gpc = 0; gpc < gr->gpc_nr; gpc++) { | |
276836d4 BS |
1571 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); |
1572 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); | |
1573 | nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); | |
1574 | nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); | |
bfee3f3d | 1575 | for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { |
276836d4 BS |
1576 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); |
1577 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); | |
1578 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); | |
1579 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); | |
1580 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); | |
1581 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); | |
1582 | nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); | |
30f4e087 | 1583 | } |
276836d4 BS |
1584 | nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); |
1585 | nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); | |
30f4e087 BS |
1586 | } |
1587 | ||
bfee3f3d | 1588 | for (rop = 0; rop < gr->rop_nr; rop++) { |
276836d4 BS |
1589 | nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); |
1590 | nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); | |
1591 | nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); | |
1592 | nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); | |
30f4e087 | 1593 | } |
ebb945a9 | 1594 | |
276836d4 BS |
1595 | nvkm_wr32(device, 0x400108, 0xffffffff); |
1596 | nvkm_wr32(device, 0x400138, 0xffffffff); | |
1597 | nvkm_wr32(device, 0x400118, 0xffffffff); | |
1598 | nvkm_wr32(device, 0x400130, 0xffffffff); | |
1599 | nvkm_wr32(device, 0x40011c, 0xffffffff); | |
1600 | nvkm_wr32(device, 0x400134, 0xffffffff); | |
30f4e087 | 1601 | |
276836d4 | 1602 | nvkm_wr32(device, 0x400054, 0x34ce3464); |
ac9738bb | 1603 | |
bfee3f3d | 1604 | gf100_gr_zbc_init(gr); |
ac9738bb | 1605 | |
bfee3f3d | 1606 | return gf100_gr_init_ctxctl(gr); |
30f4e087 BS |
1607 | } |
1608 | ||
c4d0f8f6 | 1609 | void |
e3c71eb2 | 1610 | gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc) |
30f4e087 BS |
1611 | { |
1612 | kfree(fuc->data); | |
1613 | fuc->data = NULL; | |
1614 | } | |
1615 | ||
1616 | int | |
bfee3f3d | 1617 | gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, |
e3c71eb2 | 1618 | struct gf100_gr_fuc *fuc) |
30f4e087 | 1619 | { |
109c2f2f BS |
1620 | struct nvkm_subdev *subdev = &gr->base.engine.subdev; |
1621 | struct nvkm_device *device = subdev->device; | |
30f4e087 | 1622 | const struct firmware *fw; |
8539b37a AC |
1623 | char f[64]; |
1624 | char cname[16]; | |
30f4e087 | 1625 | int ret; |
8539b37a AC |
1626 | int i; |
1627 | ||
1628 | /* Convert device name to lowercase */ | |
6cf813fb | 1629 | strncpy(cname, device->chip->name, sizeof(cname)); |
8539b37a AC |
1630 | cname[sizeof(cname) - 1] = '\0'; |
1631 | i = strlen(cname); | |
1632 | while (i) { | |
1633 | --i; | |
1634 | cname[i] = tolower(cname[i]); | |
1635 | } | |
30f4e087 | 1636 | |
8539b37a | 1637 | snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); |
420b9469 | 1638 | ret = request_firmware(&fw, f, nv_device_base(device)); |
30f4e087 | 1639 | if (ret) { |
109c2f2f | 1640 | nvkm_error(subdev, "failed to load %s\n", fwname); |
8539b37a | 1641 | return ret; |
30f4e087 BS |
1642 | } |
1643 | ||
1644 | fuc->size = fw->size; | |
1645 | fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); | |
1646 | release_firmware(fw); | |
1647 | return (fuc->data != NULL) ? 0 : -ENOMEM; | |
1648 | } | |
1649 | ||
1650 | void | |
e3c71eb2 | 1651 | gf100_gr_dtor(struct nvkm_object *object) |
30f4e087 | 1652 | { |
bfee3f3d | 1653 | struct gf100_gr *gr = (void *)object; |
30f4e087 | 1654 | |
bfee3f3d | 1655 | kfree(gr->data); |
30f4e087 | 1656 | |
bfee3f3d BS |
1657 | gf100_gr_dtor_fw(&gr->fuc409c); |
1658 | gf100_gr_dtor_fw(&gr->fuc409d); | |
1659 | gf100_gr_dtor_fw(&gr->fuc41ac); | |
1660 | gf100_gr_dtor_fw(&gr->fuc41ad); | |
30f4e087 | 1661 | |
227c95d9 BS |
1662 | nvkm_memory_del(&gr->unk4188b8); |
1663 | nvkm_memory_del(&gr->unk4188b4); | |
30f4e087 | 1664 | |
bfee3f3d | 1665 | nvkm_gr_destroy(&gr->base); |
30f4e087 BS |
1666 | } |
1667 | ||
27f3d6cf BS |
1668 | static const struct nvkm_gr_func |
1669 | gf100_gr_ = { | |
1670 | .chan_new = gf100_gr_chan_new, | |
1671 | .object_get = gf100_gr_object_get, | |
1672 | }; | |
1673 | ||
30f4e087 | 1674 | int |
e3c71eb2 BS |
1675 | gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, |
1676 | struct nvkm_oclass *bclass, void *data, u32 size, | |
1677 | struct nvkm_object **pobject) | |
30f4e087 | 1678 | { |
e3c71eb2 | 1679 | struct gf100_gr_oclass *oclass = (void *)bclass; |
109c2f2f | 1680 | struct nvkm_device *device = (void *)parent; |
bfee3f3d | 1681 | struct gf100_gr *gr; |
b7c852a6 | 1682 | bool use_ext_fw, enable; |
b81146b0 | 1683 | int ret, i, j; |
30f4e087 | 1684 | |
e3c71eb2 BS |
1685 | use_ext_fw = nvkm_boolopt(device->cfgopt, "NvGrUseFW", |
1686 | oclass->fecs.ucode == NULL); | |
b7c852a6 AC |
1687 | enable = use_ext_fw || oclass->fecs.ucode != NULL; |
1688 | ||
bfee3f3d BS |
1689 | ret = nvkm_gr_create(parent, engine, bclass, enable, &gr); |
1690 | *pobject = nv_object(gr); | |
30f4e087 BS |
1691 | if (ret) |
1692 | return ret; | |
1693 | ||
27f3d6cf BS |
1694 | gr->func = oclass->func; |
1695 | gr->base.func = &gf100_gr_; | |
bfee3f3d BS |
1696 | nv_subdev(gr)->unit = 0x08001000; |
1697 | nv_subdev(gr)->intr = gf100_gr_intr; | |
30f4e087 | 1698 | |
bfee3f3d | 1699 | gr->base.units = gf100_gr_units; |
30f4e087 | 1700 | |
b7c852a6 | 1701 | if (use_ext_fw) { |
109c2f2f | 1702 | nvkm_info(&gr->base.engine.subdev, "using external firmware\n"); |
bfee3f3d BS |
1703 | if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) || |
1704 | gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) || | |
1705 | gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) || | |
1706 | gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad)) | |
c6f37e0c | 1707 | return -ENODEV; |
bfee3f3d | 1708 | gr->firmware = true; |
30f4e087 BS |
1709 | } |
1710 | ||
227c95d9 | 1711 | ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, |
bfee3f3d | 1712 | &gr->unk4188b4); |
30f4e087 BS |
1713 | if (ret) |
1714 | return ret; | |
ebb945a9 | 1715 | |
227c95d9 | 1716 | ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, |
bfee3f3d | 1717 | &gr->unk4188b8); |
b10f20d5 | 1718 | if (ret) |
a82dd49f BS |
1719 | return ret; |
1720 | ||
142ea05f BS |
1721 | nvkm_kmap(gr->unk4188b4); |
1722 | for (i = 0; i < 0x1000; i += 4) | |
1723 | nvkm_wo32(gr->unk4188b4, i, 0x00000010); | |
1724 | nvkm_done(gr->unk4188b4); | |
1725 | ||
1726 | nvkm_kmap(gr->unk4188b8); | |
1727 | for (i = 0; i < 0x1000; i += 4) | |
1728 | nvkm_wo32(gr->unk4188b8, i, 0x00000010); | |
1729 | nvkm_done(gr->unk4188b8); | |
bfee3f3d | 1730 | |
276836d4 BS |
1731 | gr->rop_nr = (nvkm_rd32(device, 0x409604) & 0x001f0000) >> 16; |
1732 | gr->gpc_nr = nvkm_rd32(device, 0x409604) & 0x0000001f; | |
bfee3f3d | 1733 | for (i = 0; i < gr->gpc_nr; i++) { |
276836d4 | 1734 | gr->tpc_nr[i] = nvkm_rd32(device, GPC_UNIT(i, 0x2608)); |
bfee3f3d BS |
1735 | gr->tpc_total += gr->tpc_nr[i]; |
1736 | gr->ppc_nr[i] = oclass->ppc_nr; | |
1737 | for (j = 0; j < gr->ppc_nr[i]; j++) { | |
276836d4 | 1738 | u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4))); |
bfee3f3d | 1739 | gr->ppc_tpc_nr[i][j] = hweight8(mask); |
b81146b0 | 1740 | } |
30f4e087 BS |
1741 | } |
1742 | ||
1743 | /*XXX: these need figuring out... though it might not even matter */ | |
bfee3f3d | 1744 | switch (nv_device(gr)->chipset) { |
30f4e087 | 1745 | case 0xc0: |
bfee3f3d BS |
1746 | if (gr->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ |
1747 | gr->magic_not_rop_nr = 0x07; | |
30f4e087 | 1748 | } else |
bfee3f3d BS |
1749 | if (gr->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ |
1750 | gr->magic_not_rop_nr = 0x05; | |
30f4e087 | 1751 | } else |
bfee3f3d BS |
1752 | if (gr->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ |
1753 | gr->magic_not_rop_nr = 0x06; | |
30f4e087 BS |
1754 | } |
1755 | break; | |
1756 | case 0xc3: /* 450, 4/0/0/0, 2 */ | |
bfee3f3d | 1757 | gr->magic_not_rop_nr = 0x03; |
30f4e087 BS |
1758 | break; |
1759 | case 0xc4: /* 460, 3/4/0/0, 4 */ | |
bfee3f3d | 1760 | gr->magic_not_rop_nr = 0x01; |
30f4e087 BS |
1761 | break; |
1762 | case 0xc1: /* 2/0/0/0, 1 */ | |
bfee3f3d | 1763 | gr->magic_not_rop_nr = 0x01; |
30f4e087 BS |
1764 | break; |
1765 | case 0xc8: /* 4/4/3/4, 5 */ | |
bfee3f3d | 1766 | gr->magic_not_rop_nr = 0x06; |
30f4e087 BS |
1767 | break; |
1768 | case 0xce: /* 4/4/0/0, 4 */ | |
bfee3f3d | 1769 | gr->magic_not_rop_nr = 0x03; |
30f4e087 BS |
1770 | break; |
1771 | case 0xcf: /* 4/0/0/0, 3 */ | |
bfee3f3d | 1772 | gr->magic_not_rop_nr = 0x03; |
30f4e087 | 1773 | break; |
26410c67 | 1774 | case 0xd7: |
30f4e087 | 1775 | case 0xd9: /* 1/0/0/0, 1 */ |
c4d0f8f6 | 1776 | case 0xea: /* gk20a */ |
a032fb9d | 1777 | case 0x12b: /* gm20b */ |
bfee3f3d | 1778 | gr->magic_not_rop_nr = 0x01; |
30f4e087 BS |
1779 | break; |
1780 | } | |
1781 | ||
4b223eef BS |
1782 | return 0; |
1783 | } | |
1784 | ||
e3c71eb2 | 1785 | #include "fuc/hubgf100.fuc3.h" |
30f4e087 | 1786 | |
e3c71eb2 BS |
1787 | struct gf100_gr_ucode |
1788 | gf100_gr_fecs_ucode = { | |
1789 | .code.data = gf100_grhub_code, | |
1790 | .code.size = sizeof(gf100_grhub_code), | |
1791 | .data.data = gf100_grhub_data, | |
1792 | .data.size = sizeof(gf100_grhub_data), | |
30f4e087 BS |
1793 | }; |
1794 | ||
e3c71eb2 | 1795 | #include "fuc/gpcgf100.fuc3.h" |
30f4e087 | 1796 | |
e3c71eb2 BS |
1797 | struct gf100_gr_ucode |
1798 | gf100_gr_gpccs_ucode = { | |
1799 | .code.data = gf100_grgpc_code, | |
1800 | .code.size = sizeof(gf100_grgpc_code), | |
1801 | .data.data = gf100_grgpc_data, | |
1802 | .data.size = sizeof(gf100_grgpc_data), | |
30f4e087 BS |
1803 | }; |
1804 | ||
27f3d6cf BS |
1805 | static const struct gf100_gr_func |
1806 | gf100_gr = { | |
1807 | .grctx = &gf100_grctx, | |
1808 | .sclass = { | |
1809 | { -1, -1, FERMI_TWOD_A }, | |
1810 | { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, | |
1811 | { -1, -1, FERMI_A, &gf100_fermi }, | |
1812 | { -1, -1, FERMI_COMPUTE_A }, | |
1813 | {} | |
1814 | } | |
1815 | }; | |
1816 | ||
e3c71eb2 BS |
1817 | struct nvkm_oclass * |
1818 | gf100_gr_oclass = &(struct gf100_gr_oclass) { | |
30f4e087 | 1819 | .base.handle = NV_ENGINE(GR, 0xc0), |
e3c71eb2 BS |
1820 | .base.ofuncs = &(struct nvkm_ofuncs) { |
1821 | .ctor = gf100_gr_ctor, | |
1822 | .dtor = gf100_gr_dtor, | |
1823 | .init = gf100_gr_init, | |
1824 | .fini = _nvkm_gr_fini, | |
ebb945a9 | 1825 | }, |
27f3d6cf | 1826 | .func = &gf100_gr, |
e3c71eb2 BS |
1827 | .mmio = gf100_gr_pack_mmio, |
1828 | .fecs.ucode = &gf100_gr_fecs_ucode, | |
1829 | .gpccs.ucode = &gf100_gr_gpccs_ucode, | |
30f4e087 | 1830 | }.base; |