1 /*
2  * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr>
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/fb.h>
31 
32 struct pipe_state {
33 	u32 pipe_0x0000[0x040/4];
34 	u32 pipe_0x0040[0x010/4];
35 	u32 pipe_0x0200[0x0c0/4];
36 	u32 pipe_0x4400[0x080/4];
37 	u32 pipe_0x6400[0x3b0/4];
38 	u32 pipe_0x6800[0x2f0/4];
39 	u32 pipe_0x6c00[0x030/4];
40 	u32 pipe_0x7000[0x130/4];
41 	u32 pipe_0x7400[0x0c0/4];
42 	u32 pipe_0x7800[0x0c0/4];
43 };
44 
45 static int nv10_gr_ctx_regs[] = {
46 	NV10_PGRAPH_CTX_SWITCH(0),
47 	NV10_PGRAPH_CTX_SWITCH(1),
48 	NV10_PGRAPH_CTX_SWITCH(2),
49 	NV10_PGRAPH_CTX_SWITCH(3),
50 	NV10_PGRAPH_CTX_SWITCH(4),
51 	NV10_PGRAPH_CTX_CACHE(0, 0),
52 	NV10_PGRAPH_CTX_CACHE(0, 1),
53 	NV10_PGRAPH_CTX_CACHE(0, 2),
54 	NV10_PGRAPH_CTX_CACHE(0, 3),
55 	NV10_PGRAPH_CTX_CACHE(0, 4),
56 	NV10_PGRAPH_CTX_CACHE(1, 0),
57 	NV10_PGRAPH_CTX_CACHE(1, 1),
58 	NV10_PGRAPH_CTX_CACHE(1, 2),
59 	NV10_PGRAPH_CTX_CACHE(1, 3),
60 	NV10_PGRAPH_CTX_CACHE(1, 4),
61 	NV10_PGRAPH_CTX_CACHE(2, 0),
62 	NV10_PGRAPH_CTX_CACHE(2, 1),
63 	NV10_PGRAPH_CTX_CACHE(2, 2),
64 	NV10_PGRAPH_CTX_CACHE(2, 3),
65 	NV10_PGRAPH_CTX_CACHE(2, 4),
66 	NV10_PGRAPH_CTX_CACHE(3, 0),
67 	NV10_PGRAPH_CTX_CACHE(3, 1),
68 	NV10_PGRAPH_CTX_CACHE(3, 2),
69 	NV10_PGRAPH_CTX_CACHE(3, 3),
70 	NV10_PGRAPH_CTX_CACHE(3, 4),
71 	NV10_PGRAPH_CTX_CACHE(4, 0),
72 	NV10_PGRAPH_CTX_CACHE(4, 1),
73 	NV10_PGRAPH_CTX_CACHE(4, 2),
74 	NV10_PGRAPH_CTX_CACHE(4, 3),
75 	NV10_PGRAPH_CTX_CACHE(4, 4),
76 	NV10_PGRAPH_CTX_CACHE(5, 0),
77 	NV10_PGRAPH_CTX_CACHE(5, 1),
78 	NV10_PGRAPH_CTX_CACHE(5, 2),
79 	NV10_PGRAPH_CTX_CACHE(5, 3),
80 	NV10_PGRAPH_CTX_CACHE(5, 4),
81 	NV10_PGRAPH_CTX_CACHE(6, 0),
82 	NV10_PGRAPH_CTX_CACHE(6, 1),
83 	NV10_PGRAPH_CTX_CACHE(6, 2),
84 	NV10_PGRAPH_CTX_CACHE(6, 3),
85 	NV10_PGRAPH_CTX_CACHE(6, 4),
86 	NV10_PGRAPH_CTX_CACHE(7, 0),
87 	NV10_PGRAPH_CTX_CACHE(7, 1),
88 	NV10_PGRAPH_CTX_CACHE(7, 2),
89 	NV10_PGRAPH_CTX_CACHE(7, 3),
90 	NV10_PGRAPH_CTX_CACHE(7, 4),
91 	NV10_PGRAPH_CTX_USER,
92 	NV04_PGRAPH_DMA_START_0,
93 	NV04_PGRAPH_DMA_START_1,
94 	NV04_PGRAPH_DMA_LENGTH,
95 	NV04_PGRAPH_DMA_MISC,
96 	NV10_PGRAPH_DMA_PITCH,
97 	NV04_PGRAPH_BOFFSET0,
98 	NV04_PGRAPH_BBASE0,
99 	NV04_PGRAPH_BLIMIT0,
100 	NV04_PGRAPH_BOFFSET1,
101 	NV04_PGRAPH_BBASE1,
102 	NV04_PGRAPH_BLIMIT1,
103 	NV04_PGRAPH_BOFFSET2,
104 	NV04_PGRAPH_BBASE2,
105 	NV04_PGRAPH_BLIMIT2,
106 	NV04_PGRAPH_BOFFSET3,
107 	NV04_PGRAPH_BBASE3,
108 	NV04_PGRAPH_BLIMIT3,
109 	NV04_PGRAPH_BOFFSET4,
110 	NV04_PGRAPH_BBASE4,
111 	NV04_PGRAPH_BLIMIT4,
112 	NV04_PGRAPH_BOFFSET5,
113 	NV04_PGRAPH_BBASE5,
114 	NV04_PGRAPH_BLIMIT5,
115 	NV04_PGRAPH_BPITCH0,
116 	NV04_PGRAPH_BPITCH1,
117 	NV04_PGRAPH_BPITCH2,
118 	NV04_PGRAPH_BPITCH3,
119 	NV04_PGRAPH_BPITCH4,
120 	NV10_PGRAPH_SURFACE,
121 	NV10_PGRAPH_STATE,
122 	NV04_PGRAPH_BSWIZZLE2,
123 	NV04_PGRAPH_BSWIZZLE5,
124 	NV04_PGRAPH_BPIXEL,
125 	NV10_PGRAPH_NOTIFY,
126 	NV04_PGRAPH_PATT_COLOR0,
127 	NV04_PGRAPH_PATT_COLOR1,
128 	NV04_PGRAPH_PATT_COLORRAM, /* 64 values from 0x400900 to 0x4009fc */
129 	0x00400904,
130 	0x00400908,
131 	0x0040090c,
132 	0x00400910,
133 	0x00400914,
134 	0x00400918,
135 	0x0040091c,
136 	0x00400920,
137 	0x00400924,
138 	0x00400928,
139 	0x0040092c,
140 	0x00400930,
141 	0x00400934,
142 	0x00400938,
143 	0x0040093c,
144 	0x00400940,
145 	0x00400944,
146 	0x00400948,
147 	0x0040094c,
148 	0x00400950,
149 	0x00400954,
150 	0x00400958,
151 	0x0040095c,
152 	0x00400960,
153 	0x00400964,
154 	0x00400968,
155 	0x0040096c,
156 	0x00400970,
157 	0x00400974,
158 	0x00400978,
159 	0x0040097c,
160 	0x00400980,
161 	0x00400984,
162 	0x00400988,
163 	0x0040098c,
164 	0x00400990,
165 	0x00400994,
166 	0x00400998,
167 	0x0040099c,
168 	0x004009a0,
169 	0x004009a4,
170 	0x004009a8,
171 	0x004009ac,
172 	0x004009b0,
173 	0x004009b4,
174 	0x004009b8,
175 	0x004009bc,
176 	0x004009c0,
177 	0x004009c4,
178 	0x004009c8,
179 	0x004009cc,
180 	0x004009d0,
181 	0x004009d4,
182 	0x004009d8,
183 	0x004009dc,
184 	0x004009e0,
185 	0x004009e4,
186 	0x004009e8,
187 	0x004009ec,
188 	0x004009f0,
189 	0x004009f4,
190 	0x004009f8,
191 	0x004009fc,
192 	NV04_PGRAPH_PATTERN,	/* 2 values from 0x400808 to 0x40080c */
193 	0x0040080c,
194 	NV04_PGRAPH_PATTERN_SHAPE,
195 	NV03_PGRAPH_MONO_COLOR0,
196 	NV04_PGRAPH_ROP3,
197 	NV04_PGRAPH_CHROMA,
198 	NV04_PGRAPH_BETA_AND,
199 	NV04_PGRAPH_BETA_PREMULT,
200 	0x00400e70,
201 	0x00400e74,
202 	0x00400e78,
203 	0x00400e7c,
204 	0x00400e80,
205 	0x00400e84,
206 	0x00400e88,
207 	0x00400e8c,
208 	0x00400ea0,
209 	0x00400ea4,
210 	0x00400ea8,
211 	0x00400e90,
212 	0x00400e94,
213 	0x00400e98,
214 	0x00400e9c,
215 	NV10_PGRAPH_WINDOWCLIP_HORIZONTAL, /* 8 values from 0x400f00-0x400f1c */
216 	NV10_PGRAPH_WINDOWCLIP_VERTICAL,   /* 8 values from 0x400f20-0x400f3c */
217 	0x00400f04,
218 	0x00400f24,
219 	0x00400f08,
220 	0x00400f28,
221 	0x00400f0c,
222 	0x00400f2c,
223 	0x00400f10,
224 	0x00400f30,
225 	0x00400f14,
226 	0x00400f34,
227 	0x00400f18,
228 	0x00400f38,
229 	0x00400f1c,
230 	0x00400f3c,
231 	NV10_PGRAPH_XFMODE0,
232 	NV10_PGRAPH_XFMODE1,
233 	NV10_PGRAPH_GLOBALSTATE0,
234 	NV10_PGRAPH_GLOBALSTATE1,
235 	NV04_PGRAPH_STORED_FMT,
236 	NV04_PGRAPH_SOURCE_COLOR,
237 	NV03_PGRAPH_ABS_X_RAM,	/* 32 values from 0x400400 to 0x40047c */
238 	NV03_PGRAPH_ABS_Y_RAM,	/* 32 values from 0x400480 to 0x4004fc */
239 	0x00400404,
240 	0x00400484,
241 	0x00400408,
242 	0x00400488,
243 	0x0040040c,
244 	0x0040048c,
245 	0x00400410,
246 	0x00400490,
247 	0x00400414,
248 	0x00400494,
249 	0x00400418,
250 	0x00400498,
251 	0x0040041c,
252 	0x0040049c,
253 	0x00400420,
254 	0x004004a0,
255 	0x00400424,
256 	0x004004a4,
257 	0x00400428,
258 	0x004004a8,
259 	0x0040042c,
260 	0x004004ac,
261 	0x00400430,
262 	0x004004b0,
263 	0x00400434,
264 	0x004004b4,
265 	0x00400438,
266 	0x004004b8,
267 	0x0040043c,
268 	0x004004bc,
269 	0x00400440,
270 	0x004004c0,
271 	0x00400444,
272 	0x004004c4,
273 	0x00400448,
274 	0x004004c8,
275 	0x0040044c,
276 	0x004004cc,
277 	0x00400450,
278 	0x004004d0,
279 	0x00400454,
280 	0x004004d4,
281 	0x00400458,
282 	0x004004d8,
283 	0x0040045c,
284 	0x004004dc,
285 	0x00400460,
286 	0x004004e0,
287 	0x00400464,
288 	0x004004e4,
289 	0x00400468,
290 	0x004004e8,
291 	0x0040046c,
292 	0x004004ec,
293 	0x00400470,
294 	0x004004f0,
295 	0x00400474,
296 	0x004004f4,
297 	0x00400478,
298 	0x004004f8,
299 	0x0040047c,
300 	0x004004fc,
301 	NV03_PGRAPH_ABS_UCLIP_XMIN,
302 	NV03_PGRAPH_ABS_UCLIP_XMAX,
303 	NV03_PGRAPH_ABS_UCLIP_YMIN,
304 	NV03_PGRAPH_ABS_UCLIP_YMAX,
305 	0x00400550,
306 	0x00400558,
307 	0x00400554,
308 	0x0040055c,
309 	NV03_PGRAPH_ABS_UCLIPA_XMIN,
310 	NV03_PGRAPH_ABS_UCLIPA_XMAX,
311 	NV03_PGRAPH_ABS_UCLIPA_YMIN,
312 	NV03_PGRAPH_ABS_UCLIPA_YMAX,
313 	NV03_PGRAPH_ABS_ICLIP_XMAX,
314 	NV03_PGRAPH_ABS_ICLIP_YMAX,
315 	NV03_PGRAPH_XY_LOGIC_MISC0,
316 	NV03_PGRAPH_XY_LOGIC_MISC1,
317 	NV03_PGRAPH_XY_LOGIC_MISC2,
318 	NV03_PGRAPH_XY_LOGIC_MISC3,
319 	NV03_PGRAPH_CLIPX_0,
320 	NV03_PGRAPH_CLIPX_1,
321 	NV03_PGRAPH_CLIPY_0,
322 	NV03_PGRAPH_CLIPY_1,
323 	NV10_PGRAPH_COMBINER0_IN_ALPHA,
324 	NV10_PGRAPH_COMBINER1_IN_ALPHA,
325 	NV10_PGRAPH_COMBINER0_IN_RGB,
326 	NV10_PGRAPH_COMBINER1_IN_RGB,
327 	NV10_PGRAPH_COMBINER_COLOR0,
328 	NV10_PGRAPH_COMBINER_COLOR1,
329 	NV10_PGRAPH_COMBINER0_OUT_ALPHA,
330 	NV10_PGRAPH_COMBINER1_OUT_ALPHA,
331 	NV10_PGRAPH_COMBINER0_OUT_RGB,
332 	NV10_PGRAPH_COMBINER1_OUT_RGB,
333 	NV10_PGRAPH_COMBINER_FINAL0,
334 	NV10_PGRAPH_COMBINER_FINAL1,
335 	0x00400e00,
336 	0x00400e04,
337 	0x00400e08,
338 	0x00400e0c,
339 	0x00400e10,
340 	0x00400e14,
341 	0x00400e18,
342 	0x00400e1c,
343 	0x00400e20,
344 	0x00400e24,
345 	0x00400e28,
346 	0x00400e2c,
347 	0x00400e30,
348 	0x00400e34,
349 	0x00400e38,
350 	0x00400e3c,
351 	NV04_PGRAPH_PASSTHRU_0,
352 	NV04_PGRAPH_PASSTHRU_1,
353 	NV04_PGRAPH_PASSTHRU_2,
354 	NV10_PGRAPH_DIMX_TEXTURE,
355 	NV10_PGRAPH_WDIMX_TEXTURE,
356 	NV10_PGRAPH_DVD_COLORFMT,
357 	NV10_PGRAPH_SCALED_FORMAT,
358 	NV04_PGRAPH_MISC24_0,
359 	NV04_PGRAPH_MISC24_1,
360 	NV04_PGRAPH_MISC24_2,
361 	NV03_PGRAPH_X_MISC,
362 	NV03_PGRAPH_Y_MISC,
363 	NV04_PGRAPH_VALID1,
364 	NV04_PGRAPH_VALID2,
365 };
366 
367 static int nv17_gr_ctx_regs[] = {
368 	NV10_PGRAPH_DEBUG_4,
369 	0x004006b0,
370 	0x00400eac,
371 	0x00400eb0,
372 	0x00400eb4,
373 	0x00400eb8,
374 	0x00400ebc,
375 	0x00400ec0,
376 	0x00400ec4,
377 	0x00400ec8,
378 	0x00400ecc,
379 	0x00400ed0,
380 	0x00400ed4,
381 	0x00400ed8,
382 	0x00400edc,
383 	0x00400ee0,
384 	0x00400a00,
385 	0x00400a04,
386 };
387 
388 struct nv10_gr {
389 	struct nvkm_gr base;
390 	struct nv10_gr_chan *chan[32];
391 	spinlock_t lock;
392 };
393 
394 struct nv10_gr_chan {
395 	struct nvkm_object base;
396 	int chid;
397 	int nv10[ARRAY_SIZE(nv10_gr_ctx_regs)];
398 	int nv17[ARRAY_SIZE(nv17_gr_ctx_regs)];
399 	struct pipe_state pipe_state;
400 	u32 lma_window[4];
401 };
402 
403 
404 static inline struct nv10_gr *
405 nv10_gr(struct nv10_gr_chan *chan)
406 {
407 	return (void *)nv_object(chan)->engine;
408 }
409 
410 /*******************************************************************************
411  * Graphics object classes
412  ******************************************************************************/
413 
414 #define PIPE_SAVE(gr, state, addr)					\
415 	do {								\
416 		int __i;						\
417 		nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
418 		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
419 			state[__i] = nvkm_rd32(device, NV10_PGRAPH_PIPE_DATA); \
420 	} while (0)
421 
422 #define PIPE_RESTORE(gr, state, addr)					\
423 	do {								\
424 		int __i;						\
425 		nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, addr);		\
426 		for (__i = 0; __i < ARRAY_SIZE(state); __i++)		\
427 			nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, state[__i]); \
428 	} while (0)
429 
430 static struct nvkm_oclass
431 nv10_gr_sclass[] = {
432 	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
433 	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
434 	{ 0x0030, &nv04_gr_ofuncs }, /* null */
435 	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
436 	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
437 	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
438 	{ 0x004a, &nv04_gr_ofuncs }, /* gdi */
439 	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
440 	{ 0x005f, &nv04_gr_ofuncs }, /* blit */
441 	{ 0x0062, &nv04_gr_ofuncs }, /* surf2d */
442 	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
443 	{ 0x0089, &nv04_gr_ofuncs }, /* sifm */
444 	{ 0x008a, &nv04_gr_ofuncs }, /* ifc */
445 	{ 0x009f, &nv04_gr_ofuncs }, /* blit */
446 	{ 0x0093, &nv04_gr_ofuncs }, /* surf3d */
447 	{ 0x0094, &nv04_gr_ofuncs }, /* ttri */
448 	{ 0x0095, &nv04_gr_ofuncs }, /* mtri */
449 	{ 0x0056, &nv04_gr_ofuncs }, /* celcius */
450 	{},
451 };
452 
453 static struct nvkm_oclass
454 nv15_gr_sclass[] = {
455 	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
456 	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
457 	{ 0x0030, &nv04_gr_ofuncs }, /* null */
458 	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
459 	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
460 	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
461 	{ 0x004a, &nv04_gr_ofuncs }, /* gdi */
462 	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
463 	{ 0x005f, &nv04_gr_ofuncs }, /* blit */
464 	{ 0x0062, &nv04_gr_ofuncs }, /* surf2d */
465 	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
466 	{ 0x0089, &nv04_gr_ofuncs }, /* sifm */
467 	{ 0x008a, &nv04_gr_ofuncs }, /* ifc */
468 	{ 0x009f, &nv04_gr_ofuncs }, /* blit */
469 	{ 0x0093, &nv04_gr_ofuncs }, /* surf3d */
470 	{ 0x0094, &nv04_gr_ofuncs }, /* ttri */
471 	{ 0x0095, &nv04_gr_ofuncs }, /* mtri */
472 	{ 0x0096, &nv04_gr_ofuncs }, /* celcius */
473 	{},
474 };
475 
476 static int
477 nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd,
478 			void *args, u32 size)
479 {
480 	struct nv10_gr_chan *chan = (void *)object->parent;
481 	struct nv10_gr *gr = nv10_gr(chan);
482 	struct pipe_state *pipe = &chan->pipe_state;
483 	struct nvkm_device *device = gr->base.engine.subdev.device;
484 	u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
485 	u32 xfmode0, xfmode1;
486 	u32 data = *(u32 *)args;
487 	int i;
488 
489 	chan->lma_window[(mthd - 0x1638) / 4] = data;
490 
491 	if (mthd != 0x1644)
492 		return 0;
493 
494 	nv04_gr_idle(gr);
495 
496 	PIPE_SAVE(gr, pipe_0x0040, 0x0040);
497 	PIPE_SAVE(gr, pipe->pipe_0x0200, 0x0200);
498 
499 	PIPE_RESTORE(gr, chan->lma_window, 0x6790);
500 
501 	nv04_gr_idle(gr);
502 
503 	xfmode0 = nvkm_rd32(device, NV10_PGRAPH_XFMODE0);
504 	xfmode1 = nvkm_rd32(device, NV10_PGRAPH_XFMODE1);
505 
506 	PIPE_SAVE(gr, pipe->pipe_0x4400, 0x4400);
507 	PIPE_SAVE(gr, pipe_0x64c0, 0x64c0);
508 	PIPE_SAVE(gr, pipe_0x6ab0, 0x6ab0);
509 	PIPE_SAVE(gr, pipe_0x6a80, 0x6a80);
510 
511 	nv04_gr_idle(gr);
512 
513 	nvkm_wr32(device, NV10_PGRAPH_XFMODE0, 0x10000000);
514 	nvkm_wr32(device, NV10_PGRAPH_XFMODE1, 0x00000000);
515 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
516 	for (i = 0; i < 4; i++)
517 		nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
518 	for (i = 0; i < 4; i++)
519 		nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000);
520 
521 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
522 	for (i = 0; i < 3; i++)
523 		nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
524 
525 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
526 	for (i = 0; i < 3; i++)
527 		nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000);
528 
529 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
530 	nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000008);
531 
532 	PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200);
533 
534 	nv04_gr_idle(gr);
535 
536 	PIPE_RESTORE(gr, pipe_0x0040, 0x0040);
537 
538 	nvkm_wr32(device, NV10_PGRAPH_XFMODE0, xfmode0);
539 	nvkm_wr32(device, NV10_PGRAPH_XFMODE1, xfmode1);
540 
541 	PIPE_RESTORE(gr, pipe_0x64c0, 0x64c0);
542 	PIPE_RESTORE(gr, pipe_0x6ab0, 0x6ab0);
543 	PIPE_RESTORE(gr, pipe_0x6a80, 0x6a80);
544 	PIPE_RESTORE(gr, pipe->pipe_0x4400, 0x4400);
545 
546 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
547 	nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000);
548 
549 	nv04_gr_idle(gr);
550 
551 	return 0;
552 }
553 
554 static int
555 nv17_gr_mthd_lma_enable(struct nvkm_object *object, u32 mthd,
556 			void *args, u32 size)
557 {
558 	struct nv10_gr_chan *chan = (void *)object->parent;
559 	struct nv10_gr *gr = nv10_gr(chan);
560 	struct nvkm_device *device = gr->base.engine.subdev.device;
561 
562 	nv04_gr_idle(gr);
563 
564 	nvkm_mask(device, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100);
565 	nvkm_mask(device, 0x4006b0, 0x08000000, 0x08000000);
566 	return 0;
567 }
568 
569 static struct nvkm_omthds
570 nv17_celcius_omthds[] = {
571 	{ 0x1638, 0x1638, nv17_gr_mthd_lma_window },
572 	{ 0x163c, 0x163c, nv17_gr_mthd_lma_window },
573 	{ 0x1640, 0x1640, nv17_gr_mthd_lma_window },
574 	{ 0x1644, 0x1644, nv17_gr_mthd_lma_window },
575 	{ 0x1658, 0x1658, nv17_gr_mthd_lma_enable },
576 	{}
577 };
578 
579 static struct nvkm_oclass
580 nv17_gr_sclass[] = {
581 	{ 0x0012, &nv04_gr_ofuncs }, /* beta1 */
582 	{ 0x0019, &nv04_gr_ofuncs }, /* clip */
583 	{ 0x0030, &nv04_gr_ofuncs }, /* null */
584 	{ 0x0039, &nv04_gr_ofuncs }, /* m2mf */
585 	{ 0x0043, &nv04_gr_ofuncs }, /* rop */
586 	{ 0x0044, &nv04_gr_ofuncs }, /* pattern */
587 	{ 0x004a, &nv04_gr_ofuncs }, /* gdi */
588 	{ 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
589 	{ 0x005f, &nv04_gr_ofuncs }, /* blit */
590 	{ 0x0062, &nv04_gr_ofuncs }, /* surf2d */
591 	{ 0x0072, &nv04_gr_ofuncs }, /* beta4 */
592 	{ 0x0089, &nv04_gr_ofuncs }, /* sifm */
593 	{ 0x008a, &nv04_gr_ofuncs }, /* ifc */
594 	{ 0x009f, &nv04_gr_ofuncs }, /* blit */
595 	{ 0x0093, &nv04_gr_ofuncs }, /* surf3d */
596 	{ 0x0094, &nv04_gr_ofuncs }, /* ttri */
597 	{ 0x0095, &nv04_gr_ofuncs }, /* mtri */
598 	{ 0x0099, &nv04_gr_ofuncs, nv17_celcius_omthds },
599 	{},
600 };
601 
602 /*******************************************************************************
603  * PGRAPH context
604  ******************************************************************************/
605 
606 static struct nv10_gr_chan *
607 nv10_gr_channel(struct nv10_gr *gr)
608 {
609 	struct nvkm_device *device = gr->base.engine.subdev.device;
610 	struct nv10_gr_chan *chan = NULL;
611 	if (nvkm_rd32(device, 0x400144) & 0x00010000) {
612 		int chid = nvkm_rd32(device, 0x400148) >> 24;
613 		if (chid < ARRAY_SIZE(gr->chan))
614 			chan = gr->chan[chid];
615 	}
616 	return chan;
617 }
618 
619 static void
620 nv10_gr_save_pipe(struct nv10_gr_chan *chan)
621 {
622 	struct nv10_gr *gr = nv10_gr(chan);
623 	struct pipe_state *pipe = &chan->pipe_state;
624 	struct nvkm_device *device = gr->base.engine.subdev.device;
625 
626 	PIPE_SAVE(gr, pipe->pipe_0x4400, 0x4400);
627 	PIPE_SAVE(gr, pipe->pipe_0x0200, 0x0200);
628 	PIPE_SAVE(gr, pipe->pipe_0x6400, 0x6400);
629 	PIPE_SAVE(gr, pipe->pipe_0x6800, 0x6800);
630 	PIPE_SAVE(gr, pipe->pipe_0x6c00, 0x6c00);
631 	PIPE_SAVE(gr, pipe->pipe_0x7000, 0x7000);
632 	PIPE_SAVE(gr, pipe->pipe_0x7400, 0x7400);
633 	PIPE_SAVE(gr, pipe->pipe_0x7800, 0x7800);
634 	PIPE_SAVE(gr, pipe->pipe_0x0040, 0x0040);
635 	PIPE_SAVE(gr, pipe->pipe_0x0000, 0x0000);
636 }
637 
638 static void
639 nv10_gr_load_pipe(struct nv10_gr_chan *chan)
640 {
641 	struct nv10_gr *gr = nv10_gr(chan);
642 	struct pipe_state *pipe = &chan->pipe_state;
643 	struct nvkm_device *device = gr->base.engine.subdev.device;
644 	u32 xfmode0, xfmode1;
645 	int i;
646 
647 	nv04_gr_idle(gr);
648 	/* XXX check haiku comments */
649 	xfmode0 = nvkm_rd32(device, NV10_PGRAPH_XFMODE0);
650 	xfmode1 = nvkm_rd32(device, NV10_PGRAPH_XFMODE1);
651 	nvkm_wr32(device, NV10_PGRAPH_XFMODE0, 0x10000000);
652 	nvkm_wr32(device, NV10_PGRAPH_XFMODE1, 0x00000000);
653 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
654 	for (i = 0; i < 4; i++)
655 		nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
656 	for (i = 0; i < 4; i++)
657 		nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000);
658 
659 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
660 	for (i = 0; i < 3; i++)
661 		nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
662 
663 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
664 	for (i = 0; i < 3; i++)
665 		nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000);
666 
667 	nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
668 	nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000008);
669 
670 
671 	PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200);
672 	nv04_gr_idle(gr);
673 
674 	/* restore XFMODE */
675 	nvkm_wr32(device, NV10_PGRAPH_XFMODE0, xfmode0);
676 	nvkm_wr32(device, NV10_PGRAPH_XFMODE1, xfmode1);
677 	PIPE_RESTORE(gr, pipe->pipe_0x6400, 0x6400);
678 	PIPE_RESTORE(gr, pipe->pipe_0x6800, 0x6800);
679 	PIPE_RESTORE(gr, pipe->pipe_0x6c00, 0x6c00);
680 	PIPE_RESTORE(gr, pipe->pipe_0x7000, 0x7000);
681 	PIPE_RESTORE(gr, pipe->pipe_0x7400, 0x7400);
682 	PIPE_RESTORE(gr, pipe->pipe_0x7800, 0x7800);
683 	PIPE_RESTORE(gr, pipe->pipe_0x4400, 0x4400);
684 	PIPE_RESTORE(gr, pipe->pipe_0x0000, 0x0000);
685 	PIPE_RESTORE(gr, pipe->pipe_0x0040, 0x0040);
686 	nv04_gr_idle(gr);
687 }
688 
689 static void
690 nv10_gr_create_pipe(struct nv10_gr_chan *chan)
691 {
692 	struct nv10_gr *gr = nv10_gr(chan);
693 	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
694 	struct pipe_state *pipe_state = &chan->pipe_state;
695 	u32 *pipe_state_addr;
696 	int i;
697 #define PIPE_INIT(addr) \
698 	do { \
699 		pipe_state_addr = pipe_state->pipe_##addr; \
700 	} while (0)
701 #define PIPE_INIT_END(addr) \
702 	do { \
703 		u32 *__end_addr = pipe_state->pipe_##addr + \
704 				ARRAY_SIZE(pipe_state->pipe_##addr); \
705 		if (pipe_state_addr != __end_addr) \
706 			nvkm_error(subdev, "incomplete pipe init for 0x%x :  %p/%p\n", \
707 				addr, pipe_state_addr, __end_addr); \
708 	} while (0)
709 #define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value
710 
711 	PIPE_INIT(0x0200);
712 	for (i = 0; i < 48; i++)
713 		NV_WRITE_PIPE_INIT(0x00000000);
714 	PIPE_INIT_END(0x0200);
715 
716 	PIPE_INIT(0x6400);
717 	for (i = 0; i < 211; i++)
718 		NV_WRITE_PIPE_INIT(0x00000000);
719 	NV_WRITE_PIPE_INIT(0x3f800000);
720 	NV_WRITE_PIPE_INIT(0x40000000);
721 	NV_WRITE_PIPE_INIT(0x40000000);
722 	NV_WRITE_PIPE_INIT(0x40000000);
723 	NV_WRITE_PIPE_INIT(0x40000000);
724 	NV_WRITE_PIPE_INIT(0x00000000);
725 	NV_WRITE_PIPE_INIT(0x00000000);
726 	NV_WRITE_PIPE_INIT(0x3f800000);
727 	NV_WRITE_PIPE_INIT(0x00000000);
728 	NV_WRITE_PIPE_INIT(0x3f000000);
729 	NV_WRITE_PIPE_INIT(0x3f000000);
730 	NV_WRITE_PIPE_INIT(0x00000000);
731 	NV_WRITE_PIPE_INIT(0x00000000);
732 	NV_WRITE_PIPE_INIT(0x00000000);
733 	NV_WRITE_PIPE_INIT(0x00000000);
734 	NV_WRITE_PIPE_INIT(0x3f800000);
735 	NV_WRITE_PIPE_INIT(0x00000000);
736 	NV_WRITE_PIPE_INIT(0x00000000);
737 	NV_WRITE_PIPE_INIT(0x00000000);
738 	NV_WRITE_PIPE_INIT(0x00000000);
739 	NV_WRITE_PIPE_INIT(0x00000000);
740 	NV_WRITE_PIPE_INIT(0x3f800000);
741 	NV_WRITE_PIPE_INIT(0x3f800000);
742 	NV_WRITE_PIPE_INIT(0x3f800000);
743 	NV_WRITE_PIPE_INIT(0x3f800000);
744 	PIPE_INIT_END(0x6400);
745 
746 	PIPE_INIT(0x6800);
747 	for (i = 0; i < 162; i++)
748 		NV_WRITE_PIPE_INIT(0x00000000);
749 	NV_WRITE_PIPE_INIT(0x3f800000);
750 	for (i = 0; i < 25; i++)
751 		NV_WRITE_PIPE_INIT(0x00000000);
752 	PIPE_INIT_END(0x6800);
753 
754 	PIPE_INIT(0x6c00);
755 	NV_WRITE_PIPE_INIT(0x00000000);
756 	NV_WRITE_PIPE_INIT(0x00000000);
757 	NV_WRITE_PIPE_INIT(0x00000000);
758 	NV_WRITE_PIPE_INIT(0x00000000);
759 	NV_WRITE_PIPE_INIT(0xbf800000);
760 	NV_WRITE_PIPE_INIT(0x00000000);
761 	NV_WRITE_PIPE_INIT(0x00000000);
762 	NV_WRITE_PIPE_INIT(0x00000000);
763 	NV_WRITE_PIPE_INIT(0x00000000);
764 	NV_WRITE_PIPE_INIT(0x00000000);
765 	NV_WRITE_PIPE_INIT(0x00000000);
766 	NV_WRITE_PIPE_INIT(0x00000000);
767 	PIPE_INIT_END(0x6c00);
768 
769 	PIPE_INIT(0x7000);
770 	NV_WRITE_PIPE_INIT(0x00000000);
771 	NV_WRITE_PIPE_INIT(0x00000000);
772 	NV_WRITE_PIPE_INIT(0x00000000);
773 	NV_WRITE_PIPE_INIT(0x00000000);
774 	NV_WRITE_PIPE_INIT(0x00000000);
775 	NV_WRITE_PIPE_INIT(0x00000000);
776 	NV_WRITE_PIPE_INIT(0x00000000);
777 	NV_WRITE_PIPE_INIT(0x00000000);
778 	NV_WRITE_PIPE_INIT(0x00000000);
779 	NV_WRITE_PIPE_INIT(0x00000000);
780 	NV_WRITE_PIPE_INIT(0x00000000);
781 	NV_WRITE_PIPE_INIT(0x00000000);
782 	NV_WRITE_PIPE_INIT(0x7149f2ca);
783 	NV_WRITE_PIPE_INIT(0x00000000);
784 	NV_WRITE_PIPE_INIT(0x00000000);
785 	NV_WRITE_PIPE_INIT(0x00000000);
786 	NV_WRITE_PIPE_INIT(0x7149f2ca);
787 	NV_WRITE_PIPE_INIT(0x00000000);
788 	NV_WRITE_PIPE_INIT(0x00000000);
789 	NV_WRITE_PIPE_INIT(0x00000000);
790 	NV_WRITE_PIPE_INIT(0x7149f2ca);
791 	NV_WRITE_PIPE_INIT(0x00000000);
792 	NV_WRITE_PIPE_INIT(0x00000000);
793 	NV_WRITE_PIPE_INIT(0x00000000);
794 	NV_WRITE_PIPE_INIT(0x7149f2ca);
795 	NV_WRITE_PIPE_INIT(0x00000000);
796 	NV_WRITE_PIPE_INIT(0x00000000);
797 	NV_WRITE_PIPE_INIT(0x00000000);
798 	NV_WRITE_PIPE_INIT(0x7149f2ca);
799 	NV_WRITE_PIPE_INIT(0x00000000);
800 	NV_WRITE_PIPE_INIT(0x00000000);
801 	NV_WRITE_PIPE_INIT(0x00000000);
802 	NV_WRITE_PIPE_INIT(0x7149f2ca);
803 	NV_WRITE_PIPE_INIT(0x00000000);
804 	NV_WRITE_PIPE_INIT(0x00000000);
805 	NV_WRITE_PIPE_INIT(0x00000000);
806 	NV_WRITE_PIPE_INIT(0x7149f2ca);
807 	NV_WRITE_PIPE_INIT(0x00000000);
808 	NV_WRITE_PIPE_INIT(0x00000000);
809 	NV_WRITE_PIPE_INIT(0x00000000);
810 	NV_WRITE_PIPE_INIT(0x7149f2ca);
811 	for (i = 0; i < 35; i++)
812 		NV_WRITE_PIPE_INIT(0x00000000);
813 	PIPE_INIT_END(0x7000);
814 
815 	PIPE_INIT(0x7400);
816 	for (i = 0; i < 48; i++)
817 		NV_WRITE_PIPE_INIT(0x00000000);
818 	PIPE_INIT_END(0x7400);
819 
820 	PIPE_INIT(0x7800);
821 	for (i = 0; i < 48; i++)
822 		NV_WRITE_PIPE_INIT(0x00000000);
823 	PIPE_INIT_END(0x7800);
824 
825 	PIPE_INIT(0x4400);
826 	for (i = 0; i < 32; i++)
827 		NV_WRITE_PIPE_INIT(0x00000000);
828 	PIPE_INIT_END(0x4400);
829 
830 	PIPE_INIT(0x0000);
831 	for (i = 0; i < 16; i++)
832 		NV_WRITE_PIPE_INIT(0x00000000);
833 	PIPE_INIT_END(0x0000);
834 
835 	PIPE_INIT(0x0040);
836 	for (i = 0; i < 4; i++)
837 		NV_WRITE_PIPE_INIT(0x00000000);
838 	PIPE_INIT_END(0x0040);
839 
840 #undef PIPE_INIT
841 #undef PIPE_INIT_END
842 #undef NV_WRITE_PIPE_INIT
843 }
844 
845 static int
846 nv10_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg)
847 {
848 	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
849 	int i;
850 	for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) {
851 		if (nv10_gr_ctx_regs[i] == reg)
852 			return i;
853 	}
854 	nvkm_error(subdev, "unknow offset nv10_ctx_regs %d\n", reg);
855 	return -1;
856 }
857 
858 static int
859 nv17_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg)
860 {
861 	struct nvkm_subdev *subdev = &gr->base.engine.subdev;
862 	int i;
863 	for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) {
864 		if (nv17_gr_ctx_regs[i] == reg)
865 			return i;
866 	}
867 	nvkm_error(subdev, "unknow offset nv17_ctx_regs %d\n", reg);
868 	return -1;
869 }
870 
871 static void
872 nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst)
873 {
874 	struct nv10_gr *gr = nv10_gr(chan);
875 	struct nvkm_device *device = gr->base.engine.subdev.device;
876 	u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
877 	u32 ctx_user, ctx_switch[5];
878 	int i, subchan = -1;
879 
880 	/* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
881 	 * that cannot be restored via MMIO. Do it through the FIFO
882 	 * instead.
883 	 */
884 
885 	/* Look for a celsius object */
886 	for (i = 0; i < 8; i++) {
887 		int class = nvkm_rd32(device, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
888 
889 		if (class == 0x56 || class == 0x96 || class == 0x99) {
890 			subchan = i;
891 			break;
892 		}
893 	}
894 
895 	if (subchan < 0 || !inst)
896 		return;
897 
898 	/* Save the current ctx object */
899 	ctx_user = nvkm_rd32(device, NV10_PGRAPH_CTX_USER);
900 	for (i = 0; i < 5; i++)
901 		ctx_switch[i] = nvkm_rd32(device, NV10_PGRAPH_CTX_SWITCH(i));
902 
903 	/* Save the FIFO state */
904 	st2 = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2);
905 	st2_dl = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2_DL);
906 	st2_dh = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2_DH);
907 	fifo_ptr = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR);
908 
909 	for (i = 0; i < ARRAY_SIZE(fifo); i++)
910 		fifo[i] = nvkm_rd32(device, 0x4007a0 + 4 * i);
911 
912 	/* Switch to the celsius subchannel */
913 	for (i = 0; i < 5; i++)
914 		nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(i),
915 			nvkm_rd32(device, NV10_PGRAPH_CTX_CACHE(subchan, i)));
916 	nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
917 
918 	/* Inject NV10TCL_DMA_VTXBUF */
919 	nvkm_wr32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
920 	nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2,
921 		0x2c000000 | chid << 20 | subchan << 16 | 0x18c);
922 	nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
923 	nvkm_mask(device, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
924 	nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
925 	nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
926 
927 	/* Restore the FIFO state */
928 	for (i = 0; i < ARRAY_SIZE(fifo); i++)
929 		nvkm_wr32(device, 0x4007a0 + 4 * i, fifo[i]);
930 
931 	nvkm_wr32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
932 	nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2, st2);
933 	nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
934 	nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
935 
936 	/* Restore the current ctx object */
937 	for (i = 0; i < 5; i++)
938 		nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
939 	nvkm_wr32(device, NV10_PGRAPH_CTX_USER, ctx_user);
940 }
941 
942 static int
943 nv10_gr_load_context(struct nv10_gr_chan *chan, int chid)
944 {
945 	struct nv10_gr *gr = nv10_gr(chan);
946 	struct nvkm_device *device = gr->base.engine.subdev.device;
947 	u32 inst;
948 	int i;
949 
950 	for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++)
951 		nvkm_wr32(device, nv10_gr_ctx_regs[i], chan->nv10[i]);
952 
953 	if (nv_device(gr)->card_type >= NV_11 &&
954 	    nv_device(gr)->chipset >= 0x17) {
955 		for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++)
956 			nvkm_wr32(device, nv17_gr_ctx_regs[i], chan->nv17[i]);
957 	}
958 
959 	nv10_gr_load_pipe(chan);
960 
961 	inst = nvkm_rd32(device, NV10_PGRAPH_GLOBALSTATE1) & 0xffff;
962 	nv10_gr_load_dma_vtxbuf(chan, chid, inst);
963 
964 	nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
965 	nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24);
966 	nvkm_mask(device, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000);
967 	return 0;
968 }
969 
970 static int
971 nv10_gr_unload_context(struct nv10_gr_chan *chan)
972 {
973 	struct nv10_gr *gr = nv10_gr(chan);
974 	struct nvkm_device *device = gr->base.engine.subdev.device;
975 	int i;
976 
977 	for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++)
978 		chan->nv10[i] = nvkm_rd32(device, nv10_gr_ctx_regs[i]);
979 
980 	if (nv_device(gr)->card_type >= NV_11 &&
981 	    nv_device(gr)->chipset >= 0x17) {
982 		for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++)
983 			chan->nv17[i] = nvkm_rd32(device, nv17_gr_ctx_regs[i]);
984 	}
985 
986 	nv10_gr_save_pipe(chan);
987 
988 	nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
989 	nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
990 	return 0;
991 }
992 
993 static void
994 nv10_gr_context_switch(struct nv10_gr *gr)
995 {
996 	struct nvkm_device *device = gr->base.engine.subdev.device;
997 	struct nv10_gr_chan *prev = NULL;
998 	struct nv10_gr_chan *next = NULL;
999 	unsigned long flags;
1000 	int chid;
1001 
1002 	spin_lock_irqsave(&gr->lock, flags);
1003 	nv04_gr_idle(gr);
1004 
1005 	/* If previous context is valid, we need to save it */
1006 	prev = nv10_gr_channel(gr);
1007 	if (prev)
1008 		nv10_gr_unload_context(prev);
1009 
1010 	/* load context for next channel */
1011 	chid = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
1012 	next = gr->chan[chid];
1013 	if (next)
1014 		nv10_gr_load_context(next, chid);
1015 
1016 	spin_unlock_irqrestore(&gr->lock, flags);
1017 }
1018 
1019 #define NV_WRITE_CTX(reg, val) do { \
1020 	int offset = nv10_gr_ctx_regs_find_offset(gr, reg); \
1021 	if (offset > 0) \
1022 		chan->nv10[offset] = val; \
1023 	} while (0)
1024 
1025 #define NV17_WRITE_CTX(reg, val) do { \
1026 	int offset = nv17_gr_ctx_regs_find_offset(gr, reg); \
1027 	if (offset > 0) \
1028 		chan->nv17[offset] = val; \
1029 	} while (0)
1030 
1031 static int
1032 nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
1033 		     struct nvkm_oclass *oclass, void *data, u32 size,
1034 		     struct nvkm_object **pobject)
1035 {
1036 	struct nvkm_fifo_chan *fifo = (void *)parent;
1037 	struct nv10_gr *gr = (void *)engine;
1038 	struct nv10_gr_chan *chan;
1039 	struct nvkm_device *device = gr->base.engine.subdev.device;
1040 	unsigned long flags;
1041 	int ret;
1042 
1043 	ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
1044 	*pobject = nv_object(chan);
1045 	if (ret)
1046 		return ret;
1047 
1048 	spin_lock_irqsave(&gr->lock, flags);
1049 	if (gr->chan[fifo->chid]) {
1050 		*pobject = nv_object(gr->chan[fifo->chid]);
1051 		atomic_inc(&(*pobject)->refcount);
1052 		spin_unlock_irqrestore(&gr->lock, flags);
1053 		nvkm_object_destroy(&chan->base);
1054 		return 1;
1055 	}
1056 
1057 	NV_WRITE_CTX(0x00400e88, 0x08000000);
1058 	NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
1059 	NV_WRITE_CTX(NV03_PGRAPH_XY_LOGIC_MISC0, 0x0001ffff);
1060 	NV_WRITE_CTX(0x00400e10, 0x00001000);
1061 	NV_WRITE_CTX(0x00400e14, 0x00001000);
1062 	NV_WRITE_CTX(0x00400e30, 0x00080008);
1063 	NV_WRITE_CTX(0x00400e34, 0x00080008);
1064 	if (nv_device(gr)->card_type >= NV_11 &&
1065 	    nv_device(gr)->chipset >= 0x17) {
1066 		/* is it really needed ??? */
1067 		NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
1068 					nvkm_rd32(device, NV10_PGRAPH_DEBUG_4));
1069 		NV17_WRITE_CTX(0x004006b0, nvkm_rd32(device, 0x004006b0));
1070 		NV17_WRITE_CTX(0x00400eac, 0x0fff0000);
1071 		NV17_WRITE_CTX(0x00400eb0, 0x0fff0000);
1072 		NV17_WRITE_CTX(0x00400ec0, 0x00000080);
1073 		NV17_WRITE_CTX(0x00400ed0, 0x00000080);
1074 	}
1075 	NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24);
1076 
1077 	nv10_gr_create_pipe(chan);
1078 
1079 	gr->chan[fifo->chid] = chan;
1080 	chan->chid = fifo->chid;
1081 	spin_unlock_irqrestore(&gr->lock, flags);
1082 	return 0;
1083 }
1084 
1085 static void
1086 nv10_gr_context_dtor(struct nvkm_object *object)
1087 {
1088 	struct nv10_gr *gr = (void *)object->engine;
1089 	struct nv10_gr_chan *chan = (void *)object;
1090 	unsigned long flags;
1091 
1092 	spin_lock_irqsave(&gr->lock, flags);
1093 	gr->chan[chan->chid] = NULL;
1094 	spin_unlock_irqrestore(&gr->lock, flags);
1095 
1096 	nvkm_object_destroy(&chan->base);
1097 }
1098 
1099 static int
1100 nv10_gr_context_fini(struct nvkm_object *object, bool suspend)
1101 {
1102 	struct nv10_gr *gr = (void *)object->engine;
1103 	struct nv10_gr_chan *chan = (void *)object;
1104 	struct nvkm_device *device = gr->base.engine.subdev.device;
1105 	unsigned long flags;
1106 
1107 	spin_lock_irqsave(&gr->lock, flags);
1108 	nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
1109 	if (nv10_gr_channel(gr) == chan)
1110 		nv10_gr_unload_context(chan);
1111 	nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
1112 	spin_unlock_irqrestore(&gr->lock, flags);
1113 
1114 	return _nvkm_object_fini(&chan->base, suspend);
1115 }
1116 
1117 static struct nvkm_oclass
1118 nv10_gr_cclass = {
1119 	.handle = NV_ENGCTX(GR, 0x10),
1120 	.ofuncs = &(struct nvkm_ofuncs) {
1121 		.ctor = nv10_gr_context_ctor,
1122 		.dtor = nv10_gr_context_dtor,
1123 		.init = _nvkm_object_init,
1124 		.fini = nv10_gr_context_fini,
1125 	},
1126 };
1127 
1128 /*******************************************************************************
1129  * PGRAPH engine/subdev functions
1130  ******************************************************************************/
1131 
1132 static void
1133 nv10_gr_tile_prog(struct nvkm_engine *engine, int i)
1134 {
1135 	struct nv10_gr *gr = (void *)engine;
1136 	struct nvkm_device *device = gr->base.engine.subdev.device;
1137 	struct nvkm_fifo *fifo = device->fifo;
1138 	struct nvkm_fb_tile *tile = &device->fb->tile.region[i];
1139 	unsigned long flags;
1140 
1141 	fifo->pause(fifo, &flags);
1142 	nv04_gr_idle(gr);
1143 
1144 	nvkm_wr32(device, NV10_PGRAPH_TLIMIT(i), tile->limit);
1145 	nvkm_wr32(device, NV10_PGRAPH_TSIZE(i), tile->pitch);
1146 	nvkm_wr32(device, NV10_PGRAPH_TILE(i), tile->addr);
1147 
1148 	fifo->start(fifo, &flags);
1149 }
1150 
1151 const struct nvkm_bitfield nv10_gr_intr_name[] = {
1152 	{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
1153 	{ NV_PGRAPH_INTR_ERROR,  "ERROR"  },
1154 	{}
1155 };
1156 
1157 const struct nvkm_bitfield nv10_gr_nstatus[] = {
1158 	{ NV10_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
1159 	{ NV10_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
1160 	{ NV10_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
1161 	{ NV10_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
1162 	{}
1163 };
1164 
1165 static void
1166 nv10_gr_intr(struct nvkm_subdev *subdev)
1167 {
1168 	struct nv10_gr *gr = (void *)subdev;
1169 	struct nv10_gr_chan *chan = NULL;
1170 	struct nvkm_namedb *namedb = NULL;
1171 	struct nvkm_handle *handle = NULL;
1172 	struct nvkm_device *device = gr->base.engine.subdev.device;
1173 	u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR);
1174 	u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE);
1175 	u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS);
1176 	u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR);
1177 	u32 chid = (addr & 0x01f00000) >> 20;
1178 	u32 subc = (addr & 0x00070000) >> 16;
1179 	u32 mthd = (addr & 0x00001ffc);
1180 	u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA);
1181 	u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff;
1182 	u32 show = stat;
1183 	char msg[128], src[128], sta[128];
1184 	unsigned long flags;
1185 
1186 	spin_lock_irqsave(&gr->lock, flags);
1187 	chan = gr->chan[chid];
1188 	if (chan)
1189 		namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
1190 	spin_unlock_irqrestore(&gr->lock, flags);
1191 
1192 	if (stat & NV_PGRAPH_INTR_ERROR) {
1193 		if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
1194 			handle = nvkm_namedb_get_class(namedb, class);
1195 			if (handle && !nv_call(handle->object, mthd, data))
1196 				show &= ~NV_PGRAPH_INTR_ERROR;
1197 		}
1198 	}
1199 
1200 	if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
1201 		nvkm_wr32(device, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
1202 		stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
1203 		show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
1204 		nv10_gr_context_switch(gr);
1205 	}
1206 
1207 	nvkm_wr32(device, NV03_PGRAPH_INTR, stat);
1208 	nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001);
1209 
1210 	if (show) {
1211 		nvkm_snprintbf(msg, sizeof(msg), nv10_gr_intr_name, show);
1212 		nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource);
1213 		nvkm_snprintbf(sta, sizeof(sta), nv10_gr_nstatus, nstatus);
1214 		nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] "
1215 				   "nstatus %08x [%s] ch %d [%s] subc %d "
1216 				   "class %04x mthd %04x data %08x\n",
1217 			   show, msg, nsource, src, nstatus, sta, chid,
1218 			   nvkm_client_name(chan), subc, class, mthd, data);
1219 	}
1220 
1221 	nvkm_namedb_put(handle);
1222 }
1223 
1224 static int
1225 nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
1226 	     struct nvkm_oclass *oclass, void *data, u32 size,
1227 	     struct nvkm_object **pobject)
1228 {
1229 	struct nv10_gr *gr;
1230 	int ret;
1231 
1232 	ret = nvkm_gr_create(parent, engine, oclass, true, &gr);
1233 	*pobject = nv_object(gr);
1234 	if (ret)
1235 		return ret;
1236 
1237 	nv_subdev(gr)->unit = 0x00001000;
1238 	nv_subdev(gr)->intr = nv10_gr_intr;
1239 	nv_engine(gr)->cclass = &nv10_gr_cclass;
1240 
1241 	if (nv_device(gr)->chipset <= 0x10)
1242 		nv_engine(gr)->sclass = nv10_gr_sclass;
1243 	else
1244 	if (nv_device(gr)->chipset <  0x17 ||
1245 	    nv_device(gr)->card_type < NV_11)
1246 		nv_engine(gr)->sclass = nv15_gr_sclass;
1247 	else
1248 		nv_engine(gr)->sclass = nv17_gr_sclass;
1249 
1250 	nv_engine(gr)->tile_prog = nv10_gr_tile_prog;
1251 	spin_lock_init(&gr->lock);
1252 	return 0;
1253 }
1254 
1255 static void
1256 nv10_gr_dtor(struct nvkm_object *object)
1257 {
1258 	struct nv10_gr *gr = (void *)object;
1259 	nvkm_gr_destroy(&gr->base);
1260 }
1261 
1262 static int
1263 nv10_gr_init(struct nvkm_object *object)
1264 {
1265 	struct nvkm_engine *engine = nv_engine(object);
1266 	struct nv10_gr *gr = (void *)engine;
1267 	struct nvkm_device *device = gr->base.engine.subdev.device;
1268 	struct nvkm_fb *fb = device->fb;
1269 	int ret, i;
1270 
1271 	ret = nvkm_gr_init(&gr->base);
1272 	if (ret)
1273 		return ret;
1274 
1275 	nvkm_wr32(device, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
1276 	nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
1277 
1278 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
1279 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000);
1280 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x00118700);
1281 	/* nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
1282 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
1283 	nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
1284 
1285 	if (nv_device(gr)->card_type >= NV_11 &&
1286 	    nv_device(gr)->chipset >= 0x17) {
1287 		nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x1f000000);
1288 		nvkm_wr32(device, 0x400a10, 0x03ff3fb6);
1289 		nvkm_wr32(device, 0x400838, 0x002f8684);
1290 		nvkm_wr32(device, 0x40083c, 0x00115f3f);
1291 		nvkm_wr32(device, 0x4006b0, 0x40000020);
1292 	} else {
1293 		nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000);
1294 	}
1295 
1296 	/* Turn all the tiling regions off. */
1297 	for (i = 0; i < fb->tile.regions; i++)
1298 		engine->tile_prog(engine, i);
1299 
1300 	nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
1301 	nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
1302 	nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
1303 	nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
1304 	nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
1305 	nvkm_wr32(device, NV10_PGRAPH_STATE, 0xFFFFFFFF);
1306 
1307 	nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
1308 	nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
1309 	nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
1310 	return 0;
1311 }
1312 
1313 static int
1314 nv10_gr_fini(struct nvkm_object *object, bool suspend)
1315 {
1316 	struct nv10_gr *gr = (void *)object;
1317 	return nvkm_gr_fini(&gr->base, suspend);
1318 }
1319 
1320 struct nvkm_oclass
1321 nv10_gr_oclass = {
1322 	.handle = NV_ENGINE(GR, 0x10),
1323 	.ofuncs = &(struct nvkm_ofuncs) {
1324 		.ctor = nv10_gr_ctor,
1325 		.dtor = nv10_gr_dtor,
1326 		.init = nv10_gr_init,
1327 		.fini = nv10_gr_fini,
1328 	},
1329 };
1330