xref: /linux/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c (revision 3a8c3400f3e74638bedd0d2410416aa8b794c0fd)
1 /*
2  * Copyright 2007 Stephane Marchesin
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragr) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 #include <engine/gr.h>
25 #include "regs.h"
26 
27 #include <core/client.h>
28 #include <core/handle.h>
29 #include <engine/fifo.h>
30 #include <subdev/instmem.h>
31 #include <subdev/timer.h>
32 
33 static u32
34 nv04_gr_ctx_regs[] = {
35 	0x0040053c,
36 	0x00400544,
37 	0x00400540,
38 	0x00400548,
39 	NV04_PGRAPH_CTX_SWITCH1,
40 	NV04_PGRAPH_CTX_SWITCH2,
41 	NV04_PGRAPH_CTX_SWITCH3,
42 	NV04_PGRAPH_CTX_SWITCH4,
43 	NV04_PGRAPH_CTX_CACHE1,
44 	NV04_PGRAPH_CTX_CACHE2,
45 	NV04_PGRAPH_CTX_CACHE3,
46 	NV04_PGRAPH_CTX_CACHE4,
47 	0x00400184,
48 	0x004001a4,
49 	0x004001c4,
50 	0x004001e4,
51 	0x00400188,
52 	0x004001a8,
53 	0x004001c8,
54 	0x004001e8,
55 	0x0040018c,
56 	0x004001ac,
57 	0x004001cc,
58 	0x004001ec,
59 	0x00400190,
60 	0x004001b0,
61 	0x004001d0,
62 	0x004001f0,
63 	0x00400194,
64 	0x004001b4,
65 	0x004001d4,
66 	0x004001f4,
67 	0x00400198,
68 	0x004001b8,
69 	0x004001d8,
70 	0x004001f8,
71 	0x0040019c,
72 	0x004001bc,
73 	0x004001dc,
74 	0x004001fc,
75 	0x00400174,
76 	NV04_PGRAPH_DMA_START_0,
77 	NV04_PGRAPH_DMA_START_1,
78 	NV04_PGRAPH_DMA_LENGTH,
79 	NV04_PGRAPH_DMA_MISC,
80 	NV04_PGRAPH_DMA_PITCH,
81 	NV04_PGRAPH_BOFFSET0,
82 	NV04_PGRAPH_BBASE0,
83 	NV04_PGRAPH_BLIMIT0,
84 	NV04_PGRAPH_BOFFSET1,
85 	NV04_PGRAPH_BBASE1,
86 	NV04_PGRAPH_BLIMIT1,
87 	NV04_PGRAPH_BOFFSET2,
88 	NV04_PGRAPH_BBASE2,
89 	NV04_PGRAPH_BLIMIT2,
90 	NV04_PGRAPH_BOFFSET3,
91 	NV04_PGRAPH_BBASE3,
92 	NV04_PGRAPH_BLIMIT3,
93 	NV04_PGRAPH_BOFFSET4,
94 	NV04_PGRAPH_BBASE4,
95 	NV04_PGRAPH_BLIMIT4,
96 	NV04_PGRAPH_BOFFSET5,
97 	NV04_PGRAPH_BBASE5,
98 	NV04_PGRAPH_BLIMIT5,
99 	NV04_PGRAPH_BPITCH0,
100 	NV04_PGRAPH_BPITCH1,
101 	NV04_PGRAPH_BPITCH2,
102 	NV04_PGRAPH_BPITCH3,
103 	NV04_PGRAPH_BPITCH4,
104 	NV04_PGRAPH_SURFACE,
105 	NV04_PGRAPH_STATE,
106 	NV04_PGRAPH_BSWIZZLE2,
107 	NV04_PGRAPH_BSWIZZLE5,
108 	NV04_PGRAPH_BPIXEL,
109 	NV04_PGRAPH_NOTIFY,
110 	NV04_PGRAPH_PATT_COLOR0,
111 	NV04_PGRAPH_PATT_COLOR1,
112 	NV04_PGRAPH_PATT_COLORRAM+0x00,
113 	NV04_PGRAPH_PATT_COLORRAM+0x04,
114 	NV04_PGRAPH_PATT_COLORRAM+0x08,
115 	NV04_PGRAPH_PATT_COLORRAM+0x0c,
116 	NV04_PGRAPH_PATT_COLORRAM+0x10,
117 	NV04_PGRAPH_PATT_COLORRAM+0x14,
118 	NV04_PGRAPH_PATT_COLORRAM+0x18,
119 	NV04_PGRAPH_PATT_COLORRAM+0x1c,
120 	NV04_PGRAPH_PATT_COLORRAM+0x20,
121 	NV04_PGRAPH_PATT_COLORRAM+0x24,
122 	NV04_PGRAPH_PATT_COLORRAM+0x28,
123 	NV04_PGRAPH_PATT_COLORRAM+0x2c,
124 	NV04_PGRAPH_PATT_COLORRAM+0x30,
125 	NV04_PGRAPH_PATT_COLORRAM+0x34,
126 	NV04_PGRAPH_PATT_COLORRAM+0x38,
127 	NV04_PGRAPH_PATT_COLORRAM+0x3c,
128 	NV04_PGRAPH_PATT_COLORRAM+0x40,
129 	NV04_PGRAPH_PATT_COLORRAM+0x44,
130 	NV04_PGRAPH_PATT_COLORRAM+0x48,
131 	NV04_PGRAPH_PATT_COLORRAM+0x4c,
132 	NV04_PGRAPH_PATT_COLORRAM+0x50,
133 	NV04_PGRAPH_PATT_COLORRAM+0x54,
134 	NV04_PGRAPH_PATT_COLORRAM+0x58,
135 	NV04_PGRAPH_PATT_COLORRAM+0x5c,
136 	NV04_PGRAPH_PATT_COLORRAM+0x60,
137 	NV04_PGRAPH_PATT_COLORRAM+0x64,
138 	NV04_PGRAPH_PATT_COLORRAM+0x68,
139 	NV04_PGRAPH_PATT_COLORRAM+0x6c,
140 	NV04_PGRAPH_PATT_COLORRAM+0x70,
141 	NV04_PGRAPH_PATT_COLORRAM+0x74,
142 	NV04_PGRAPH_PATT_COLORRAM+0x78,
143 	NV04_PGRAPH_PATT_COLORRAM+0x7c,
144 	NV04_PGRAPH_PATT_COLORRAM+0x80,
145 	NV04_PGRAPH_PATT_COLORRAM+0x84,
146 	NV04_PGRAPH_PATT_COLORRAM+0x88,
147 	NV04_PGRAPH_PATT_COLORRAM+0x8c,
148 	NV04_PGRAPH_PATT_COLORRAM+0x90,
149 	NV04_PGRAPH_PATT_COLORRAM+0x94,
150 	NV04_PGRAPH_PATT_COLORRAM+0x98,
151 	NV04_PGRAPH_PATT_COLORRAM+0x9c,
152 	NV04_PGRAPH_PATT_COLORRAM+0xa0,
153 	NV04_PGRAPH_PATT_COLORRAM+0xa4,
154 	NV04_PGRAPH_PATT_COLORRAM+0xa8,
155 	NV04_PGRAPH_PATT_COLORRAM+0xac,
156 	NV04_PGRAPH_PATT_COLORRAM+0xb0,
157 	NV04_PGRAPH_PATT_COLORRAM+0xb4,
158 	NV04_PGRAPH_PATT_COLORRAM+0xb8,
159 	NV04_PGRAPH_PATT_COLORRAM+0xbc,
160 	NV04_PGRAPH_PATT_COLORRAM+0xc0,
161 	NV04_PGRAPH_PATT_COLORRAM+0xc4,
162 	NV04_PGRAPH_PATT_COLORRAM+0xc8,
163 	NV04_PGRAPH_PATT_COLORRAM+0xcc,
164 	NV04_PGRAPH_PATT_COLORRAM+0xd0,
165 	NV04_PGRAPH_PATT_COLORRAM+0xd4,
166 	NV04_PGRAPH_PATT_COLORRAM+0xd8,
167 	NV04_PGRAPH_PATT_COLORRAM+0xdc,
168 	NV04_PGRAPH_PATT_COLORRAM+0xe0,
169 	NV04_PGRAPH_PATT_COLORRAM+0xe4,
170 	NV04_PGRAPH_PATT_COLORRAM+0xe8,
171 	NV04_PGRAPH_PATT_COLORRAM+0xec,
172 	NV04_PGRAPH_PATT_COLORRAM+0xf0,
173 	NV04_PGRAPH_PATT_COLORRAM+0xf4,
174 	NV04_PGRAPH_PATT_COLORRAM+0xf8,
175 	NV04_PGRAPH_PATT_COLORRAM+0xfc,
176 	NV04_PGRAPH_PATTERN,
177 	0x0040080c,
178 	NV04_PGRAPH_PATTERN_SHAPE,
179 	0x00400600,
180 	NV04_PGRAPH_ROP3,
181 	NV04_PGRAPH_CHROMA,
182 	NV04_PGRAPH_BETA_AND,
183 	NV04_PGRAPH_BETA_PREMULT,
184 	NV04_PGRAPH_CONTROL0,
185 	NV04_PGRAPH_CONTROL1,
186 	NV04_PGRAPH_CONTROL2,
187 	NV04_PGRAPH_BLEND,
188 	NV04_PGRAPH_STORED_FMT,
189 	NV04_PGRAPH_SOURCE_COLOR,
190 	0x00400560,
191 	0x00400568,
192 	0x00400564,
193 	0x0040056c,
194 	0x00400400,
195 	0x00400480,
196 	0x00400404,
197 	0x00400484,
198 	0x00400408,
199 	0x00400488,
200 	0x0040040c,
201 	0x0040048c,
202 	0x00400410,
203 	0x00400490,
204 	0x00400414,
205 	0x00400494,
206 	0x00400418,
207 	0x00400498,
208 	0x0040041c,
209 	0x0040049c,
210 	0x00400420,
211 	0x004004a0,
212 	0x00400424,
213 	0x004004a4,
214 	0x00400428,
215 	0x004004a8,
216 	0x0040042c,
217 	0x004004ac,
218 	0x00400430,
219 	0x004004b0,
220 	0x00400434,
221 	0x004004b4,
222 	0x00400438,
223 	0x004004b8,
224 	0x0040043c,
225 	0x004004bc,
226 	0x00400440,
227 	0x004004c0,
228 	0x00400444,
229 	0x004004c4,
230 	0x00400448,
231 	0x004004c8,
232 	0x0040044c,
233 	0x004004cc,
234 	0x00400450,
235 	0x004004d0,
236 	0x00400454,
237 	0x004004d4,
238 	0x00400458,
239 	0x004004d8,
240 	0x0040045c,
241 	0x004004dc,
242 	0x00400460,
243 	0x004004e0,
244 	0x00400464,
245 	0x004004e4,
246 	0x00400468,
247 	0x004004e8,
248 	0x0040046c,
249 	0x004004ec,
250 	0x00400470,
251 	0x004004f0,
252 	0x00400474,
253 	0x004004f4,
254 	0x00400478,
255 	0x004004f8,
256 	0x0040047c,
257 	0x004004fc,
258 	0x00400534,
259 	0x00400538,
260 	0x00400514,
261 	0x00400518,
262 	0x0040051c,
263 	0x00400520,
264 	0x00400524,
265 	0x00400528,
266 	0x0040052c,
267 	0x00400530,
268 	0x00400d00,
269 	0x00400d40,
270 	0x00400d80,
271 	0x00400d04,
272 	0x00400d44,
273 	0x00400d84,
274 	0x00400d08,
275 	0x00400d48,
276 	0x00400d88,
277 	0x00400d0c,
278 	0x00400d4c,
279 	0x00400d8c,
280 	0x00400d10,
281 	0x00400d50,
282 	0x00400d90,
283 	0x00400d14,
284 	0x00400d54,
285 	0x00400d94,
286 	0x00400d18,
287 	0x00400d58,
288 	0x00400d98,
289 	0x00400d1c,
290 	0x00400d5c,
291 	0x00400d9c,
292 	0x00400d20,
293 	0x00400d60,
294 	0x00400da0,
295 	0x00400d24,
296 	0x00400d64,
297 	0x00400da4,
298 	0x00400d28,
299 	0x00400d68,
300 	0x00400da8,
301 	0x00400d2c,
302 	0x00400d6c,
303 	0x00400dac,
304 	0x00400d30,
305 	0x00400d70,
306 	0x00400db0,
307 	0x00400d34,
308 	0x00400d74,
309 	0x00400db4,
310 	0x00400d38,
311 	0x00400d78,
312 	0x00400db8,
313 	0x00400d3c,
314 	0x00400d7c,
315 	0x00400dbc,
316 	0x00400590,
317 	0x00400594,
318 	0x00400598,
319 	0x0040059c,
320 	0x004005a8,
321 	0x004005ac,
322 	0x004005b0,
323 	0x004005b4,
324 	0x004005c0,
325 	0x004005c4,
326 	0x004005c8,
327 	0x004005cc,
328 	0x004005d0,
329 	0x004005d4,
330 	0x004005d8,
331 	0x004005dc,
332 	0x004005e0,
333 	NV04_PGRAPH_PASSTHRU_0,
334 	NV04_PGRAPH_PASSTHRU_1,
335 	NV04_PGRAPH_PASSTHRU_2,
336 	NV04_PGRAPH_DVD_COLORFMT,
337 	NV04_PGRAPH_SCALED_FORMAT,
338 	NV04_PGRAPH_MISC24_0,
339 	NV04_PGRAPH_MISC24_1,
340 	NV04_PGRAPH_MISC24_2,
341 	0x00400500,
342 	0x00400504,
343 	NV04_PGRAPH_VALID1,
344 	NV04_PGRAPH_VALID2,
345 	NV04_PGRAPH_DEBUG_3
346 };
347 
348 struct nv04_gr {
349 	struct nvkm_gr base;
350 	struct nv04_gr_chan *chan[16];
351 	spinlock_t lock;
352 };
353 
354 struct nv04_gr_chan {
355 	struct nvkm_object base;
356 	int chid;
357 	u32 nv04[ARRAY_SIZE(nv04_gr_ctx_regs)];
358 };
359 
360 
361 static inline struct nv04_gr *
362 nv04_gr(struct nv04_gr_chan *chan)
363 {
364 	return (void *)nv_object(chan)->engine;
365 }
366 
367 /*******************************************************************************
368  * Graphics object classes
369  ******************************************************************************/
370 
371 /*
372  * Software methods, why they are needed, and how they all work:
373  *
374  * NV04 and NV05 keep most of the state in PGRAPH context itself, but some
375  * 2d engine settings are kept inside the grobjs themselves. The grobjs are
376  * 3 words long on both. grobj format on NV04 is:
377  *
378  * word 0:
379  *  - bits 0-7: class
380  *  - bit 12: color key active
381  *  - bit 13: clip rect active
382  *  - bit 14: if set, destination surface is swizzled and taken from buffer 5
383  *            [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
384  *            from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
385  *            NV03_CONTEXT_SURFACE_DST].
386  *  - bits 15-17: 2d operation [aka patch config]
387  *  - bit 24: patch valid [enables rendering using this object]
388  *  - bit 25: surf3d valid [for tex_tri and multitex_tri only]
389  * word 1:
390  *  - bits 0-1: mono format
391  *  - bits 8-13: color format
392  *  - bits 16-31: DMA_NOTIFY instance
393  * word 2:
394  *  - bits 0-15: DMA_A instance
395  *  - bits 16-31: DMA_B instance
396  *
397  * On NV05 it's:
398  *
399  * word 0:
400  *  - bits 0-7: class
401  *  - bit 12: color key active
402  *  - bit 13: clip rect active
403  *  - bit 14: if set, destination surface is swizzled and taken from buffer 5
404  *            [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
405  *            from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
406  *            NV03_CONTEXT_SURFACE_DST].
407  *  - bits 15-17: 2d operation [aka patch config]
408  *  - bits 20-22: dither mode
409  *  - bit 24: patch valid [enables rendering using this object]
410  *  - bit 25: surface_dst/surface_color/surf2d/surf3d valid
411  *  - bit 26: surface_src/surface_zeta valid
412  *  - bit 27: pattern valid
413  *  - bit 28: rop valid
414  *  - bit 29: beta1 valid
415  *  - bit 30: beta4 valid
416  * word 1:
417  *  - bits 0-1: mono format
418  *  - bits 8-13: color format
419  *  - bits 16-31: DMA_NOTIFY instance
420  * word 2:
421  *  - bits 0-15: DMA_A instance
422  *  - bits 16-31: DMA_B instance
423  *
424  * NV05 will set/unset the relevant valid bits when you poke the relevant
425  * object-binding methods with object of the proper type, or with the NULL
426  * type. It'll only allow rendering using the grobj if all needed objects
427  * are bound. The needed set of objects depends on selected operation: for
428  * example rop object is needed by ROP_AND, but not by SRCCOPY_AND.
429  *
430  * NV04 doesn't have these methods implemented at all, and doesn't have the
431  * relevant bits in grobj. Instead, it'll allow rendering whenever bit 24
432  * is set. So we have to emulate them in software, internally keeping the
433  * same bits as NV05 does. Since grobjs are aligned to 16 bytes on nv04,
434  * but the last word isn't actually used for anything, we abuse it for this
435  * purpose.
436  *
437  * Actually, NV05 can optionally check bit 24 too, but we disable this since
438  * there's no use for it.
439  *
440  * For unknown reasons, NV04 implements surf3d binding in hardware as an
441  * exception. Also for unknown reasons, NV04 doesn't implement the clipping
442  * methods on the surf3d object, so we have to emulate them too.
443  */
444 
445 static void
446 nv04_gr_set_ctx1(struct nvkm_object *obj, u32 mask, u32 value)
447 {
448 	struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object);
449 	struct nv04_gr *gr = (void *)object->object.engine;
450 	struct nvkm_device *device = gr->base.engine.subdev.device;
451 	int subc = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
452 	u32 tmp;
453 
454 	nvkm_kmap(object);
455 	tmp  = nvkm_ro32(object, 0x00);
456 	tmp &= ~mask;
457 	tmp |= value;
458 	nvkm_wo32(object, 0x00, tmp);
459 	nvkm_done(object);
460 
461 	nvkm_wr32(device, NV04_PGRAPH_CTX_SWITCH1, tmp);
462 	nvkm_wr32(device, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
463 }
464 
465 static void
466 nv04_gr_set_ctx_val(struct nvkm_object *obj, u32 mask, u32 value)
467 {
468 	struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object);
469 	int class, op, valid = 1;
470 	u32 tmp, ctx1;
471 
472 	nvkm_kmap(object);
473 	ctx1 = nvkm_ro32(object, 0x00);
474 	class = ctx1 & 0xff;
475 	op = (ctx1 >> 15) & 7;
476 
477 	tmp = nvkm_ro32(object, 0x0c);
478 	tmp &= ~mask;
479 	tmp |= value;
480 	nvkm_wo32(object, 0x0c, tmp);
481 	nvkm_done(object);
482 
483 	/* check for valid surf2d/surf_dst/surf_color */
484 	if (!(tmp & 0x02000000))
485 		valid = 0;
486 	/* check for valid surf_src/surf_zeta */
487 	if ((class == 0x1f || class == 0x48) && !(tmp & 0x04000000))
488 		valid = 0;
489 
490 	switch (op) {
491 	/* SRCCOPY_AND, SRCCOPY: no extra objects required */
492 	case 0:
493 	case 3:
494 		break;
495 	/* ROP_AND: requires pattern and rop */
496 	case 1:
497 		if (!(tmp & 0x18000000))
498 			valid = 0;
499 		break;
500 	/* BLEND_AND: requires beta1 */
501 	case 2:
502 		if (!(tmp & 0x20000000))
503 			valid = 0;
504 		break;
505 	/* SRCCOPY_PREMULT, BLEND_PREMULT: beta4 required */
506 	case 4:
507 	case 5:
508 		if (!(tmp & 0x40000000))
509 			valid = 0;
510 		break;
511 	}
512 
513 	nv04_gr_set_ctx1(obj, 0x01000000, valid << 24);
514 }
515 
516 static int
517 nv04_gr_mthd_set_operation(struct nvkm_object *obj, u32 mthd,
518 			   void *args, u32 size)
519 {
520 	struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object);
521 	u32 class = nvkm_ro32(object, 0) & 0xff;
522 	u32 data = *(u32 *)args;
523 	if (data > 5)
524 		return 1;
525 	/* Old versions of the objects only accept first three operations. */
526 	if (data > 2 && class < 0x40)
527 		return 1;
528 	nv04_gr_set_ctx1(obj, 0x00038000, data << 15);
529 	/* changing operation changes set of objects needed for validation */
530 	nv04_gr_set_ctx_val(obj, 0, 0);
531 	return 0;
532 }
533 
534 static int
535 nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd,
536 			   void *args, u32 size)
537 {
538 	struct nv04_gr *gr = (void *)object->engine;
539 	struct nvkm_device *device = gr->base.engine.subdev.device;
540 	u32 data = *(u32 *)args;
541 	u32 min = data & 0xffff, max;
542 	u32 w = data >> 16;
543 	if (min & 0x8000)
544 		/* too large */
545 		return 1;
546 	if (w & 0x8000)
547 		/* yes, it accepts negative for some reason. */
548 		w |= 0xffff0000;
549 	max = min + w;
550 	max &= 0x3ffff;
551 	nvkm_wr32(device, 0x40053c, min);
552 	nvkm_wr32(device, 0x400544, max);
553 	return 0;
554 }
555 
556 static int
557 nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd,
558 			   void *args, u32 size)
559 {
560 	struct nv04_gr *gr = (void *)object->engine;
561 	struct nvkm_device *device = gr->base.engine.subdev.device;
562 	u32 data = *(u32 *)args;
563 	u32 min = data & 0xffff, max;
564 	u32 w = data >> 16;
565 	if (min & 0x8000)
566 		/* too large */
567 		return 1;
568 	if (w & 0x8000)
569 		/* yes, it accepts negative for some reason. */
570 		w |= 0xffff0000;
571 	max = min + w;
572 	max &= 0x3ffff;
573 	nvkm_wr32(device, 0x400540, min);
574 	nvkm_wr32(device, 0x400548, max);
575 	return 0;
576 }
577 
578 static u16
579 nv04_gr_mthd_bind_class(struct nvkm_object *object, u32 *args, u32 size)
580 {
581 	struct nvkm_instmem *imem = nvkm_instmem(object);
582 	u32 inst = *(u32 *)args << 4;
583 	return imem->func->rd32(imem, inst);
584 }
585 
586 static int
587 nv04_gr_mthd_bind_surf2d(struct nvkm_object *object, u32 mthd,
588 			    void *args, u32 size)
589 {
590 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
591 	case 0x30:
592 		nv04_gr_set_ctx1(object, 0x00004000, 0);
593 		nv04_gr_set_ctx_val(object, 0x02000000, 0);
594 		return 0;
595 	case 0x42:
596 		nv04_gr_set_ctx1(object, 0x00004000, 0);
597 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
598 		return 0;
599 	}
600 	return 1;
601 }
602 
603 static int
604 nv04_gr_mthd_bind_surf2d_swzsurf(struct nvkm_object *object, u32 mthd,
605 				 void *args, u32 size)
606 {
607 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
608 	case 0x30:
609 		nv04_gr_set_ctx1(object, 0x00004000, 0);
610 		nv04_gr_set_ctx_val(object, 0x02000000, 0);
611 		return 0;
612 	case 0x42:
613 		nv04_gr_set_ctx1(object, 0x00004000, 0);
614 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
615 		return 0;
616 	case 0x52:
617 		nv04_gr_set_ctx1(object, 0x00004000, 0x00004000);
618 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
619 		return 0;
620 	}
621 	return 1;
622 }
623 
624 static int
625 nv01_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd,
626 		       void *args, u32 size)
627 {
628 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
629 	case 0x30:
630 		nv04_gr_set_ctx_val(object, 0x08000000, 0);
631 		return 0;
632 	case 0x18:
633 		nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000);
634 		return 0;
635 	}
636 	return 1;
637 }
638 
639 static int
640 nv04_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd,
641 		       void *args, u32 size)
642 {
643 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
644 	case 0x30:
645 		nv04_gr_set_ctx_val(object, 0x08000000, 0);
646 		return 0;
647 	case 0x44:
648 		nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000);
649 		return 0;
650 	}
651 	return 1;
652 }
653 
654 static int
655 nv04_gr_mthd_bind_rop(struct nvkm_object *object, u32 mthd,
656 		      void *args, u32 size)
657 {
658 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
659 	case 0x30:
660 		nv04_gr_set_ctx_val(object, 0x10000000, 0);
661 		return 0;
662 	case 0x43:
663 		nv04_gr_set_ctx_val(object, 0x10000000, 0x10000000);
664 		return 0;
665 	}
666 	return 1;
667 }
668 
669 static int
670 nv04_gr_mthd_bind_beta1(struct nvkm_object *object, u32 mthd,
671 			void *args, u32 size)
672 {
673 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
674 	case 0x30:
675 		nv04_gr_set_ctx_val(object, 0x20000000, 0);
676 		return 0;
677 	case 0x12:
678 		nv04_gr_set_ctx_val(object, 0x20000000, 0x20000000);
679 		return 0;
680 	}
681 	return 1;
682 }
683 
684 static int
685 nv04_gr_mthd_bind_beta4(struct nvkm_object *object, u32 mthd,
686 			void *args, u32 size)
687 {
688 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
689 	case 0x30:
690 		nv04_gr_set_ctx_val(object, 0x40000000, 0);
691 		return 0;
692 	case 0x72:
693 		nv04_gr_set_ctx_val(object, 0x40000000, 0x40000000);
694 		return 0;
695 	}
696 	return 1;
697 }
698 
699 static int
700 nv04_gr_mthd_bind_surf_dst(struct nvkm_object *object, u32 mthd,
701 			   void *args, u32 size)
702 {
703 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
704 	case 0x30:
705 		nv04_gr_set_ctx_val(object, 0x02000000, 0);
706 		return 0;
707 	case 0x58:
708 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
709 		return 0;
710 	}
711 	return 1;
712 }
713 
714 static int
715 nv04_gr_mthd_bind_surf_src(struct nvkm_object *object, u32 mthd,
716 			   void *args, u32 size)
717 {
718 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
719 	case 0x30:
720 		nv04_gr_set_ctx_val(object, 0x04000000, 0);
721 		return 0;
722 	case 0x59:
723 		nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000);
724 		return 0;
725 	}
726 	return 1;
727 }
728 
729 static int
730 nv04_gr_mthd_bind_surf_color(struct nvkm_object *object, u32 mthd,
731 			     void *args, u32 size)
732 {
733 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
734 	case 0x30:
735 		nv04_gr_set_ctx_val(object, 0x02000000, 0);
736 		return 0;
737 	case 0x5a:
738 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
739 		return 0;
740 	}
741 	return 1;
742 }
743 
744 static int
745 nv04_gr_mthd_bind_surf_zeta(struct nvkm_object *object, u32 mthd,
746 			    void *args, u32 size)
747 {
748 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
749 	case 0x30:
750 		nv04_gr_set_ctx_val(object, 0x04000000, 0);
751 		return 0;
752 	case 0x5b:
753 		nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000);
754 		return 0;
755 	}
756 	return 1;
757 }
758 
759 static int
760 nv01_gr_mthd_bind_clip(struct nvkm_object *object, u32 mthd,
761 		       void *args, u32 size)
762 {
763 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
764 	case 0x30:
765 		nv04_gr_set_ctx1(object, 0x2000, 0);
766 		return 0;
767 	case 0x19:
768 		nv04_gr_set_ctx1(object, 0x2000, 0x2000);
769 		return 0;
770 	}
771 	return 1;
772 }
773 
774 static int
775 nv01_gr_mthd_bind_chroma(struct nvkm_object *object, u32 mthd,
776 			 void *args, u32 size)
777 {
778 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
779 	case 0x30:
780 		nv04_gr_set_ctx1(object, 0x1000, 0);
781 		return 0;
782 	/* Yes, for some reason even the old versions of objects
783 	 * accept 0x57 and not 0x17. Consistency be damned.
784 	 */
785 	case 0x57:
786 		nv04_gr_set_ctx1(object, 0x1000, 0x1000);
787 		return 0;
788 	}
789 	return 1;
790 }
791 
792 static struct nvkm_omthds
793 nv03_gr_gdi_omthds[] = {
794 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_patt },
795 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_rop },
796 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_beta1 },
797 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_surf_dst },
798 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
799 	{}
800 };
801 
802 static struct nvkm_omthds
803 nv04_gr_gdi_omthds[] = {
804 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
805 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
806 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
807 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
808 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
809 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
810 	{}
811 };
812 
813 static struct nvkm_omthds
814 nv01_gr_blit_omthds[] = {
815 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
816 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
817 	{ 0x018c, 0x018c, nv01_gr_mthd_bind_patt },
818 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
819 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
820 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst },
821 	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf_src },
822 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
823 	{}
824 };
825 
826 static struct nvkm_omthds
827 nv04_gr_blit_omthds[] = {
828 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
829 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
830 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_patt },
831 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
832 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
833 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 },
834 	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d },
835 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
836 	{}
837 };
838 
839 static struct nvkm_omthds
840 nv04_gr_iifc_omthds[] = {
841 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_chroma },
842 	{ 0x018c, 0x018c, nv01_gr_mthd_bind_clip },
843 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_patt },
844 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_rop },
845 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta1 },
846 	{ 0x019c, 0x019c, nv04_gr_mthd_bind_beta4 },
847 	{ 0x01a0, 0x01a0, nv04_gr_mthd_bind_surf2d_swzsurf },
848 	{ 0x03e4, 0x03e4, nv04_gr_mthd_set_operation },
849 	{}
850 };
851 
852 static struct nvkm_omthds
853 nv01_gr_ifc_omthds[] = {
854 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
855 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
856 	{ 0x018c, 0x018c, nv01_gr_mthd_bind_patt },
857 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
858 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
859 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst },
860 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
861 	{}
862 };
863 
864 static struct nvkm_omthds
865 nv04_gr_ifc_omthds[] = {
866 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
867 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
868 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_patt },
869 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
870 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
871 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 },
872 	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d },
873 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
874 	{}
875 };
876 
877 static struct nvkm_omthds
878 nv03_gr_sifc_omthds[] = {
879 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
880 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
881 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
882 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
883 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
884 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
885 	{}
886 };
887 
888 static struct nvkm_omthds
889 nv04_gr_sifc_omthds[] = {
890 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
891 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
892 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
893 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
894 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
895 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
896 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
897 	{}
898 };
899 
900 static struct nvkm_omthds
901 nv03_gr_sifm_omthds[] = {
902 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
903 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
904 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
905 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
906 	{ 0x0304, 0x0304, nv04_gr_mthd_set_operation },
907 	{}
908 };
909 
910 static struct nvkm_omthds
911 nv04_gr_sifm_omthds[] = {
912 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
913 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
914 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
915 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
916 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
917 	{ 0x0304, 0x0304, nv04_gr_mthd_set_operation },
918 	{}
919 };
920 
921 static struct nvkm_omthds
922 nv04_gr_surf3d_omthds[] = {
923 	{ 0x02f8, 0x02f8, nv04_gr_mthd_surf3d_clip_h },
924 	{ 0x02fc, 0x02fc, nv04_gr_mthd_surf3d_clip_v },
925 	{}
926 };
927 
928 static struct nvkm_omthds
929 nv03_gr_ttri_omthds[] = {
930 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
931 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_surf_color },
932 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_surf_zeta },
933 	{}
934 };
935 
936 static struct nvkm_omthds
937 nv01_gr_prim_omthds[] = {
938 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_clip },
939 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
940 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
941 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
942 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
943 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
944 	{}
945 };
946 
947 static struct nvkm_omthds
948 nv04_gr_prim_omthds[] = {
949 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_clip },
950 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
951 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
952 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
953 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
954 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
955 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
956 	{}
957 };
958 
959 static int
960 nv04_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
961 		    struct nvkm_oclass *oclass, void *data, u32 size,
962 		    struct nvkm_object **pobject)
963 {
964 	struct nvkm_gpuobj *obj;
965 	int ret;
966 
967 	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
968 				 16, 16, 0, &obj);
969 	*pobject = nv_object(obj);
970 	if (ret)
971 		return ret;
972 
973 	nvkm_kmap(obj);
974 	nvkm_wo32(obj, 0x00, nv_mclass(obj));
975 #ifdef __BIG_ENDIAN
976 	nvkm_mo32(obj, 0x00, 0x00080000, 0x00080000);
977 #endif
978 	nvkm_wo32(obj, 0x04, 0x00000000);
979 	nvkm_wo32(obj, 0x08, 0x00000000);
980 	nvkm_wo32(obj, 0x0c, 0x00000000);
981 	nvkm_done(obj);
982 	return 0;
983 }
984 
985 struct nvkm_ofuncs
986 nv04_gr_ofuncs = {
987 	.ctor = nv04_gr_object_ctor,
988 	.dtor = _nvkm_gpuobj_dtor,
989 	.init = _nvkm_gpuobj_init,
990 	.fini = _nvkm_gpuobj_fini,
991 	.rd32 = _nvkm_gpuobj_rd32,
992 	.wr32 = _nvkm_gpuobj_wr32,
993 };
994 
995 static struct nvkm_oclass
996 nv04_gr_sclass[] = {
997 	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
998 	{ 0x0017, &nv04_gr_ofuncs }, /* chroma */
999 	{ 0x0018, &nv04_gr_ofuncs }, /* pattern (nv01) */
1000 	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
1001 	{ 0x001c, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* line */
1002 	{ 0x001d, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* tri */
1003 	{ 0x001e, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* rect */
1004 	{ 0x001f, &nv04_gr_ofuncs, nv01_gr_blit_omthds },
1005 	{ 0x0021, &nv04_gr_ofuncs, nv01_gr_ifc_omthds },
1006 	{ 0x0030, &nv04_gr_ofuncs }, /* null */
1007 	{ 0x0036, &nv04_gr_ofuncs, nv03_gr_sifc_omthds },
1008 	{ 0x0037, &nv04_gr_ofuncs, nv03_gr_sifm_omthds },
1009 	{ 0x0038, &nv04_gr_ofuncs }, /* dvd subpicture */
1010 	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
1011 	{ 0x0042, &nv04_gr_ofuncs }, /* surf2d */
1012 	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
1013 	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
1014 	{ 0x0048, &nv04_gr_ofuncs, nv03_gr_ttri_omthds },
1015 	{ 0x004a, &nv04_gr_ofuncs, nv04_gr_gdi_omthds },
1016 	{ 0x004b, &nv04_gr_ofuncs, nv03_gr_gdi_omthds },
1017 	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
1018 	{ 0x0053, &nv04_gr_ofuncs, nv04_gr_surf3d_omthds },
1019 	{ 0x0054, &nv04_gr_ofuncs }, /* ttri */
1020 	{ 0x0055, &nv04_gr_ofuncs }, /* mtri */
1021 	{ 0x0057, &nv04_gr_ofuncs }, /* chroma */
1022 	{ 0x0058, &nv04_gr_ofuncs }, /* surf_dst */
1023 	{ 0x0059, &nv04_gr_ofuncs }, /* surf_src */
1024 	{ 0x005a, &nv04_gr_ofuncs }, /* surf_color */
1025 	{ 0x005b, &nv04_gr_ofuncs }, /* surf_zeta */
1026 	{ 0x005c, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* line */
1027 	{ 0x005d, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* tri */
1028 	{ 0x005e, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* rect */
1029 	{ 0x005f, &nv04_gr_ofuncs, nv04_gr_blit_omthds },
1030 	{ 0x0060, &nv04_gr_ofuncs, nv04_gr_iifc_omthds },
1031 	{ 0x0061, &nv04_gr_ofuncs, nv04_gr_ifc_omthds },
1032 	{ 0x0064, &nv04_gr_ofuncs }, /* iifc (nv05) */
1033 	{ 0x0065, &nv04_gr_ofuncs }, /* ifc (nv05) */
1034 	{ 0x0066, &nv04_gr_ofuncs }, /* sifc (nv05) */
1035 	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
1036 	{ 0x0076, &nv04_gr_ofuncs, nv04_gr_sifc_omthds },
1037 	{ 0x0077, &nv04_gr_ofuncs, nv04_gr_sifm_omthds },
1038 	{},
1039 };
1040 
1041 /*******************************************************************************
1042  * PGRAPH context
1043  ******************************************************************************/
1044 
1045 static struct nv04_gr_chan *
1046 nv04_gr_channel(struct nv04_gr *gr)
1047 {
1048 	struct nvkm_device *device = gr->base.engine.subdev.device;
1049 	struct nv04_gr_chan *chan = NULL;
1050 	if (nvkm_rd32(device, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) {
1051 		int chid = nvkm_rd32(device, NV04_PGRAPH_CTX_USER) >> 24;
1052 		if (chid < ARRAY_SIZE(gr->chan))
1053 			chan = gr->chan[chid];
1054 	}
1055 	return chan;
1056 }
1057 
1058 static int
1059 nv04_gr_load_context(struct nv04_gr_chan *chan, int chid)
1060 {
1061 	struct nv04_gr *gr = nv04_gr(chan);
1062 	struct nvkm_device *device = gr->base.engine.subdev.device;
1063 	int i;
1064 
1065 	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++)
1066 		nvkm_wr32(device, nv04_gr_ctx_regs[i], chan->nv04[i]);
1067 
1068 	nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
1069 	nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24);
1070 	nvkm_mask(device, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000);
1071 	return 0;
1072 }
1073 
1074 static int
1075 nv04_gr_unload_context(struct nv04_gr_chan *chan)
1076 {
1077 	struct nv04_gr *gr = nv04_gr(chan);
1078 	struct nvkm_device *device = gr->base.engine.subdev.device;
1079 	int i;
1080 
1081 	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++)
1082 		chan->nv04[i] = nvkm_rd32(device, nv04_gr_ctx_regs[i]);
1083 
1084 	nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
1085 	nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
1086 	return 0;
1087 }
1088 
1089 static void
1090 nv04_gr_context_switch(struct nv04_gr *gr)
1091 {
1092 	struct nvkm_device *device = gr->base.engine.subdev.device;
1093 	struct nv04_gr_chan *prev = NULL;
1094 	struct nv04_gr_chan *next = NULL;
1095 	unsigned long flags;
1096 	int chid;
1097 
1098 	spin_lock_irqsave(&gr->lock, flags);
1099 	nv04_gr_idle(gr);
1100 
1101 	/* If previous context is valid, we need to save it */
1102 	prev = nv04_gr_channel(gr);
1103 	if (prev)
1104 		nv04_gr_unload_context(prev);
1105 
1106 	/* load context for next channel */
1107 	chid = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f;
1108 	next = gr->chan[chid];
1109 	if (next)
1110 		nv04_gr_load_context(next, chid);
1111 
1112 	spin_unlock_irqrestore(&gr->lock, flags);
1113 }
1114 
1115 static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg)
1116 {
1117 	int i;
1118 
1119 	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) {
1120 		if (nv04_gr_ctx_regs[i] == reg)
1121 			return &chan->nv04[i];
1122 	}
1123 
1124 	return NULL;
1125 }
1126 
1127 static int
1128 nv04_gr_context_ctor(struct nvkm_object *parent,
1129 		     struct nvkm_object *engine,
1130 		     struct nvkm_oclass *oclass, void *data, u32 size,
1131 		     struct nvkm_object **pobject)
1132 {
1133 	struct nvkm_fifo_chan *fifo = (void *)parent;
1134 	struct nv04_gr *gr = (void *)engine;
1135 	struct nv04_gr_chan *chan;
1136 	unsigned long flags;
1137 	int ret;
1138 
1139 	ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
1140 	*pobject = nv_object(chan);
1141 	if (ret)
1142 		return ret;
1143 
1144 	spin_lock_irqsave(&gr->lock, flags);
1145 	if (gr->chan[fifo->chid]) {
1146 		*pobject = nv_object(gr->chan[fifo->chid]);
1147 		atomic_inc(&(*pobject)->refcount);
1148 		spin_unlock_irqrestore(&gr->lock, flags);
1149 		nvkm_object_destroy(&chan->base);
1150 		return 1;
1151 	}
1152 
1153 	*ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
1154 
1155 	gr->chan[fifo->chid] = chan;
1156 	chan->chid = fifo->chid;
1157 	spin_unlock_irqrestore(&gr->lock, flags);
1158 	return 0;
1159 }
1160 
1161 static void
1162 nv04_gr_context_dtor(struct nvkm_object *object)
1163 {
1164 	struct nv04_gr *gr = (void *)object->engine;
1165 	struct nv04_gr_chan *chan = (void *)object;
1166 	unsigned long flags;
1167 
1168 	spin_lock_irqsave(&gr->lock, flags);
1169 	gr->chan[chan->chid] = NULL;
1170 	spin_unlock_irqrestore(&gr->lock, flags);
1171 
1172 	nvkm_object_destroy(&chan->base);
1173 }
1174 
1175 static int
1176 nv04_gr_context_fini(struct nvkm_object *object, bool suspend)
1177 {
1178 	struct nv04_gr *gr = (void *)object->engine;
1179 	struct nv04_gr_chan *chan = (void *)object;
1180 	struct nvkm_device *device = gr->base.engine.subdev.device;
1181 	unsigned long flags;
1182 
1183 	spin_lock_irqsave(&gr->lock, flags);
1184 	nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
1185 	if (nv04_gr_channel(gr) == chan)
1186 		nv04_gr_unload_context(chan);
1187 	nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
1188 	spin_unlock_irqrestore(&gr->lock, flags);
1189 
1190 	return _nvkm_object_fini(&chan->base, suspend);
1191 }
1192 
1193 static struct nvkm_oclass
1194 nv04_gr_cclass = {
1195 	.handle = NV_ENGCTX(GR, 0x04),
1196 	.ofuncs = &(struct nvkm_ofuncs) {
1197 		.ctor = nv04_gr_context_ctor,
1198 		.dtor = nv04_gr_context_dtor,
1199 		.init = _nvkm_object_init,
1200 		.fini = nv04_gr_context_fini,
1201 	},
1202 };
1203 
1204 /*******************************************************************************
1205  * PGRAPH engine/subdev functions
1206  ******************************************************************************/
1207 
1208 bool
1209 nv04_gr_idle(void *obj)
1210 {
1211 	struct nvkm_gr *gr = nvkm_gr(obj);
1212 	struct nvkm_subdev *subdev = &gr->engine.subdev;
1213 	struct nvkm_device *device = subdev->device;
1214 	u32 mask = 0xffffffff;
1215 
1216 	if (nv_device(obj)->card_type == NV_40)
1217 		mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
1218 
1219 	if (nvkm_msec(device, 2000,
1220 		if (!(nvkm_rd32(device, NV04_PGRAPH_STATUS) & mask))
1221 			break;
1222 	) < 0) {
1223 		nvkm_error(subdev, "idle timed out with status %08x\n",
1224 			   nvkm_rd32(device, NV04_PGRAPH_STATUS));
1225 		return false;
1226 	}
1227 
1228 	return true;
1229 }
1230 
1231 static const struct nvkm_bitfield
1232 nv04_gr_intr_name[] = {
1233 	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
1234 	{}
1235 };
1236 
1237 static const struct nvkm_bitfield
1238 nv04_gr_nstatus[] = {
1239 	{ NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
1240 	{ NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
1241 	{ NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
1242 	{ NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
1243 	{}
1244 };
1245 
1246 const struct nvkm_bitfield
1247 nv04_gr_nsource[] = {
1248 	{ NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
1249 	{ NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
1250 	{ NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
1251 	{ NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
1252 	{ NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
1253 	{ NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
1254 	{ NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
1255 	{ NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
1256 	{ NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
1257 	{ NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
1258 	{ NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
1259 	{ NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
1260 	{ NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
1261 	{ NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
1262 	{ NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
1263 	{ NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
1264 	{ NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
1265 	{ NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
1266 	{ NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
1267 	{}
1268 };
1269 
1270 static void
1271 nv04_gr_intr(struct nvkm_subdev *subdev)
1272 {
1273 	struct nv04_gr *gr = (void *)subdev;
1274 	struct nv04_gr_chan *chan = NULL;
1275 	struct nvkm_namedb *namedb = NULL;
1276 	struct nvkm_handle *handle = NULL;
1277 	struct nvkm_device *device = gr->base.engine.subdev.device;
1278 	u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR);
1279 	u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE);
1280 	u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS);
1281 	u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR);
1282 	u32 chid = (addr & 0x0f000000) >> 24;
1283 	u32 subc = (addr & 0x0000e000) >> 13;
1284 	u32 mthd = (addr & 0x00001ffc);
1285 	u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA);
1286 	u32 class = nvkm_rd32(device, 0x400180 + subc * 4) & 0xff;
1287 	u32 inst = (nvkm_rd32(device, 0x40016c) & 0xffff) << 4;
1288 	u32 show = stat;
1289 	char msg[128], src[128], sta[128];
1290 	unsigned long flags;
1291 
1292 	spin_lock_irqsave(&gr->lock, flags);
1293 	chan = gr->chan[chid];
1294 	if (chan)
1295 		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
1296 	spin_unlock_irqrestore(&gr->lock, flags);
1297 
1298 	if (stat & NV_PGRAPH_INTR_NOTIFY) {
1299 		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
1300 			handle = nvkm_namedb_get_vinst(namedb, inst);
1301 			if (handle && !nv_call(handle->object, mthd, data))
1302 				show &= ~NV_PGRAPH_INTR_NOTIFY;
1303 		}
1304 	}
1305 
1306 	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
1307 		nvkm_wr32(device, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
1308 		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
1309 		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
1310 		nv04_gr_context_switch(gr);
1311 	}
1312 
1313 	nvkm_wr32(device, NV03_PGRAPH_INTR, stat);
1314 	nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001);
1315 
1316 	if (show) {
1317 		nvkm_snprintbf(msg, sizeof(msg), nv04_gr_intr_name, show);
1318 		nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource);
1319 		nvkm_snprintbf(sta, sizeof(sta), nv04_gr_nstatus, nstatus);
1320 		nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] "
1321 				   "nstatus %08x [%s] ch %d [%s] subc %d "
1322 				   "class %04x mthd %04x data %08x\n",
1323 			   show, msg, nsource, src, nstatus, sta, chid,
1324 			   nvkm_client_name(chan), subc, class, mthd, data);
1325 	}
1326 
1327 	nvkm_namedb_put(handle);
1328 }
1329 
1330 static int
1331 nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
1332 	     struct nvkm_oclass *oclass, void *data, u32 size,
1333 	     struct nvkm_object **pobject)
1334 {
1335 	struct nv04_gr *gr;
1336 	int ret;
1337 
1338 	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
1339 	*pobject = nv_object(gr);
1340 	if (ret)
1341 		return ret;
1342 
1343 	nv_subdev(gr)->unit = 0x00001000;
1344 	nv_subdev(gr)->intr = nv04_gr_intr;
1345 	nv_engine(gr)->cclass = &nv04_gr_cclass;
1346 	nv_engine(gr)->sclass = nv04_gr_sclass;
1347 	spin_lock_init(&gr->lock);
1348 	return 0;
1349 }
1350 
1351 static int
1352 nv04_gr_init(struct nvkm_object *object)
1353 {
1354 	struct nvkm_engine *engine = nv_engine(object);
1355 	struct nv04_gr *gr = (void *)engine;
1356 	struct nvkm_device *device = gr->base.engine.subdev.device;
1357 	int ret;
1358 
1359 	ret = nvkm_gr_init(&gr->base);
1360 	if (ret)
1361 		return ret;
1362 
1363 	/* Enable PGRAPH interrupts */
1364 	nvkm_wr32(device, NV03_PGRAPH_INTR, 0xFFFFFFFF);
1365 	nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
1366 
1367 	nvkm_wr32(device, NV04_PGRAPH_VALID1, 0);
1368 	nvkm_wr32(device, NV04_PGRAPH_VALID2, 0);
1369 	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x000001FF);
1370 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
1371 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x1231c000);
1372 	/*1231C000 blob, 001 haiku*/
1373 	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
1374 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x72111100);
1375 	/*0x72111100 blob , 01 haiku*/
1376 	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
1377 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
1378 	/*haiku same*/
1379 
1380 	/*nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
1381 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
1382 	/*haiku and blob 10d4*/
1383 
1384 	nvkm_wr32(device, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
1385 	nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
1386 	nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
1387 
1388 	/* These don't belong here, they're part of a per-channel context */
1389 	nvkm_wr32(device, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
1390 	nvkm_wr32(device, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
1391 	return 0;
1392 }
1393 
1394 struct nvkm_oclass
1395 nv04_gr_oclass = {
1396 	.handle = NV_ENGINE(GR, 0x04),
1397 	.ofuncs = &(struct nvkm_ofuncs) {
1398 		.ctor = nv04_gr_ctor,
1399 		.dtor = _nvkm_gr_dtor,
1400 		.init = nv04_gr_init,
1401 		.fini = _nvkm_gr_fini,
1402 	},
1403 };
1404