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