2 * Copyright 2012 Red Hat Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include "fuc/hubnvc0.fuc.h"
27 #include "fuc/gpcnvc0.fuc.h"
29 /*******************************************************************************
30 * Graphics object classes
31 ******************************************************************************/
33 static struct nouveau_oclass
34 nvc0_graph_sclass
[] = {
35 { 0x902d, &nouveau_object_ofuncs
},
36 { 0x9039, &nouveau_object_ofuncs
},
37 { 0x9097, &nouveau_object_ofuncs
},
38 { 0x90c0, &nouveau_object_ofuncs
},
42 static struct nouveau_oclass
43 nvc1_graph_sclass
[] = {
44 { 0x902d, &nouveau_object_ofuncs
},
45 { 0x9039, &nouveau_object_ofuncs
},
46 { 0x9097, &nouveau_object_ofuncs
},
47 { 0x90c0, &nouveau_object_ofuncs
},
48 { 0x9197, &nouveau_object_ofuncs
},
52 static struct nouveau_oclass
53 nvc8_graph_sclass
[] = {
54 { 0x902d, &nouveau_object_ofuncs
},
55 { 0x9039, &nouveau_object_ofuncs
},
56 { 0x9097, &nouveau_object_ofuncs
},
57 { 0x90c0, &nouveau_object_ofuncs
},
58 { 0x9197, &nouveau_object_ofuncs
},
59 { 0x9297, &nouveau_object_ofuncs
},
63 /*******************************************************************************
65 ******************************************************************************/
68 nvc0_graph_context_ctor(struct nouveau_object
*parent
,
69 struct nouveau_object
*engine
,
70 struct nouveau_oclass
*oclass
, void *args
, u32 size
,
71 struct nouveau_object
**pobject
)
73 struct nouveau_vm
*vm
= nouveau_client(parent
)->vm
;
74 struct nvc0_graph_priv
*priv
= (void *)engine
;
75 struct nvc0_graph_data
*data
= priv
->mmio_data
;
76 struct nvc0_graph_mmio
*mmio
= priv
->mmio_list
;
77 struct nvc0_graph_chan
*chan
;
80 /* allocate memory for context, and fill with default values */
81 ret
= nouveau_graph_context_create(parent
, engine
, oclass
, NULL
,
83 NVOBJ_FLAG_ZERO_ALLOC
, &chan
);
84 *pobject
= nv_object(chan
);
88 /* allocate memory for a "mmio list" buffer that's used by the HUB
89 * fuc to modify some per-context register settings on first load
92 ret
= nouveau_gpuobj_new(parent
, NULL
, 0x1000, 0x100, 0, &chan
->mmio
);
96 ret
= nouveau_gpuobj_map_vm(nv_gpuobj(chan
->mmio
), vm
,
97 NV_MEM_ACCESS_RW
| NV_MEM_ACCESS_SYS
,
102 /* allocate buffers referenced by mmio list */
103 for (i
= 0; data
->size
&& i
< ARRAY_SIZE(priv
->mmio_data
); i
++) {
104 ret
= nouveau_gpuobj_new(parent
, NULL
, data
->size
, data
->align
,
105 0, &chan
->data
[i
].mem
);
109 ret
= nouveau_gpuobj_map_vm(chan
->data
[i
].mem
, vm
, data
->access
,
117 /* finally, fill in the mmio list and point the context at it */
118 for (i
= 0; mmio
->addr
&& i
< ARRAY_SIZE(priv
->mmio_list
); i
++) {
119 u32 addr
= mmio
->addr
;
120 u32 data
= mmio
->data
;
123 u64 info
= chan
->data
[mmio
->buffer
].vma
.offset
;
124 data
|= info
>> mmio
->shift
;
127 nv_wo32(chan
->mmio
, chan
->mmio_nr
++ * 4, addr
);
128 nv_wo32(chan
->mmio
, chan
->mmio_nr
++ * 4, data
);
132 for (i
= 0; i
< priv
->size
; i
+= 4)
133 nv_wo32(chan
, i
, priv
->data
[i
/ 4]);
135 if (!priv
->firmware
) {
136 nv_wo32(chan
, 0x00, chan
->mmio_nr
/ 2);
137 nv_wo32(chan
, 0x04, chan
->mmio_vma
.offset
>> 8);
139 nv_wo32(chan
, 0xf4, 0);
140 nv_wo32(chan
, 0xf8, 0);
141 nv_wo32(chan
, 0x10, chan
->mmio_nr
/ 2);
142 nv_wo32(chan
, 0x14, lower_32_bits(chan
->mmio_vma
.offset
));
143 nv_wo32(chan
, 0x18, upper_32_bits(chan
->mmio_vma
.offset
));
144 nv_wo32(chan
, 0x1c, 1);
145 nv_wo32(chan
, 0x20, 0);
146 nv_wo32(chan
, 0x28, 0);
147 nv_wo32(chan
, 0x2c, 0);
154 nvc0_graph_context_dtor(struct nouveau_object
*object
)
156 struct nvc0_graph_chan
*chan
= (void *)object
;
159 for (i
= 0; i
< ARRAY_SIZE(chan
->data
); i
++) {
160 nouveau_gpuobj_unmap(&chan
->data
[i
].vma
);
161 nouveau_gpuobj_ref(NULL
, &chan
->data
[i
].mem
);
164 nouveau_gpuobj_unmap(&chan
->mmio_vma
);
165 nouveau_gpuobj_ref(NULL
, &chan
->mmio
);
167 nouveau_graph_context_destroy(&chan
->base
);
170 static struct nouveau_oclass
171 nvc0_graph_cclass
= {
172 .ofuncs
= &(struct nouveau_ofuncs
) {
173 .ctor
= nvc0_graph_context_ctor
,
174 .dtor
= nvc0_graph_context_dtor
,
175 .init
= _nouveau_graph_context_init
,
176 .fini
= _nouveau_graph_context_fini
,
177 .rd32
= _nouveau_graph_context_rd32
,
178 .wr32
= _nouveau_graph_context_wr32
,
182 /*******************************************************************************
183 * PGRAPH engine/subdev functions
184 ******************************************************************************/
187 nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv
*priv
, u32 base
)
189 nv_error(priv
, "%06x - done 0x%08x\n", base
,
190 nv_rd32(priv
, base
+ 0x400));
191 nv_error(priv
, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base
,
192 nv_rd32(priv
, base
+ 0x800), nv_rd32(priv
, base
+ 0x804),
193 nv_rd32(priv
, base
+ 0x808), nv_rd32(priv
, base
+ 0x80c));
194 nv_error(priv
, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base
,
195 nv_rd32(priv
, base
+ 0x810), nv_rd32(priv
, base
+ 0x814),
196 nv_rd32(priv
, base
+ 0x818), nv_rd32(priv
, base
+ 0x81c));
200 nvc0_graph_ctxctl_debug(struct nvc0_graph_priv
*priv
)
202 u32 gpcnr
= nv_rd32(priv
, 0x409604) & 0xffff;
205 nvc0_graph_ctxctl_debug_unit(priv
, 0x409000);
206 for (gpc
= 0; gpc
< gpcnr
; gpc
++)
207 nvc0_graph_ctxctl_debug_unit(priv
, 0x502000 + (gpc
* 0x8000));
211 nvc0_graph_ctxctl_isr(struct nvc0_graph_priv
*priv
)
213 u32 ustat
= nv_rd32(priv
, 0x409c18);
215 if (ustat
& 0x00000001)
216 nv_error(priv
, "CTXCTRL ucode error\n");
217 if (ustat
& 0x00080000)
218 nv_error(priv
, "CTXCTRL watchdog timeout\n");
219 if (ustat
& ~0x00080001)
220 nv_error(priv
, "CTXCTRL 0x%08x\n", ustat
);
222 nvc0_graph_ctxctl_debug(priv
);
223 nv_wr32(priv
, 0x409c20, ustat
);
227 nvc0_graph_intr(struct nouveau_subdev
*subdev
)
229 struct nvc0_graph_priv
*priv
= (void *)subdev
;
230 struct nouveau_engine
*engine
= nv_engine(subdev
);
231 struct nouveau_handle
*handle
= NULL
;
232 u64 inst
= (u64
)(nv_rd32(priv
, 0x409b00) & 0x0fffffff) << 12;
233 u32 stat
= nv_rd32(priv
, 0x400100);
234 u32 addr
= nv_rd32(priv
, 0x400704);
235 u32 mthd
= (addr
& 0x00003ffc);
236 u32 subc
= (addr
& 0x00070000) >> 16;
237 u32 data
= nv_rd32(priv
, 0x400708);
238 u32 code
= nv_rd32(priv
, 0x400110);
239 u32
class = nv_rd32(priv
, 0x404200 + (subc
* 4));
241 if (stat
& 0x00000010) {
242 handle
= nouveau_engctx_lookup_class(engine
, inst
, class);
243 if (!handle
|| nv_call(handle
->object
, mthd
, data
)) {
244 nv_error(priv
, "ILLEGAL_MTHD ch 0x%010llx "
245 "subc %d class 0x%04x mthd 0x%04x "
247 inst
, subc
, class, mthd
, data
);
249 nouveau_engctx_handle_put(handle
);
250 nv_wr32(priv
, 0x400100, 0x00000010);
254 if (stat
& 0x00000020) {
255 nv_error(priv
, "ILLEGAL_CLASS ch 0x%010llx subc %d "
256 "class 0x%04x mthd 0x%04x data 0x%08x\n",
257 inst
, subc
, class, mthd
, data
);
258 nv_wr32(priv
, 0x400100, 0x00000020);
262 if (stat
& 0x00100000) {
263 nv_error(priv
, "DATA_ERROR [");
264 nouveau_enum_print(nv50_data_error_names
, code
);
265 printk("] ch 0x%010llx subc %d class 0x%04x "
266 "mthd 0x%04x data 0x%08x\n",
267 inst
, subc
, class, mthd
, data
);
268 nv_wr32(priv
, 0x400100, 0x00100000);
272 if (stat
& 0x00200000) {
273 u32 trap
= nv_rd32(priv
, 0x400108);
274 nv_error(priv
, "TRAP ch 0x%010llx status 0x%08x\n", inst
, trap
);
275 nv_wr32(priv
, 0x400108, trap
);
276 nv_wr32(priv
, 0x400100, 0x00200000);
280 if (stat
& 0x00080000) {
281 nvc0_graph_ctxctl_isr(priv
);
282 nv_wr32(priv
, 0x400100, 0x00080000);
287 nv_error(priv
, "unknown stat 0x%08x\n", stat
);
288 nv_wr32(priv
, 0x400100, stat
);
291 nv_wr32(priv
, 0x400500, 0x00010001);
295 nvc0_graph_ctor_fw(struct nvc0_graph_priv
*priv
, const char *fwname
,
296 struct nvc0_graph_fuc
*fuc
)
298 struct nouveau_device
*device
= nv_device(priv
);
299 const struct firmware
*fw
;
303 snprintf(f
, sizeof(f
), "nouveau/nv%02x_%s", device
->chipset
, fwname
);
304 ret
= request_firmware(&fw
, f
, &device
->pdev
->dev
);
306 snprintf(f
, sizeof(f
), "nouveau/%s", fwname
);
307 ret
= request_firmware(&fw
, f
, &device
->pdev
->dev
);
309 nv_error(priv
, "failed to load %s\n", fwname
);
314 fuc
->size
= fw
->size
;
315 fuc
->data
= kmemdup(fw
->data
, fuc
->size
, GFP_KERNEL
);
316 release_firmware(fw
);
317 return (fuc
->data
!= NULL
) ? 0 : -ENOMEM
;
321 nvc0_graph_ctor(struct nouveau_object
*parent
, struct nouveau_object
*engine
,
322 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
323 struct nouveau_object
**pobject
)
325 struct nouveau_device
*device
= nv_device(parent
);
326 struct nvc0_graph_priv
*priv
;
330 switch (device
->chipset
) {
331 case 0xd9: /* known broken without binary driver firmware */
338 ret
= nouveau_graph_create(parent
, engine
, oclass
, enable
, &priv
);
339 *pobject
= nv_object(priv
);
343 nv_subdev(priv
)->unit
= 0x18001000;
344 nv_subdev(priv
)->intr
= nvc0_graph_intr
;
345 nv_engine(priv
)->cclass
= &nvc0_graph_cclass
;
347 if (nouveau_boolopt(device
->cfgopt
, "NvGrUseFW", false)) {
348 nv_info(priv
, "using external firmware\n");
349 if (nvc0_graph_ctor_fw(priv
, "fuc409c", &priv
->fuc409c
) ||
350 nvc0_graph_ctor_fw(priv
, "fuc409d", &priv
->fuc409d
) ||
351 nvc0_graph_ctor_fw(priv
, "fuc41ac", &priv
->fuc41ac
) ||
352 nvc0_graph_ctor_fw(priv
, "fuc41ad", &priv
->fuc41ad
))
354 priv
->firmware
= true;
357 switch (nvc0_graph_class(priv
)) {
359 nv_engine(priv
)->sclass
= nvc0_graph_sclass
;
362 nv_engine(priv
)->sclass
= nvc1_graph_sclass
;
365 nv_engine(priv
)->sclass
= nvc8_graph_sclass
;
369 ret
= nouveau_gpuobj_new(parent
, NULL
, 0x1000, 256, 0, &priv
->unk4188b4
);
373 ret
= nouveau_gpuobj_new(parent
, NULL
, 0x1000, 256, 0, &priv
->unk4188b8
);
377 for (i
= 0; i
< 0x1000; i
+= 4) {
378 nv_wo32(priv
->unk4188b4
, i
, 0x00000010);
379 nv_wo32(priv
->unk4188b8
, i
, 0x00000010);
382 priv
->rop_nr
= (nv_rd32(priv
, 0x409604) & 0x001f0000) >> 16;
383 priv
->gpc_nr
= nv_rd32(priv
, 0x409604) & 0x0000001f;
384 for (i
= 0; i
< priv
->gpc_nr
; i
++) {
385 priv
->tpc_nr
[i
] = nv_rd32(priv
, GPC_UNIT(i
, 0x2608));
386 priv
->tpc_total
+= priv
->tpc_nr
[i
];
389 /*XXX: these need figuring out... though it might not even matter */
390 switch (nv_device(priv
)->chipset
) {
392 if (priv
->tpc_total
== 11) { /* 465, 3/4/4/0, 4 */
393 priv
->magic_not_rop_nr
= 0x07;
395 if (priv
->tpc_total
== 14) { /* 470, 3/3/4/4, 5 */
396 priv
->magic_not_rop_nr
= 0x05;
398 if (priv
->tpc_total
== 15) { /* 480, 3/4/4/4, 6 */
399 priv
->magic_not_rop_nr
= 0x06;
402 case 0xc3: /* 450, 4/0/0/0, 2 */
403 priv
->magic_not_rop_nr
= 0x03;
405 case 0xc4: /* 460, 3/4/0/0, 4 */
406 priv
->magic_not_rop_nr
= 0x01;
408 case 0xc1: /* 2/0/0/0, 1 */
409 priv
->magic_not_rop_nr
= 0x01;
411 case 0xc8: /* 4/4/3/4, 5 */
412 priv
->magic_not_rop_nr
= 0x06;
414 case 0xce: /* 4/4/0/0, 4 */
415 priv
->magic_not_rop_nr
= 0x03;
417 case 0xcf: /* 4/0/0/0, 3 */
418 priv
->magic_not_rop_nr
= 0x03;
420 case 0xd9: /* 1/0/0/0, 1 */
421 priv
->magic_not_rop_nr
= 0x01;
429 nvc0_graph_dtor_fw(struct nvc0_graph_fuc
*fuc
)
438 nvc0_graph_dtor(struct nouveau_object
*object
)
440 struct nvc0_graph_priv
*priv
= (void *)object
;
445 nvc0_graph_dtor_fw(&priv
->fuc409c
);
446 nvc0_graph_dtor_fw(&priv
->fuc409d
);
447 nvc0_graph_dtor_fw(&priv
->fuc41ac
);
448 nvc0_graph_dtor_fw(&priv
->fuc41ad
);
450 nouveau_gpuobj_ref(NULL
, &priv
->unk4188b8
);
451 nouveau_gpuobj_ref(NULL
, &priv
->unk4188b4
);
453 nouveau_graph_destroy(&priv
->base
);
457 nvc0_graph_init_obj418880(struct nvc0_graph_priv
*priv
)
461 nv_wr32(priv
, GPC_BCAST(0x0880), 0x00000000);
462 nv_wr32(priv
, GPC_BCAST(0x08a4), 0x00000000);
463 for (i
= 0; i
< 4; i
++)
464 nv_wr32(priv
, GPC_BCAST(0x0888) + (i
* 4), 0x00000000);
465 nv_wr32(priv
, GPC_BCAST(0x08b4), priv
->unk4188b4
->addr
>> 8);
466 nv_wr32(priv
, GPC_BCAST(0x08b8), priv
->unk4188b8
->addr
>> 8);
470 nvc0_graph_init_regs(struct nvc0_graph_priv
*priv
)
472 nv_wr32(priv
, 0x400080, 0x003083c2);
473 nv_wr32(priv
, 0x400088, 0x00006fe7);
474 nv_wr32(priv
, 0x40008c, 0x00000000);
475 nv_wr32(priv
, 0x400090, 0x00000030);
476 nv_wr32(priv
, 0x40013c, 0x013901f7);
477 nv_wr32(priv
, 0x400140, 0x00000100);
478 nv_wr32(priv
, 0x400144, 0x00000000);
479 nv_wr32(priv
, 0x400148, 0x00000110);
480 nv_wr32(priv
, 0x400138, 0x00000000);
481 nv_wr32(priv
, 0x400130, 0x00000000);
482 nv_wr32(priv
, 0x400134, 0x00000000);
483 nv_wr32(priv
, 0x400124, 0x00000002);
487 nvc0_graph_init_gpc_0(struct nvc0_graph_priv
*priv
)
489 const u32 magicgpc918
= DIV_ROUND_UP(0x00800000, priv
->tpc_total
);
490 u32 data
[TPC_MAX
/ 8];
494 nv_wr32(priv
, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */
497 * TP ROP UNKVAL(magic_not_rop_nr)
505 memset(data
, 0x00, sizeof(data
));
506 memcpy(tpcnr
, priv
->tpc_nr
, sizeof(priv
->tpc_nr
));
507 for (i
= 0, gpc
= -1; i
< priv
->tpc_total
; i
++) {
509 gpc
= (gpc
+ 1) % priv
->gpc_nr
;
510 } while (!tpcnr
[gpc
]);
511 tpc
= priv
->tpc_nr
[gpc
] - tpcnr
[gpc
]--;
513 data
[i
/ 8] |= tpc
<< ((i
% 8) * 4);
516 nv_wr32(priv
, GPC_BCAST(0x0980), data
[0]);
517 nv_wr32(priv
, GPC_BCAST(0x0984), data
[1]);
518 nv_wr32(priv
, GPC_BCAST(0x0988), data
[2]);
519 nv_wr32(priv
, GPC_BCAST(0x098c), data
[3]);
521 for (gpc
= 0; gpc
< priv
->gpc_nr
; gpc
++) {
522 nv_wr32(priv
, GPC_UNIT(gpc
, 0x0914), priv
->magic_not_rop_nr
<< 8 |
524 nv_wr32(priv
, GPC_UNIT(gpc
, 0x0910), 0x00040000 | priv
->tpc_total
);
525 nv_wr32(priv
, GPC_UNIT(gpc
, 0x0918), magicgpc918
);
528 nv_wr32(priv
, GPC_BCAST(0x1bd4), magicgpc918
);
529 nv_wr32(priv
, GPC_BCAST(0x08ac), nv_rd32(priv
, 0x100800));
533 nvc0_graph_init_units(struct nvc0_graph_priv
*priv
)
535 nv_wr32(priv
, 0x409c24, 0x000f0000);
536 nv_wr32(priv
, 0x404000, 0xc0000000); /* DISPATCH */
537 nv_wr32(priv
, 0x404600, 0xc0000000); /* M2MF */
538 nv_wr32(priv
, 0x408030, 0xc0000000);
539 nv_wr32(priv
, 0x40601c, 0xc0000000);
540 nv_wr32(priv
, 0x404490, 0xc0000000); /* MACRO */
541 nv_wr32(priv
, 0x406018, 0xc0000000);
542 nv_wr32(priv
, 0x405840, 0xc0000000);
543 nv_wr32(priv
, 0x405844, 0x00ffffff);
544 nv_mask(priv
, 0x419cc0, 0x00000008, 0x00000008);
545 nv_mask(priv
, 0x419eb4, 0x00001000, 0x00001000);
549 nvc0_graph_init_gpc_1(struct nvc0_graph_priv
*priv
)
553 for (gpc
= 0; gpc
< priv
->gpc_nr
; gpc
++) {
554 nv_wr32(priv
, GPC_UNIT(gpc
, 0x0420), 0xc0000000);
555 nv_wr32(priv
, GPC_UNIT(gpc
, 0x0900), 0xc0000000);
556 nv_wr32(priv
, GPC_UNIT(gpc
, 0x1028), 0xc0000000);
557 nv_wr32(priv
, GPC_UNIT(gpc
, 0x0824), 0xc0000000);
558 for (tpc
= 0; tpc
< priv
->tpc_nr
[gpc
]; tpc
++) {
559 nv_wr32(priv
, TPC_UNIT(gpc
, tpc
, 0x508), 0xffffffff);
560 nv_wr32(priv
, TPC_UNIT(gpc
, tpc
, 0x50c), 0xffffffff);
561 nv_wr32(priv
, TPC_UNIT(gpc
, tpc
, 0x224), 0xc0000000);
562 nv_wr32(priv
, TPC_UNIT(gpc
, tpc
, 0x48c), 0xc0000000);
563 nv_wr32(priv
, TPC_UNIT(gpc
, tpc
, 0x084), 0xc0000000);
564 nv_wr32(priv
, TPC_UNIT(gpc
, tpc
, 0x644), 0x001ffffe);
565 nv_wr32(priv
, TPC_UNIT(gpc
, tpc
, 0x64c), 0x0000000f);
567 nv_wr32(priv
, GPC_UNIT(gpc
, 0x2c90), 0xffffffff);
568 nv_wr32(priv
, GPC_UNIT(gpc
, 0x2c94), 0xffffffff);
573 nvc0_graph_init_rop(struct nvc0_graph_priv
*priv
)
577 for (rop
= 0; rop
< priv
->rop_nr
; rop
++) {
578 nv_wr32(priv
, ROP_UNIT(rop
, 0x144), 0xc0000000);
579 nv_wr32(priv
, ROP_UNIT(rop
, 0x070), 0xc0000000);
580 nv_wr32(priv
, ROP_UNIT(rop
, 0x204), 0xffffffff);
581 nv_wr32(priv
, ROP_UNIT(rop
, 0x208), 0xffffffff);
586 nvc0_graph_init_fw(struct nvc0_graph_priv
*priv
, u32 fuc_base
,
587 struct nvc0_graph_fuc
*code
, struct nvc0_graph_fuc
*data
)
591 nv_wr32(priv
, fuc_base
+ 0x01c0, 0x01000000);
592 for (i
= 0; i
< data
->size
/ 4; i
++)
593 nv_wr32(priv
, fuc_base
+ 0x01c4, data
->data
[i
]);
595 nv_wr32(priv
, fuc_base
+ 0x0180, 0x01000000);
596 for (i
= 0; i
< code
->size
/ 4; i
++) {
598 nv_wr32(priv
, fuc_base
+ 0x0188, i
>> 6);
599 nv_wr32(priv
, fuc_base
+ 0x0184, code
->data
[i
]);
604 nvc0_graph_init_ctxctl(struct nvc0_graph_priv
*priv
)
609 if (priv
->firmware
) {
610 /* load fuc microcode */
611 r000260
= nv_mask(priv
, 0x000260, 0x00000001, 0x00000000);
612 nvc0_graph_init_fw(priv
, 0x409000, &priv
->fuc409c
,
614 nvc0_graph_init_fw(priv
, 0x41a000, &priv
->fuc41ac
,
616 nv_wr32(priv
, 0x000260, r000260
);
618 /* start both of them running */
619 nv_wr32(priv
, 0x409840, 0xffffffff);
620 nv_wr32(priv
, 0x41a10c, 0x00000000);
621 nv_wr32(priv
, 0x40910c, 0x00000000);
622 nv_wr32(priv
, 0x41a100, 0x00000002);
623 nv_wr32(priv
, 0x409100, 0x00000002);
624 if (!nv_wait(priv
, 0x409800, 0x00000001, 0x00000001))
625 nv_info(priv
, "0x409800 wait failed\n");
627 nv_wr32(priv
, 0x409840, 0xffffffff);
628 nv_wr32(priv
, 0x409500, 0x7fffffff);
629 nv_wr32(priv
, 0x409504, 0x00000021);
631 nv_wr32(priv
, 0x409840, 0xffffffff);
632 nv_wr32(priv
, 0x409500, 0x00000000);
633 nv_wr32(priv
, 0x409504, 0x00000010);
634 if (!nv_wait_ne(priv
, 0x409800, 0xffffffff, 0x00000000)) {
635 nv_error(priv
, "fuc09 req 0x10 timeout\n");
638 priv
->size
= nv_rd32(priv
, 0x409800);
640 nv_wr32(priv
, 0x409840, 0xffffffff);
641 nv_wr32(priv
, 0x409500, 0x00000000);
642 nv_wr32(priv
, 0x409504, 0x00000016);
643 if (!nv_wait_ne(priv
, 0x409800, 0xffffffff, 0x00000000)) {
644 nv_error(priv
, "fuc09 req 0x16 timeout\n");
648 nv_wr32(priv
, 0x409840, 0xffffffff);
649 nv_wr32(priv
, 0x409500, 0x00000000);
650 nv_wr32(priv
, 0x409504, 0x00000025);
651 if (!nv_wait_ne(priv
, 0x409800, 0xffffffff, 0x00000000)) {
652 nv_error(priv
, "fuc09 req 0x25 timeout\n");
656 if (priv
->data
== NULL
) {
657 int ret
= nvc0_grctx_generate(priv
);
659 nv_error(priv
, "failed to construct context\n");
667 /* load HUB microcode */
668 r000260
= nv_mask(priv
, 0x000260, 0x00000001, 0x00000000);
669 nv_wr32(priv
, 0x4091c0, 0x01000000);
670 for (i
= 0; i
< sizeof(nvc0_grhub_data
) / 4; i
++)
671 nv_wr32(priv
, 0x4091c4, nvc0_grhub_data
[i
]);
673 nv_wr32(priv
, 0x409180, 0x01000000);
674 for (i
= 0; i
< sizeof(nvc0_grhub_code
) / 4; i
++) {
676 nv_wr32(priv
, 0x409188, i
>> 6);
677 nv_wr32(priv
, 0x409184, nvc0_grhub_code
[i
]);
680 /* load GPC microcode */
681 nv_wr32(priv
, 0x41a1c0, 0x01000000);
682 for (i
= 0; i
< sizeof(nvc0_grgpc_data
) / 4; i
++)
683 nv_wr32(priv
, 0x41a1c4, nvc0_grgpc_data
[i
]);
685 nv_wr32(priv
, 0x41a180, 0x01000000);
686 for (i
= 0; i
< sizeof(nvc0_grgpc_code
) / 4; i
++) {
688 nv_wr32(priv
, 0x41a188, i
>> 6);
689 nv_wr32(priv
, 0x41a184, nvc0_grgpc_code
[i
]);
691 nv_wr32(priv
, 0x000260, r000260
);
693 /* start HUB ucode running, it'll init the GPCs */
694 nv_wr32(priv
, 0x409800, nv_device(priv
)->chipset
);
695 nv_wr32(priv
, 0x40910c, 0x00000000);
696 nv_wr32(priv
, 0x409100, 0x00000002);
697 if (!nv_wait(priv
, 0x409800, 0x80000000, 0x80000000)) {
698 nv_error(priv
, "HUB_INIT timed out\n");
699 nvc0_graph_ctxctl_debug(priv
);
703 priv
->size
= nv_rd32(priv
, 0x409804);
704 if (priv
->data
== NULL
) {
705 int ret
= nvc0_grctx_generate(priv
);
707 nv_error(priv
, "failed to construct context\n");
718 nvc0_graph_init(struct nouveau_object
*object
)
720 struct nvc0_graph_priv
*priv
= (void *)object
;
724 ret
= nouveau_graph_init(&priv
->base
);
728 nvc0_graph_init_obj418880(priv
);
729 nvc0_graph_init_regs(priv
);
730 /*nvc0_graph_init_unitplemented_magics(priv);*/
731 nvc0_graph_init_gpc_0(priv
);
732 /*nvc0_graph_init_unitplemented_c242(priv);*/
734 nv_wr32(priv
, 0x400500, 0x00010001);
735 nv_wr32(priv
, 0x400100, 0xffffffff);
736 nv_wr32(priv
, 0x40013c, 0xffffffff);
738 nvc0_graph_init_units(priv
);
739 nvc0_graph_init_gpc_1(priv
);
740 nvc0_graph_init_rop(priv
);
742 nv_wr32(priv
, 0x400108, 0xffffffff);
743 nv_wr32(priv
, 0x400138, 0xffffffff);
744 nv_wr32(priv
, 0x400118, 0xffffffff);
745 nv_wr32(priv
, 0x400130, 0xffffffff);
746 nv_wr32(priv
, 0x40011c, 0xffffffff);
747 nv_wr32(priv
, 0x400134, 0xffffffff);
748 nv_wr32(priv
, 0x400054, 0x34ce3464);
750 ret
= nvc0_graph_init_ctxctl(priv
);
760 struct nouveau_oclass
761 nvc0_graph_oclass
= {
762 .handle
= NV_ENGINE(GR
, 0xc0),
763 .ofuncs
= &(struct nouveau_ofuncs
) {
764 .ctor
= nvc0_graph_ctor
,
765 .dtor
= nvc0_graph_dtor
,
766 .init
= nvc0_graph_init
,
767 .fini
= _nouveau_graph_fini
,