]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
c79748a6fa2bd573829c9c621c164eabd247ac61
[karo-tx-linux.git] / drivers / gpu / drm / nouveau / core / engine / graph / nve0.c
1 /*
2  * Copyright 2012 Red Hat Inc.
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
25 #include "nvc0.h"
26
27 /*******************************************************************************
28  * Graphics object classes
29  ******************************************************************************/
30
31 static struct nouveau_oclass
32 nve0_graph_sclass[] = {
33         { 0x902d, &nouveau_object_ofuncs },
34         { 0xa040, &nouveau_object_ofuncs },
35         { 0xa097, &nouveau_object_ofuncs },
36         { 0xa0c0, &nouveau_object_ofuncs },
37         { 0xa0b5, &nouveau_object_ofuncs },
38         {}
39 };
40
41 /*******************************************************************************
42  * PGRAPH context
43  ******************************************************************************/
44
45 static struct nouveau_oclass
46 nve0_graph_cclass = {
47         .handle = NV_ENGCTX(GR, 0xe0),
48         .ofuncs = &(struct nouveau_ofuncs) {
49                 .ctor = nvc0_graph_context_ctor,
50                 .dtor = nvc0_graph_context_dtor,
51                 .init = _nouveau_graph_context_init,
52                 .fini = _nouveau_graph_context_fini,
53                 .rd32 = _nouveau_graph_context_rd32,
54                 .wr32 = _nouveau_graph_context_wr32,
55         },
56 };
57
58 /*******************************************************************************
59  * PGRAPH engine/subdev functions
60  ******************************************************************************/
61
62 static void
63 nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
64 {
65         u32 ustat = nv_rd32(priv, 0x409c18);
66
67         if (ustat & 0x00000001)
68                 nv_error(priv, "CTXCTRL ucode error\n");
69         if (ustat & 0x00080000)
70                 nv_error(priv, "CTXCTRL watchdog timeout\n");
71         if (ustat & ~0x00080001)
72                 nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
73
74         nvc0_graph_ctxctl_debug(priv);
75         nv_wr32(priv, 0x409c20, ustat);
76 }
77
78 static void
79 nve0_graph_trap_isr(struct nvc0_graph_priv *priv, u64 inst)
80 {
81         u32 trap = nv_rd32(priv, 0x400108);
82         int rop;
83
84         if (trap & 0x00000001) {
85                 u32 stat = nv_rd32(priv, 0x404000);
86                 nv_error(priv, "DISPATCH ch 0x%010llx 0x%08x\n", inst, stat);
87                 nv_wr32(priv, 0x404000, 0xc0000000);
88                 nv_wr32(priv, 0x400108, 0x00000001);
89                 trap &= ~0x00000001;
90         }
91
92         if (trap & 0x00000010) {
93                 u32 stat = nv_rd32(priv, 0x405840);
94                 nv_error(priv, "SHADER ch 0x%010llx 0x%08x\n", inst, stat);
95                 nv_wr32(priv, 0x405840, 0xc0000000);
96                 nv_wr32(priv, 0x400108, 0x00000010);
97                 trap &= ~0x00000010;
98         }
99
100         if (trap & 0x02000000) {
101                 for (rop = 0; rop < priv->rop_nr; rop++) {
102                         u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
103                         u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
104                         nv_error(priv, "ROP%d ch 0x%010llx 0x%08x 0x%08x\n",
105                                      rop, inst, statz, statc);
106                         nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
107                         nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
108                 }
109                 nv_wr32(priv, 0x400108, 0x02000000);
110                 trap &= ~0x02000000;
111         }
112
113         if (trap) {
114                 nv_error(priv, "TRAP ch 0x%010llx 0x%08x\n", inst, trap);
115                 nv_wr32(priv, 0x400108, trap);
116         }
117 }
118
119 static void
120 nve0_graph_intr(struct nouveau_subdev *subdev)
121 {
122         struct nvc0_graph_priv *priv = (void *)subdev;
123         struct nouveau_engine *engine = nv_engine(subdev);
124         struct nouveau_handle *handle = NULL;
125         u64 inst = (u64)(nv_rd32(priv, 0x409b00) & 0x0fffffff) << 12;
126         u32 stat = nv_rd32(priv, 0x400100);
127         u32 addr = nv_rd32(priv, 0x400704);
128         u32 mthd = (addr & 0x00003ffc);
129         u32 subc = (addr & 0x00070000) >> 16;
130         u32 data = nv_rd32(priv, 0x400708);
131         u32 code = nv_rd32(priv, 0x400110);
132         u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
133
134         if (stat & 0x00000010) {
135                 handle = nouveau_engctx_lookup_class(engine, inst, class);
136                 if (!handle || nv_call(handle->object, mthd, data)) {
137                         nv_error(priv, "ILLEGAL_MTHD ch 0x%010llx "
138                                      "subc %d class 0x%04x mthd 0x%04x "
139                                      "data 0x%08x\n",
140                                  inst, subc, class, mthd, data);
141                 }
142                 nouveau_engctx_handle_put(handle);
143                 nv_wr32(priv, 0x400100, 0x00000010);
144                 stat &= ~0x00000010;
145         }
146
147         if (stat & 0x00000020) {
148                 nv_error(priv, "ILLEGAL_CLASS ch 0x%010llx subc %d "
149                              "class 0x%04x mthd 0x%04x data 0x%08x\n",
150                          inst, subc, class, mthd, data);
151                 nv_wr32(priv, 0x400100, 0x00000020);
152                 stat &= ~0x00000020;
153         }
154
155         if (stat & 0x00100000) {
156                 nv_error(priv, "DATA_ERROR [");
157                 nouveau_enum_print(nv50_data_error_names, code);
158                 printk("] ch 0x%010llx subc %d class 0x%04x "
159                        "mthd 0x%04x data 0x%08x\n",
160                        inst, subc, class, mthd, data);
161                 nv_wr32(priv, 0x400100, 0x00100000);
162                 stat &= ~0x00100000;
163         }
164
165         if (stat & 0x00200000) {
166                 nve0_graph_trap_isr(priv, inst);
167                 nv_wr32(priv, 0x400100, 0x00200000);
168                 stat &= ~0x00200000;
169         }
170
171         if (stat & 0x00080000) {
172                 nve0_graph_ctxctl_isr(priv);
173                 nv_wr32(priv, 0x400100, 0x00080000);
174                 stat &= ~0x00080000;
175         }
176
177         if (stat) {
178                 nv_error(priv, "unknown stat 0x%08x\n", stat);
179                 nv_wr32(priv, 0x400100, stat);
180         }
181
182         nv_wr32(priv, 0x400500, 0x00010001);
183 }
184
185 static int
186 nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
187                struct nouveau_oclass *oclass, void *data, u32 size,
188                struct nouveau_object **pobject)
189 {
190         struct nvc0_graph_priv *priv;
191         int ret, i;
192
193         ret = nouveau_graph_create(parent, engine, oclass, false, &priv);
194         *pobject = nv_object(priv);
195         if (ret)
196                 return ret;
197
198         nv_subdev(priv)->unit = 0x18001000;
199         nv_subdev(priv)->intr = nve0_graph_intr;
200         nv_engine(priv)->cclass = &nve0_graph_cclass;
201         nv_engine(priv)->sclass = nve0_graph_sclass;
202
203         nv_info(priv, "using external firmware\n");
204         if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
205             nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
206             nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
207             nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
208                 return -EINVAL;
209         priv->firmware = true;
210
211         ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b4);
212         if (ret)
213                 return ret;
214
215         ret = nouveau_gpuobj_new(parent, NULL, 0x1000, 256, 0, &priv->unk4188b8);
216         if (ret)
217                 return ret;
218
219         for (i = 0; i < 0x1000; i += 4) {
220                 nv_wo32(priv->unk4188b4, i, 0x00000010);
221                 nv_wo32(priv->unk4188b8, i, 0x00000010);
222         }
223
224         priv->gpc_nr =  nv_rd32(priv, 0x409604) & 0x0000001f;
225         priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
226         for (i = 0; i < priv->gpc_nr; i++) {
227                 priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
228                 priv->tpc_total += priv->tpc_nr[i];
229         }
230
231         switch (nv_device(priv)->chipset) {
232         case 0xe4:
233                 if (priv->tpc_total == 8)
234                         priv->magic_not_rop_nr = 3;
235                 else
236                 if (priv->tpc_total == 7)
237                         priv->magic_not_rop_nr = 1;
238                 break;
239         case 0xe7:
240                 priv->magic_not_rop_nr = 1;
241                 break;
242         default:
243                 break;
244         }
245
246         return 0;
247 }
248
249 static void
250 nve0_graph_init_obj418880(struct nvc0_graph_priv *priv)
251 {
252         int i;
253
254         nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
255         nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
256         for (i = 0; i < 4; i++)
257                 nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
258         nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
259         nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
260 }
261
262 static void
263 nve0_graph_init_regs(struct nvc0_graph_priv *priv)
264 {
265         nv_wr32(priv, 0x400080, 0x003083c2);
266         nv_wr32(priv, 0x400088, 0x0001ffe7);
267         nv_wr32(priv, 0x40008c, 0x00000000);
268         nv_wr32(priv, 0x400090, 0x00000030);
269         nv_wr32(priv, 0x40013c, 0x003901f7);
270         nv_wr32(priv, 0x400140, 0x00000100);
271         nv_wr32(priv, 0x400144, 0x00000000);
272         nv_wr32(priv, 0x400148, 0x00000110);
273         nv_wr32(priv, 0x400138, 0x00000000);
274         nv_wr32(priv, 0x400130, 0x00000000);
275         nv_wr32(priv, 0x400134, 0x00000000);
276         nv_wr32(priv, 0x400124, 0x00000002);
277 }
278
279 static void
280 nve0_graph_init_units(struct nvc0_graph_priv *priv)
281 {
282         nv_wr32(priv, 0x409ffc, 0x00000000);
283         nv_wr32(priv, 0x409c14, 0x00003e3e);
284         nv_wr32(priv, 0x409c24, 0x000f0000);
285
286         nv_wr32(priv, 0x404000, 0xc0000000);
287         nv_wr32(priv, 0x404600, 0xc0000000);
288         nv_wr32(priv, 0x408030, 0xc0000000);
289         nv_wr32(priv, 0x404490, 0xc0000000);
290         nv_wr32(priv, 0x406018, 0xc0000000);
291         nv_wr32(priv, 0x407020, 0xc0000000);
292         nv_wr32(priv, 0x405840, 0xc0000000);
293         nv_wr32(priv, 0x405844, 0x00ffffff);
294
295         nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
296         nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
297
298 }
299
300 static void
301 nve0_graph_init_gpc_0(struct nvc0_graph_priv *priv)
302 {
303         const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
304         u32 data[TPC_MAX / 8];
305         u8  tpcnr[GPC_MAX];
306         int i, gpc, tpc;
307
308         nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
309
310         memset(data, 0x00, sizeof(data));
311         memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
312         for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
313                 do {
314                         gpc = (gpc + 1) % priv->gpc_nr;
315                 } while (!tpcnr[gpc]);
316                 tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
317
318                 data[i / 8] |= tpc << ((i % 8) * 4);
319         }
320
321         nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
322         nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
323         nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
324         nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
325
326         for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
327                 nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
328                                                   priv->tpc_nr[gpc]);
329                 nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
330                 nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
331         }
332
333         nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
334         nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
335 }
336
337 static void
338 nve0_graph_init_gpc_1(struct nvc0_graph_priv *priv)
339 {
340         int gpc, tpc;
341
342         for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
343                 nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
344                 nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
345                 nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
346                 nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
347                 nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
348                 for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
349                         nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
350                         nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
351                         nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
352                         nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
353                         nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
354                         nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
355                         nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
356                 }
357                 nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
358                 nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
359         }
360 }
361
362 static void
363 nve0_graph_init_rop(struct nvc0_graph_priv *priv)
364 {
365         int rop;
366
367         for (rop = 0; rop < priv->rop_nr; rop++) {
368                 nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
369                 nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
370                 nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
371                 nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
372         }
373 }
374
375 static int
376 nve0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
377 {
378         u32 r000260;
379
380         /* load fuc microcode */
381         r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
382         nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, &priv->fuc409d);
383         nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
384         nv_wr32(priv, 0x000260, r000260);
385
386         /* start both of them running */
387         nv_wr32(priv, 0x409840, 0xffffffff);
388         nv_wr32(priv, 0x41a10c, 0x00000000);
389         nv_wr32(priv, 0x40910c, 0x00000000);
390         nv_wr32(priv, 0x41a100, 0x00000002);
391         nv_wr32(priv, 0x409100, 0x00000002);
392         if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
393                 nv_error(priv, "0x409800 wait failed\n");
394
395         nv_wr32(priv, 0x409840, 0xffffffff);
396         nv_wr32(priv, 0x409500, 0x7fffffff);
397         nv_wr32(priv, 0x409504, 0x00000021);
398
399         nv_wr32(priv, 0x409840, 0xffffffff);
400         nv_wr32(priv, 0x409500, 0x00000000);
401         nv_wr32(priv, 0x409504, 0x00000010);
402         if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
403                 nv_error(priv, "fuc09 req 0x10 timeout\n");
404                 return -EBUSY;
405         }
406         priv->size = nv_rd32(priv, 0x409800);
407
408         nv_wr32(priv, 0x409840, 0xffffffff);
409         nv_wr32(priv, 0x409500, 0x00000000);
410         nv_wr32(priv, 0x409504, 0x00000016);
411         if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
412                 nv_error(priv, "fuc09 req 0x16 timeout\n");
413                 return -EBUSY;
414         }
415
416         nv_wr32(priv, 0x409840, 0xffffffff);
417         nv_wr32(priv, 0x409500, 0x00000000);
418         nv_wr32(priv, 0x409504, 0x00000025);
419         if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
420                 nv_error(priv, "fuc09 req 0x25 timeout\n");
421                 return -EBUSY;
422         }
423
424         nv_wr32(priv, 0x409800, 0x00000000);
425         nv_wr32(priv, 0x409500, 0x00000001);
426         nv_wr32(priv, 0x409504, 0x00000030);
427         if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
428                 nv_error(priv, "fuc09 req 0x30 timeout\n");
429                 return -EBUSY;
430         }
431
432         nv_wr32(priv, 0x409810, 0xb00095c8);
433         nv_wr32(priv, 0x409800, 0x00000000);
434         nv_wr32(priv, 0x409500, 0x00000001);
435         nv_wr32(priv, 0x409504, 0x00000031);
436         if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
437                 nv_error(priv, "fuc09 req 0x31 timeout\n");
438                 return -EBUSY;
439         }
440
441         nv_wr32(priv, 0x409810, 0x00080420);
442         nv_wr32(priv, 0x409800, 0x00000000);
443         nv_wr32(priv, 0x409500, 0x00000001);
444         nv_wr32(priv, 0x409504, 0x00000032);
445         if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
446                 nv_error(priv, "fuc09 req 0x32 timeout\n");
447                 return -EBUSY;
448         }
449
450         nv_wr32(priv, 0x409614, 0x00000070);
451         nv_wr32(priv, 0x409614, 0x00000770);
452         nv_wr32(priv, 0x40802c, 0x00000001);
453
454         if (priv->data == NULL) {
455                 int ret = nve0_grctx_generate(priv);
456                 if (ret) {
457                         nv_error(priv, "failed to construct context\n");
458                         return ret;
459                 }
460
461                 return 1;
462         }
463
464         return 0;
465 }
466
467 static int
468 nve0_graph_init(struct nouveau_object *object)
469 {
470         struct nvc0_graph_priv *priv = (void *)object;
471         int ret;
472
473 reset:
474         ret = nouveau_graph_init(&priv->base);
475         if (ret)
476                 return ret;
477
478         nve0_graph_init_obj418880(priv);
479         nve0_graph_init_regs(priv);
480         nve0_graph_init_gpc_0(priv);
481
482         nv_wr32(priv, 0x400500, 0x00010001);
483         nv_wr32(priv, 0x400100, 0xffffffff);
484         nv_wr32(priv, 0x40013c, 0xffffffff);
485
486         nve0_graph_init_units(priv);
487         nve0_graph_init_gpc_1(priv);
488         nve0_graph_init_rop(priv);
489
490         nv_wr32(priv, 0x400108, 0xffffffff);
491         nv_wr32(priv, 0x400138, 0xffffffff);
492         nv_wr32(priv, 0x400118, 0xffffffff);
493         nv_wr32(priv, 0x400130, 0xffffffff);
494         nv_wr32(priv, 0x40011c, 0xffffffff);
495         nv_wr32(priv, 0x400134, 0xffffffff);
496         nv_wr32(priv, 0x400054, 0x34ce3464);
497
498         ret = nve0_graph_init_ctxctl(priv);
499         if (ret) {
500                 if (ret == 1)
501                         goto reset;
502                 return ret;
503         }
504
505         return 0;
506 }
507
508 struct nouveau_oclass
509 nve0_graph_oclass = {
510         .handle = NV_ENGINE(GR, 0xe0),
511         .ofuncs = &(struct nouveau_ofuncs) {
512                 .ctor = nve0_graph_ctor,
513                 .dtor = nvc0_graph_dtor,
514                 .init = nve0_graph_init,
515                 .fini = _nouveau_graph_fini,
516         },
517 };