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