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