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_priv {
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_priv *
362 nv04_gr_priv(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 *object, u32 mask, u32 value)
447 {
448 	struct nv04_gr_priv *priv = (void *)object->engine;
449 	int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
450 	u32 tmp;
451 
452 	tmp  = nv_ro32(object, 0x00);
453 	tmp &= ~mask;
454 	tmp |= value;
455 	nv_wo32(object, 0x00, tmp);
456 
457 	nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp);
458 	nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
459 }
460 
461 static void
462 nv04_gr_set_ctx_val(struct nvkm_object *object, u32 mask, u32 value)
463 {
464 	int class, op, valid = 1;
465 	u32 tmp, ctx1;
466 
467 	ctx1 = nv_ro32(object, 0x00);
468 	class = ctx1 & 0xff;
469 	op = (ctx1 >> 15) & 7;
470 
471 	tmp = nv_ro32(object, 0x0c);
472 	tmp &= ~mask;
473 	tmp |= value;
474 	nv_wo32(object, 0x0c, tmp);
475 
476 	/* check for valid surf2d/surf_dst/surf_color */
477 	if (!(tmp & 0x02000000))
478 		valid = 0;
479 	/* check for valid surf_src/surf_zeta */
480 	if ((class == 0x1f || class == 0x48) && !(tmp & 0x04000000))
481 		valid = 0;
482 
483 	switch (op) {
484 	/* SRCCOPY_AND, SRCCOPY: no extra objects required */
485 	case 0:
486 	case 3:
487 		break;
488 	/* ROP_AND: requires pattern and rop */
489 	case 1:
490 		if (!(tmp & 0x18000000))
491 			valid = 0;
492 		break;
493 	/* BLEND_AND: requires beta1 */
494 	case 2:
495 		if (!(tmp & 0x20000000))
496 			valid = 0;
497 		break;
498 	/* SRCCOPY_PREMULT, BLEND_PREMULT: beta4 required */
499 	case 4:
500 	case 5:
501 		if (!(tmp & 0x40000000))
502 			valid = 0;
503 		break;
504 	}
505 
506 	nv04_gr_set_ctx1(object, 0x01000000, valid << 24);
507 }
508 
509 static int
510 nv04_gr_mthd_set_operation(struct nvkm_object *object, u32 mthd,
511 			   void *args, u32 size)
512 {
513 	u32 class = nv_ro32(object, 0) & 0xff;
514 	u32 data = *(u32 *)args;
515 	if (data > 5)
516 		return 1;
517 	/* Old versions of the objects only accept first three operations. */
518 	if (data > 2 && class < 0x40)
519 		return 1;
520 	nv04_gr_set_ctx1(object, 0x00038000, data << 15);
521 	/* changing operation changes set of objects needed for validation */
522 	nv04_gr_set_ctx_val(object, 0, 0);
523 	return 0;
524 }
525 
526 static int
527 nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd,
528 			   void *args, u32 size)
529 {
530 	struct nv04_gr_priv *priv = (void *)object->engine;
531 	u32 data = *(u32 *)args;
532 	u32 min = data & 0xffff, max;
533 	u32 w = data >> 16;
534 	if (min & 0x8000)
535 		/* too large */
536 		return 1;
537 	if (w & 0x8000)
538 		/* yes, it accepts negative for some reason. */
539 		w |= 0xffff0000;
540 	max = min + w;
541 	max &= 0x3ffff;
542 	nv_wr32(priv, 0x40053c, min);
543 	nv_wr32(priv, 0x400544, max);
544 	return 0;
545 }
546 
547 static int
548 nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd,
549 			   void *args, u32 size)
550 {
551 	struct nv04_gr_priv *priv = (void *)object->engine;
552 	u32 data = *(u32 *)args;
553 	u32 min = data & 0xffff, max;
554 	u32 w = data >> 16;
555 	if (min & 0x8000)
556 		/* too large */
557 		return 1;
558 	if (w & 0x8000)
559 		/* yes, it accepts negative for some reason. */
560 		w |= 0xffff0000;
561 	max = min + w;
562 	max &= 0x3ffff;
563 	nv_wr32(priv, 0x400540, min);
564 	nv_wr32(priv, 0x400548, max);
565 	return 0;
566 }
567 
568 static u16
569 nv04_gr_mthd_bind_class(struct nvkm_object *object, u32 *args, u32 size)
570 {
571 	struct nvkm_instmem *imem = nvkm_instmem(object);
572 	u32 inst = *(u32 *)args << 4;
573 	return nv_ro32(imem, inst);
574 }
575 
576 static int
577 nv04_gr_mthd_bind_surf2d(struct nvkm_object *object, u32 mthd,
578 			    void *args, u32 size)
579 {
580 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
581 	case 0x30:
582 		nv04_gr_set_ctx1(object, 0x00004000, 0);
583 		nv04_gr_set_ctx_val(object, 0x02000000, 0);
584 		return 0;
585 	case 0x42:
586 		nv04_gr_set_ctx1(object, 0x00004000, 0);
587 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
588 		return 0;
589 	}
590 	return 1;
591 }
592 
593 static int
594 nv04_gr_mthd_bind_surf2d_swzsurf(struct nvkm_object *object, u32 mthd,
595 				 void *args, u32 size)
596 {
597 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
598 	case 0x30:
599 		nv04_gr_set_ctx1(object, 0x00004000, 0);
600 		nv04_gr_set_ctx_val(object, 0x02000000, 0);
601 		return 0;
602 	case 0x42:
603 		nv04_gr_set_ctx1(object, 0x00004000, 0);
604 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
605 		return 0;
606 	case 0x52:
607 		nv04_gr_set_ctx1(object, 0x00004000, 0x00004000);
608 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
609 		return 0;
610 	}
611 	return 1;
612 }
613 
614 static int
615 nv01_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd,
616 		       void *args, u32 size)
617 {
618 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
619 	case 0x30:
620 		nv04_gr_set_ctx_val(object, 0x08000000, 0);
621 		return 0;
622 	case 0x18:
623 		nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000);
624 		return 0;
625 	}
626 	return 1;
627 }
628 
629 static int
630 nv04_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd,
631 		       void *args, u32 size)
632 {
633 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
634 	case 0x30:
635 		nv04_gr_set_ctx_val(object, 0x08000000, 0);
636 		return 0;
637 	case 0x44:
638 		nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000);
639 		return 0;
640 	}
641 	return 1;
642 }
643 
644 static int
645 nv04_gr_mthd_bind_rop(struct nvkm_object *object, u32 mthd,
646 		      void *args, u32 size)
647 {
648 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
649 	case 0x30:
650 		nv04_gr_set_ctx_val(object, 0x10000000, 0);
651 		return 0;
652 	case 0x43:
653 		nv04_gr_set_ctx_val(object, 0x10000000, 0x10000000);
654 		return 0;
655 	}
656 	return 1;
657 }
658 
659 static int
660 nv04_gr_mthd_bind_beta1(struct nvkm_object *object, u32 mthd,
661 			void *args, u32 size)
662 {
663 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
664 	case 0x30:
665 		nv04_gr_set_ctx_val(object, 0x20000000, 0);
666 		return 0;
667 	case 0x12:
668 		nv04_gr_set_ctx_val(object, 0x20000000, 0x20000000);
669 		return 0;
670 	}
671 	return 1;
672 }
673 
674 static int
675 nv04_gr_mthd_bind_beta4(struct nvkm_object *object, u32 mthd,
676 			void *args, u32 size)
677 {
678 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
679 	case 0x30:
680 		nv04_gr_set_ctx_val(object, 0x40000000, 0);
681 		return 0;
682 	case 0x72:
683 		nv04_gr_set_ctx_val(object, 0x40000000, 0x40000000);
684 		return 0;
685 	}
686 	return 1;
687 }
688 
689 static int
690 nv04_gr_mthd_bind_surf_dst(struct nvkm_object *object, u32 mthd,
691 			   void *args, u32 size)
692 {
693 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
694 	case 0x30:
695 		nv04_gr_set_ctx_val(object, 0x02000000, 0);
696 		return 0;
697 	case 0x58:
698 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
699 		return 0;
700 	}
701 	return 1;
702 }
703 
704 static int
705 nv04_gr_mthd_bind_surf_src(struct nvkm_object *object, u32 mthd,
706 			   void *args, u32 size)
707 {
708 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
709 	case 0x30:
710 		nv04_gr_set_ctx_val(object, 0x04000000, 0);
711 		return 0;
712 	case 0x59:
713 		nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000);
714 		return 0;
715 	}
716 	return 1;
717 }
718 
719 static int
720 nv04_gr_mthd_bind_surf_color(struct nvkm_object *object, u32 mthd,
721 			     void *args, u32 size)
722 {
723 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
724 	case 0x30:
725 		nv04_gr_set_ctx_val(object, 0x02000000, 0);
726 		return 0;
727 	case 0x5a:
728 		nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
729 		return 0;
730 	}
731 	return 1;
732 }
733 
734 static int
735 nv04_gr_mthd_bind_surf_zeta(struct nvkm_object *object, u32 mthd,
736 			    void *args, u32 size)
737 {
738 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
739 	case 0x30:
740 		nv04_gr_set_ctx_val(object, 0x04000000, 0);
741 		return 0;
742 	case 0x5b:
743 		nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000);
744 		return 0;
745 	}
746 	return 1;
747 }
748 
749 static int
750 nv01_gr_mthd_bind_clip(struct nvkm_object *object, u32 mthd,
751 		       void *args, u32 size)
752 {
753 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
754 	case 0x30:
755 		nv04_gr_set_ctx1(object, 0x2000, 0);
756 		return 0;
757 	case 0x19:
758 		nv04_gr_set_ctx1(object, 0x2000, 0x2000);
759 		return 0;
760 	}
761 	return 1;
762 }
763 
764 static int
765 nv01_gr_mthd_bind_chroma(struct nvkm_object *object, u32 mthd,
766 			 void *args, u32 size)
767 {
768 	switch (nv04_gr_mthd_bind_class(object, args, size)) {
769 	case 0x30:
770 		nv04_gr_set_ctx1(object, 0x1000, 0);
771 		return 0;
772 	/* Yes, for some reason even the old versions of objects
773 	 * accept 0x57 and not 0x17. Consistency be damned.
774 	 */
775 	case 0x57:
776 		nv04_gr_set_ctx1(object, 0x1000, 0x1000);
777 		return 0;
778 	}
779 	return 1;
780 }
781 
782 static struct nvkm_omthds
783 nv03_gr_gdi_omthds[] = {
784 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_patt },
785 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_rop },
786 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_beta1 },
787 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_surf_dst },
788 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
789 	{}
790 };
791 
792 static struct nvkm_omthds
793 nv04_gr_gdi_omthds[] = {
794 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
795 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
796 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
797 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
798 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
799 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
800 	{}
801 };
802 
803 static struct nvkm_omthds
804 nv01_gr_blit_omthds[] = {
805 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
806 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
807 	{ 0x018c, 0x018c, nv01_gr_mthd_bind_patt },
808 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
809 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
810 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst },
811 	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf_src },
812 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
813 	{}
814 };
815 
816 static struct nvkm_omthds
817 nv04_gr_blit_omthds[] = {
818 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
819 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
820 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_patt },
821 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
822 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
823 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 },
824 	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d },
825 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
826 	{}
827 };
828 
829 static struct nvkm_omthds
830 nv04_gr_iifc_omthds[] = {
831 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_chroma },
832 	{ 0x018c, 0x018c, nv01_gr_mthd_bind_clip },
833 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_patt },
834 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_rop },
835 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta1 },
836 	{ 0x019c, 0x019c, nv04_gr_mthd_bind_beta4 },
837 	{ 0x01a0, 0x01a0, nv04_gr_mthd_bind_surf2d_swzsurf },
838 	{ 0x03e4, 0x03e4, nv04_gr_mthd_set_operation },
839 	{}
840 };
841 
842 static struct nvkm_omthds
843 nv01_gr_ifc_omthds[] = {
844 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
845 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
846 	{ 0x018c, 0x018c, nv01_gr_mthd_bind_patt },
847 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
848 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
849 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst },
850 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
851 	{}
852 };
853 
854 static struct nvkm_omthds
855 nv04_gr_ifc_omthds[] = {
856 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
857 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
858 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_patt },
859 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
860 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
861 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 },
862 	{ 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d },
863 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
864 	{}
865 };
866 
867 static struct nvkm_omthds
868 nv03_gr_sifc_omthds[] = {
869 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
870 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
871 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
872 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
873 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
874 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
875 	{}
876 };
877 
878 static struct nvkm_omthds
879 nv04_gr_sifc_omthds[] = {
880 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
881 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
882 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
883 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
884 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
885 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
886 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
887 	{}
888 };
889 
890 static struct nvkm_omthds
891 nv03_gr_sifm_omthds[] = {
892 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
893 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
894 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
895 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
896 	{ 0x0304, 0x0304, nv04_gr_mthd_set_operation },
897 	{}
898 };
899 
900 static struct nvkm_omthds
901 nv04_gr_sifm_omthds[] = {
902 	{ 0x0188, 0x0188, nv04_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_beta4 },
906 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
907 	{ 0x0304, 0x0304, nv04_gr_mthd_set_operation },
908 	{}
909 };
910 
911 static struct nvkm_omthds
912 nv04_gr_surf3d_omthds[] = {
913 	{ 0x02f8, 0x02f8, nv04_gr_mthd_surf3d_clip_h },
914 	{ 0x02fc, 0x02fc, nv04_gr_mthd_surf3d_clip_v },
915 	{}
916 };
917 
918 static struct nvkm_omthds
919 nv03_gr_ttri_omthds[] = {
920 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
921 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_surf_color },
922 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_surf_zeta },
923 	{}
924 };
925 
926 static struct nvkm_omthds
927 nv01_gr_prim_omthds[] = {
928 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_clip },
929 	{ 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
930 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
931 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
932 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
933 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
934 	{}
935 };
936 
937 static struct nvkm_omthds
938 nv04_gr_prim_omthds[] = {
939 	{ 0x0184, 0x0184, nv01_gr_mthd_bind_clip },
940 	{ 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
941 	{ 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
942 	{ 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
943 	{ 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
944 	{ 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
945 	{ 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
946 	{}
947 };
948 
949 static int
950 nv04_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
951 		    struct nvkm_oclass *oclass, void *data, u32 size,
952 		    struct nvkm_object **pobject)
953 {
954 	struct nvkm_gpuobj *obj;
955 	int ret;
956 
957 	ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
958 				 16, 16, 0, &obj);
959 	*pobject = nv_object(obj);
960 	if (ret)
961 		return ret;
962 
963 	nv_wo32(obj, 0x00, nv_mclass(obj));
964 #ifdef __BIG_ENDIAN
965 	nv_mo32(obj, 0x00, 0x00080000, 0x00080000);
966 #endif
967 	nv_wo32(obj, 0x04, 0x00000000);
968 	nv_wo32(obj, 0x08, 0x00000000);
969 	nv_wo32(obj, 0x0c, 0x00000000);
970 	return 0;
971 }
972 
973 struct nvkm_ofuncs
974 nv04_gr_ofuncs = {
975 	.ctor = nv04_gr_object_ctor,
976 	.dtor = _nvkm_gpuobj_dtor,
977 	.init = _nvkm_gpuobj_init,
978 	.fini = _nvkm_gpuobj_fini,
979 	.rd32 = _nvkm_gpuobj_rd32,
980 	.wr32 = _nvkm_gpuobj_wr32,
981 };
982 
983 static struct nvkm_oclass
984 nv04_gr_sclass[] = {
985 	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
986 	{ 0x0017, &nv04_gr_ofuncs }, /* chroma */
987 	{ 0x0018, &nv04_gr_ofuncs }, /* pattern (nv01) */
988 	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
989 	{ 0x001c, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* line */
990 	{ 0x001d, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* tri */
991 	{ 0x001e, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* rect */
992 	{ 0x001f, &nv04_gr_ofuncs, nv01_gr_blit_omthds },
993 	{ 0x0021, &nv04_gr_ofuncs, nv01_gr_ifc_omthds },
994 	{ 0x0030, &nv04_gr_ofuncs }, /* null */
995 	{ 0x0036, &nv04_gr_ofuncs, nv03_gr_sifc_omthds },
996 	{ 0x0037, &nv04_gr_ofuncs, nv03_gr_sifm_omthds },
997 	{ 0x0038, &nv04_gr_ofuncs }, /* dvd subpicture */
998 	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
999 	{ 0x0042, &nv04_gr_ofuncs }, /* surf2d */
1000 	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
1001 	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
1002 	{ 0x0048, &nv04_gr_ofuncs, nv03_gr_ttri_omthds },
1003 	{ 0x004a, &nv04_gr_ofuncs, nv04_gr_gdi_omthds },
1004 	{ 0x004b, &nv04_gr_ofuncs, nv03_gr_gdi_omthds },
1005 	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
1006 	{ 0x0053, &nv04_gr_ofuncs, nv04_gr_surf3d_omthds },
1007 	{ 0x0054, &nv04_gr_ofuncs }, /* ttri */
1008 	{ 0x0055, &nv04_gr_ofuncs }, /* mtri */
1009 	{ 0x0057, &nv04_gr_ofuncs }, /* chroma */
1010 	{ 0x0058, &nv04_gr_ofuncs }, /* surf_dst */
1011 	{ 0x0059, &nv04_gr_ofuncs }, /* surf_src */
1012 	{ 0x005a, &nv04_gr_ofuncs }, /* surf_color */
1013 	{ 0x005b, &nv04_gr_ofuncs }, /* surf_zeta */
1014 	{ 0x005c, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* line */
1015 	{ 0x005d, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* tri */
1016 	{ 0x005e, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* rect */
1017 	{ 0x005f, &nv04_gr_ofuncs, nv04_gr_blit_omthds },
1018 	{ 0x0060, &nv04_gr_ofuncs, nv04_gr_iifc_omthds },
1019 	{ 0x0061, &nv04_gr_ofuncs, nv04_gr_ifc_omthds },
1020 	{ 0x0064, &nv04_gr_ofuncs }, /* iifc (nv05) */
1021 	{ 0x0065, &nv04_gr_ofuncs }, /* ifc (nv05) */
1022 	{ 0x0066, &nv04_gr_ofuncs }, /* sifc (nv05) */
1023 	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
1024 	{ 0x0076, &nv04_gr_ofuncs, nv04_gr_sifc_omthds },
1025 	{ 0x0077, &nv04_gr_ofuncs, nv04_gr_sifm_omthds },
1026 	{},
1027 };
1028 
1029 /*******************************************************************************
1030  * PGRAPH context
1031  ******************************************************************************/
1032 
1033 static struct nv04_gr_chan *
1034 nv04_gr_channel(struct nv04_gr_priv *priv)
1035 {
1036 	struct nv04_gr_chan *chan = NULL;
1037 	if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) {
1038 		int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24;
1039 		if (chid < ARRAY_SIZE(priv->chan))
1040 			chan = priv->chan[chid];
1041 	}
1042 	return chan;
1043 }
1044 
1045 static int
1046 nv04_gr_load_context(struct nv04_gr_chan *chan, int chid)
1047 {
1048 	struct nv04_gr_priv *priv = nv04_gr_priv(chan);
1049 	int i;
1050 
1051 	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++)
1052 		nv_wr32(priv, nv04_gr_ctx_regs[i], chan->nv04[i]);
1053 
1054 	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
1055 	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24);
1056 	nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000);
1057 	return 0;
1058 }
1059 
1060 static int
1061 nv04_gr_unload_context(struct nv04_gr_chan *chan)
1062 {
1063 	struct nv04_gr_priv *priv = nv04_gr_priv(chan);
1064 	int i;
1065 
1066 	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++)
1067 		chan->nv04[i] = nv_rd32(priv, nv04_gr_ctx_regs[i]);
1068 
1069 	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
1070 	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
1071 	return 0;
1072 }
1073 
1074 static void
1075 nv04_gr_context_switch(struct nv04_gr_priv *priv)
1076 {
1077 	struct nv04_gr_chan *prev = NULL;
1078 	struct nv04_gr_chan *next = NULL;
1079 	unsigned long flags;
1080 	int chid;
1081 
1082 	spin_lock_irqsave(&priv->lock, flags);
1083 	nv04_gr_idle(priv);
1084 
1085 	/* If previous context is valid, we need to save it */
1086 	prev = nv04_gr_channel(priv);
1087 	if (prev)
1088 		nv04_gr_unload_context(prev);
1089 
1090 	/* load context for next channel */
1091 	chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f;
1092 	next = priv->chan[chid];
1093 	if (next)
1094 		nv04_gr_load_context(next, chid);
1095 
1096 	spin_unlock_irqrestore(&priv->lock, flags);
1097 }
1098 
1099 static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg)
1100 {
1101 	int i;
1102 
1103 	for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) {
1104 		if (nv04_gr_ctx_regs[i] == reg)
1105 			return &chan->nv04[i];
1106 	}
1107 
1108 	return NULL;
1109 }
1110 
1111 static int
1112 nv04_gr_context_ctor(struct nvkm_object *parent,
1113 		     struct nvkm_object *engine,
1114 		     struct nvkm_oclass *oclass, void *data, u32 size,
1115 		     struct nvkm_object **pobject)
1116 {
1117 	struct nvkm_fifo_chan *fifo = (void *)parent;
1118 	struct nv04_gr_priv *priv = (void *)engine;
1119 	struct nv04_gr_chan *chan;
1120 	unsigned long flags;
1121 	int ret;
1122 
1123 	ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
1124 	*pobject = nv_object(chan);
1125 	if (ret)
1126 		return ret;
1127 
1128 	spin_lock_irqsave(&priv->lock, flags);
1129 	if (priv->chan[fifo->chid]) {
1130 		*pobject = nv_object(priv->chan[fifo->chid]);
1131 		atomic_inc(&(*pobject)->refcount);
1132 		spin_unlock_irqrestore(&priv->lock, flags);
1133 		nvkm_object_destroy(&chan->base);
1134 		return 1;
1135 	}
1136 
1137 	*ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
1138 
1139 	priv->chan[fifo->chid] = chan;
1140 	chan->chid = fifo->chid;
1141 	spin_unlock_irqrestore(&priv->lock, flags);
1142 	return 0;
1143 }
1144 
1145 static void
1146 nv04_gr_context_dtor(struct nvkm_object *object)
1147 {
1148 	struct nv04_gr_priv *priv = (void *)object->engine;
1149 	struct nv04_gr_chan *chan = (void *)object;
1150 	unsigned long flags;
1151 
1152 	spin_lock_irqsave(&priv->lock, flags);
1153 	priv->chan[chan->chid] = NULL;
1154 	spin_unlock_irqrestore(&priv->lock, flags);
1155 
1156 	nvkm_object_destroy(&chan->base);
1157 }
1158 
1159 static int
1160 nv04_gr_context_fini(struct nvkm_object *object, bool suspend)
1161 {
1162 	struct nv04_gr_priv *priv = (void *)object->engine;
1163 	struct nv04_gr_chan *chan = (void *)object;
1164 	unsigned long flags;
1165 
1166 	spin_lock_irqsave(&priv->lock, flags);
1167 	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
1168 	if (nv04_gr_channel(priv) == chan)
1169 		nv04_gr_unload_context(chan);
1170 	nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
1171 	spin_unlock_irqrestore(&priv->lock, flags);
1172 
1173 	return nvkm_object_fini(&chan->base, suspend);
1174 }
1175 
1176 static struct nvkm_oclass
1177 nv04_gr_cclass = {
1178 	.handle = NV_ENGCTX(GR, 0x04),
1179 	.ofuncs = &(struct nvkm_ofuncs) {
1180 		.ctor = nv04_gr_context_ctor,
1181 		.dtor = nv04_gr_context_dtor,
1182 		.init = nvkm_object_init,
1183 		.fini = nv04_gr_context_fini,
1184 	},
1185 };
1186 
1187 /*******************************************************************************
1188  * PGRAPH engine/subdev functions
1189  ******************************************************************************/
1190 
1191 bool
1192 nv04_gr_idle(void *obj)
1193 {
1194 	struct nvkm_gr *gr = nvkm_gr(obj);
1195 	u32 mask = 0xffffffff;
1196 
1197 	if (nv_device(obj)->card_type == NV_40)
1198 		mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
1199 
1200 	if (!nv_wait(gr, NV04_PGRAPH_STATUS, mask, 0)) {
1201 		nv_error(gr, "idle timed out with status 0x%08x\n",
1202 			 nv_rd32(gr, NV04_PGRAPH_STATUS));
1203 		return false;
1204 	}
1205 
1206 	return true;
1207 }
1208 
1209 static const struct nvkm_bitfield
1210 nv04_gr_intr_name[] = {
1211 	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
1212 	{}
1213 };
1214 
1215 static const struct nvkm_bitfield
1216 nv04_gr_nstatus[] = {
1217 	{ NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
1218 	{ NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
1219 	{ NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
1220 	{ NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
1221 	{}
1222 };
1223 
1224 const struct nvkm_bitfield
1225 nv04_gr_nsource[] = {
1226 	{ NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
1227 	{ NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
1228 	{ NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
1229 	{ NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
1230 	{ NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
1231 	{ NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
1232 	{ NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
1233 	{ NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
1234 	{ NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
1235 	{ NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
1236 	{ NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
1237 	{ NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
1238 	{ NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
1239 	{ NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
1240 	{ NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
1241 	{ NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
1242 	{ NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
1243 	{ NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
1244 	{ NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
1245 	{}
1246 };
1247 
1248 static void
1249 nv04_gr_intr(struct nvkm_subdev *subdev)
1250 {
1251 	struct nv04_gr_priv *priv = (void *)subdev;
1252 	struct nv04_gr_chan *chan = NULL;
1253 	struct nvkm_namedb *namedb = NULL;
1254 	struct nvkm_handle *handle = NULL;
1255 	u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
1256 	u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
1257 	u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
1258 	u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
1259 	u32 chid = (addr & 0x0f000000) >> 24;
1260 	u32 subc = (addr & 0x0000e000) >> 13;
1261 	u32 mthd = (addr & 0x00001ffc);
1262 	u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
1263 	u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff;
1264 	u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4;
1265 	u32 show = stat;
1266 	unsigned long flags;
1267 
1268 	spin_lock_irqsave(&priv->lock, flags);
1269 	chan = priv->chan[chid];
1270 	if (chan)
1271 		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
1272 	spin_unlock_irqrestore(&priv->lock, flags);
1273 
1274 	if (stat & NV_PGRAPH_INTR_NOTIFY) {
1275 		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
1276 			handle = nvkm_namedb_get_vinst(namedb, inst);
1277 			if (handle && !nv_call(handle->object, mthd, data))
1278 				show &= ~NV_PGRAPH_INTR_NOTIFY;
1279 		}
1280 	}
1281 
1282 	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
1283 		nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
1284 		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
1285 		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
1286 		nv04_gr_context_switch(priv);
1287 	}
1288 
1289 	nv_wr32(priv, NV03_PGRAPH_INTR, stat);
1290 	nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
1291 
1292 	if (show) {
1293 		nv_error(priv, "%s", "");
1294 		nvkm_bitfield_print(nv04_gr_intr_name, show);
1295 		pr_cont(" nsource:");
1296 		nvkm_bitfield_print(nv04_gr_nsource, nsource);
1297 		pr_cont(" nstatus:");
1298 		nvkm_bitfield_print(nv04_gr_nstatus, nstatus);
1299 		pr_cont("\n");
1300 		nv_error(priv,
1301 			 "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
1302 			 chid, nvkm_client_name(chan), subc, class, mthd,
1303 			 data);
1304 	}
1305 
1306 	nvkm_namedb_put(handle);
1307 }
1308 
1309 static int
1310 nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
1311 	     struct nvkm_oclass *oclass, void *data, u32 size,
1312 	     struct nvkm_object **pobject)
1313 {
1314 	struct nv04_gr_priv *priv;
1315 	int ret;
1316 
1317 	ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
1318 	*pobject = nv_object(priv);
1319 	if (ret)
1320 		return ret;
1321 
1322 	nv_subdev(priv)->unit = 0x00001000;
1323 	nv_subdev(priv)->intr = nv04_gr_intr;
1324 	nv_engine(priv)->cclass = &nv04_gr_cclass;
1325 	nv_engine(priv)->sclass = nv04_gr_sclass;
1326 	spin_lock_init(&priv->lock);
1327 	return 0;
1328 }
1329 
1330 static int
1331 nv04_gr_init(struct nvkm_object *object)
1332 {
1333 	struct nvkm_engine *engine = nv_engine(object);
1334 	struct nv04_gr_priv *priv = (void *)engine;
1335 	int ret;
1336 
1337 	ret = nvkm_gr_init(&priv->base);
1338 	if (ret)
1339 		return ret;
1340 
1341 	/* Enable PGRAPH interrupts */
1342 	nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF);
1343 	nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
1344 
1345 	nv_wr32(priv, NV04_PGRAPH_VALID1, 0);
1346 	nv_wr32(priv, NV04_PGRAPH_VALID2, 0);
1347 	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF);
1348 	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
1349 	nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000);
1350 	/*1231C000 blob, 001 haiku*/
1351 	/*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
1352 	nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100);
1353 	/*0x72111100 blob , 01 haiku*/
1354 	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
1355 	nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
1356 	/*haiku same*/
1357 
1358 	/*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
1359 	nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
1360 	/*haiku and blob 10d4*/
1361 
1362 	nv_wr32(priv, NV04_PGRAPH_STATE        , 0xFFFFFFFF);
1363 	nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL  , 0x10000100);
1364 	nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
1365 
1366 	/* These don't belong here, they're part of a per-channel context */
1367 	nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
1368 	nv_wr32(priv, NV04_PGRAPH_BETA_AND     , 0xFFFFFFFF);
1369 	return 0;
1370 }
1371 
1372 struct nvkm_oclass
1373 nv04_gr_oclass = {
1374 	.handle = NV_ENGINE(GR, 0x04),
1375 	.ofuncs = &(struct nvkm_ofuncs) {
1376 		.ctor = nv04_gr_ctor,
1377 		.dtor = _nvkm_gr_dtor,
1378 		.init = nv04_gr_init,
1379 		.fini = _nvkm_gr_fini,
1380 	},
1381 };
1382