1/*
2 * Copyright 2007 Ben Skeggs
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23#include "nv_include.h"
24
25#include "hwdefs/nv_object.xml.h"
26#include "hwdefs/nv_m2mf.xml.h"
27#include "hwdefs/nv01_2d.xml.h"
28#include "hwdefs/nv50_2d.xml.h"
29#include "nv04_accel.h"
30
31Bool
32nouveau_allocate_surface(ScrnInfoPtr scrn, int width, int height, int bpp,
33			 int usage_hint, int *pitch, struct nouveau_bo **bo)
34{
35	NVPtr pNv = NVPTR(scrn);
36	Bool scanout = (usage_hint & NOUVEAU_CREATE_PIXMAP_SCANOUT);
37	Bool tiled = (usage_hint & NOUVEAU_CREATE_PIXMAP_TILED);
38	Bool shared = FALSE;
39	union nouveau_bo_config cfg = {};
40	int flags = NOUVEAU_BO_MAP | (bpp >= 8 ? NOUVEAU_BO_VRAM : 0);
41	int cpp = bpp / 8, ret;
42
43#ifdef NOUVEAU_PIXMAP_SHARING
44	shared = ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED);
45#endif
46
47	flags = NOUVEAU_BO_MAP;
48	if (bpp >= 8)
49		flags |= shared ? NOUVEAU_BO_GART : NOUVEAU_BO_VRAM;
50
51	if (scanout && pNv->tiled_scanout)
52		tiled = TRUE;
53
54	if (pNv->Architecture >= NV_TESLA) {
55		if (!scanout && bpp >= 8 && !shared)
56			tiled = TRUE;
57
58		*pitch = NOUVEAU_ALIGN(width * cpp, !tiled ? 256 : 64);
59	} else {
60		*pitch = NOUVEAU_ALIGN(width * cpp, 64);
61	}
62
63	if (tiled) {
64		if (pNv->Architecture >= NV_FERMI) {
65			if      (height > 64) cfg.nvc0.tile_mode = 0x040;
66			else if (height > 32) cfg.nvc0.tile_mode = 0x030;
67			else if (height > 16) cfg.nvc0.tile_mode = 0x020;
68			else if (height >  8) cfg.nvc0.tile_mode = 0x010;
69			else                  cfg.nvc0.tile_mode = 0x000;
70
71			if (usage_hint & NOUVEAU_CREATE_PIXMAP_ZETA)
72				cfg.nvc0.memtype = (bpp == 16) ? 0x01 : 0x11;
73			else
74				cfg.nvc0.memtype = 0xfe;
75
76			height = NOUVEAU_ALIGN(height,
77				 NVC0_TILE_HEIGHT(cfg.nvc0.tile_mode));
78		} else if (pNv->Architecture >= NV_TESLA) {
79			if      (height > 32) cfg.nv50.tile_mode = 0x040;
80			else if (height > 16) cfg.nv50.tile_mode = 0x030;
81			else if (height >  8) cfg.nv50.tile_mode = 0x020;
82			else if (height >  4) cfg.nv50.tile_mode = 0x010;
83			else                  cfg.nv50.tile_mode = 0x000;
84
85			if (usage_hint & NOUVEAU_CREATE_PIXMAP_ZETA)
86				cfg.nv50.memtype = (bpp == 16) ? 0x16c : 0x128;
87			else if (usage_hint & NOUVEAU_CREATE_PIXMAP_SCANOUT)
88				cfg.nv50.memtype = (bpp == 16) ? 0x070 : 0x07a;
89			else
90				cfg.nv50.memtype = 0x070;
91
92			height = NOUVEAU_ALIGN(height,
93				 NV50_TILE_HEIGHT(cfg.nv50.tile_mode));
94		} else {
95			int pitch_align = max(
96				pNv->dev->chipset >= 0x40 ? 1024 : 256,
97				round_down_pow2(*pitch / 4));
98
99			*pitch = NOUVEAU_ALIGN(*pitch, pitch_align);
100			cfg.nv04.surf_pitch = *pitch;
101		}
102	}
103
104	if (pNv->Architecture < NV_TESLA) {
105		if (bpp == 16)
106			cfg.nv04.surf_flags |= NV04_BO_16BPP;
107		if (bpp == 32)
108			cfg.nv04.surf_flags |= NV04_BO_32BPP;
109		if (usage_hint & NOUVEAU_CREATE_PIXMAP_ZETA)
110			cfg.nv04.surf_flags |= NV04_BO_ZETA;
111	}
112
113	if (usage_hint & NOUVEAU_CREATE_PIXMAP_SCANOUT)
114		flags |= NOUVEAU_BO_CONTIG;
115
116	ret = nouveau_bo_new(pNv->dev, flags, 0, *pitch * height, &cfg, bo);
117	if (ret) {
118		ErrorF("failure to allocate surface %dx%d@%d (pitch %d): %d\n", width, height, bpp, *pitch, ret);
119		return FALSE;
120	}
121
122	return TRUE;
123}
124
125void
126NV11SyncToVBlank(PixmapPtr ppix, BoxPtr box)
127{
128	ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
129	NVPtr pNv = NVPTR(pScrn);
130	struct nouveau_pushbuf *push = pNv->pushbuf;
131	int head;
132	xf86CrtcPtr crtc;
133
134	if (!nouveau_exa_pixmap_is_onscreen(ppix))
135		return;
136
137	crtc = nouveau_pick_best_crtc(pScrn, box->x1, box->y1,
138				      box->x2 - box->x1,
139				      box->y2 - box->y1);
140	if (!crtc)
141		return;
142
143	if (!PUSH_SPACE(push, 8))
144		return;
145
146	head = drmmode_head(crtc);
147
148	BEGIN_NV04(push, NV15_BLIT(FLIP_INCR_WRITE), 1);
149	PUSH_DATA (push, 0);
150	BEGIN_NV04(push, NV15_BLIT(FLIP_CRTC_INCR_READ), 1);
151	PUSH_DATA (push, head);
152	BEGIN_NV04(push, SUBC_BLIT(0x00000100), 1);
153	PUSH_DATA (push, 0);
154	BEGIN_NV04(push, NV15_BLIT(FLIP_WAIT), 1);
155	PUSH_DATA (push, 0);
156}
157
158static Bool
159NVAccelInitDmaNotifier0(ScrnInfoPtr pScrn)
160{
161	NVPtr pNv = NVPTR(pScrn);
162	struct nouveau_object *chan = pNv->channel;
163	struct nv04_notify ntfy = { .length = 32 };
164
165	if (nouveau_object_new(chan, NvDmaNotifier0, NOUVEAU_NOTIFIER_CLASS,
166			       &ntfy, sizeof(ntfy), &pNv->notify0))
167		return FALSE;
168
169	return TRUE;
170}
171
172static Bool
173NVAccelInitNull(ScrnInfoPtr pScrn)
174{
175	NVPtr pNv = NVPTR(pScrn);
176
177	if (nouveau_object_new(pNv->channel, NvNullObject, NV01_NULL_CLASS,
178			       NULL, 0, &pNv->NvNull))
179		return FALSE;
180
181	return TRUE;
182}
183
184static Bool
185NVAccelInitContextSurfaces(ScrnInfoPtr pScrn)
186{
187	NVPtr pNv = NVPTR(pScrn);
188	struct nouveau_pushbuf *push = pNv->pushbuf;
189	struct nv04_fifo *fifo = pNv->channel->data;
190	uint32_t class;
191
192	class = (pNv->Architecture >= NV_ARCH_10) ? NV10_SURFACE_2D_CLASS :
193						    NV04_SURFACE_2D_CLASS;
194
195	if (nouveau_object_new(pNv->channel, NvContextSurfaces, class,
196			       NULL, 0, &pNv->NvContextSurfaces))
197		return FALSE;
198
199	if (!PUSH_SPACE(push, 8))
200		return FALSE;
201
202	BEGIN_NV04(push, NV01_SUBC(SF2D, OBJECT), 1);
203	PUSH_DATA (push, pNv->NvContextSurfaces->handle);
204	BEGIN_NV04(push, NV04_SF2D(DMA_NOTIFY), 1);
205	PUSH_DATA (push, pNv->NvNull->handle);
206	BEGIN_NV04(push, NV04_SF2D(DMA_IMAGE_SOURCE), 2);
207	PUSH_DATA (push, fifo->vram);
208	PUSH_DATA (push, fifo->vram);
209	return TRUE;
210}
211
212static Bool
213NVAccelInitContextBeta1(ScrnInfoPtr pScrn)
214{
215	NVPtr pNv = NVPTR(pScrn);
216	struct nouveau_pushbuf *push = pNv->pushbuf;
217
218	if (nouveau_object_new(pNv->channel, NvContextBeta1, NV01_BETA_CLASS,
219			       NULL, 0, &pNv->NvContextBeta1))
220		return FALSE;
221
222	if (!PUSH_SPACE(push, 4))
223		return FALSE;
224
225	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
226	PUSH_DATA (push, pNv->NvContextBeta1->handle);
227	BEGIN_NV04(push, NV01_BETA(BETA_1D31), 1); /*alpha factor*/
228	PUSH_DATA (push, 0xff << 23);
229	return TRUE;
230}
231
232
233static Bool
234NVAccelInitContextBeta4(ScrnInfoPtr pScrn)
235{
236	NVPtr pNv = NVPTR(pScrn);
237	struct nouveau_pushbuf *push = pNv->pushbuf;
238
239	if (nouveau_object_new(pNv->channel, NvContextBeta4, NV04_BETA4_CLASS,
240			       NULL, 0, &pNv->NvContextBeta4))
241		return FALSE;
242
243	if (!PUSH_SPACE(push, 4))
244		return FALSE;
245
246	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
247	PUSH_DATA (push, pNv->NvContextBeta4->handle);
248	BEGIN_NV04(push, NV04_BETA4(BETA_FACTOR), 1); /*RGBA factor*/
249	PUSH_DATA (push, 0xffff0000);
250	return TRUE;
251}
252
253Bool
254NVAccelGetCtxSurf2DFormatFromPixmap(PixmapPtr pPix, int *fmt_ret)
255{
256	switch (pPix->drawable.bitsPerPixel) {
257	case 32:
258		*fmt_ret = NV04_SURFACE_2D_FORMAT_A8R8G8B8;
259		break;
260	case 24:
261		*fmt_ret = NV04_SURFACE_2D_FORMAT_X8R8G8B8_Z8R8G8B8;
262		break;
263	case 16:
264		if (pPix->drawable.depth == 16)
265			*fmt_ret = NV04_SURFACE_2D_FORMAT_R5G6B5;
266		else
267			*fmt_ret = NV04_SURFACE_2D_FORMAT_X1R5G5B5_Z1R5G5B5;
268		break;
269	case 8:
270		*fmt_ret = NV04_SURFACE_2D_FORMAT_Y8;
271		break;
272	default:
273		return FALSE;
274	}
275
276	return TRUE;
277}
278
279Bool
280NVAccelGetCtxSurf2DFormatFromPicture(PicturePtr pPict, int *fmt_ret)
281{
282	switch (pPict->format) {
283	case PICT_a8r8g8b8:
284		*fmt_ret = NV04_SURFACE_2D_FORMAT_A8R8G8B8;
285		break;
286	case PICT_x8r8g8b8:
287		*fmt_ret = NV04_SURFACE_2D_FORMAT_X8R8G8B8_Z8R8G8B8;
288		break;
289	case PICT_r5g6b5:
290		*fmt_ret = NV04_SURFACE_2D_FORMAT_R5G6B5;
291		break;
292	case PICT_a8:
293		*fmt_ret = NV04_SURFACE_2D_FORMAT_Y8;
294		break;
295	default:
296		return FALSE;
297	}
298
299	return TRUE;
300}
301
302/* A copy of exaGetOffscreenPixmap(), since it's private. */
303PixmapPtr
304NVGetDrawablePixmap(DrawablePtr pDraw)
305{
306	if (pDraw->type == DRAWABLE_WINDOW)
307		return pDraw->pScreen->GetWindowPixmap ((WindowPtr) pDraw);
308	else
309		return (PixmapPtr) pDraw;
310}
311
312static Bool
313NVAccelInitImagePattern(ScrnInfoPtr pScrn)
314{
315	NVPtr pNv = NVPTR(pScrn);
316	struct nouveau_pushbuf *push = pNv->pushbuf;
317
318	if (nouveau_object_new(pNv->channel, NvImagePattern, NV04_PATTERN_CLASS,
319			       NULL, 0, &pNv->NvImagePattern))
320		return FALSE;
321
322	if (!PUSH_SPACE(push, 8))
323		return FALSE;
324
325	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
326	PUSH_DATA (push, pNv->NvImagePattern->handle);
327	BEGIN_NV04(push, NV01_PATT(DMA_NOTIFY), 1);
328	PUSH_DATA (push, pNv->NvNull->handle);
329	BEGIN_NV04(push, NV01_PATT(MONOCHROME_FORMAT), 3);
330#if X_BYTE_ORDER == X_BIG_ENDIAN
331	PUSH_DATA (push, NV01_PATTERN_MONOCHROME_FORMAT_LE);
332#else
333	PUSH_DATA (push, NV01_PATTERN_MONOCHROME_FORMAT_CGA6);
334#endif
335	PUSH_DATA (push, NV01_PATTERN_MONOCHROME_SHAPE_8X8);
336	PUSH_DATA (push, NV04_PATTERN_PATTERN_SELECT_MONO);
337
338	return TRUE;
339}
340
341static Bool
342NVAccelInitRasterOp(ScrnInfoPtr pScrn)
343{
344	NVPtr pNv = NVPTR(pScrn);
345	struct nouveau_pushbuf *push = pNv->pushbuf;
346
347	if (nouveau_object_new(pNv->channel, NvRop, NV03_ROP_CLASS,
348			       NULL, 0, &pNv->NvRop))
349		return FALSE;
350
351	if (!PUSH_SPACE(push, 4))
352		return FALSE;
353
354	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
355	PUSH_DATA (push, pNv->NvRop->handle);
356	BEGIN_NV04(push, NV01_ROP(DMA_NOTIFY), 1);
357	PUSH_DATA (push, pNv->NvNull->handle);
358
359	pNv->currentRop = ~0;
360	return TRUE;
361}
362
363static Bool
364NVAccelInitRectangle(ScrnInfoPtr pScrn)
365{
366	NVPtr pNv = NVPTR(pScrn);
367	struct nouveau_pushbuf *push = pNv->pushbuf;
368
369	if (nouveau_object_new(pNv->channel, NvRectangle, NV04_GDI_CLASS,
370			       NULL, 0, &pNv->NvRectangle))
371		return FALSE;
372
373	if (!PUSH_SPACE(push, 16))
374		return FALSE;
375
376	BEGIN_NV04(push, NV01_SUBC(RECT, OBJECT), 1);
377	PUSH_DATA (push, pNv->NvRectangle->handle);
378	BEGIN_NV04(push, NV04_RECT(DMA_NOTIFY), 1);
379	PUSH_DATA (push, pNv->notify0->handle);
380	BEGIN_NV04(push, NV04_RECT(DMA_FONTS), 1);
381	PUSH_DATA (push, pNv->NvNull->handle);
382	BEGIN_NV04(push, NV04_RECT(SURFACE), 1);
383	PUSH_DATA (push, pNv->NvContextSurfaces->handle);
384	BEGIN_NV04(push, NV04_RECT(ROP), 1);
385	PUSH_DATA (push, pNv->NvRop->handle);
386	BEGIN_NV04(push, NV04_RECT(PATTERN), 1);
387	PUSH_DATA (push, pNv->NvImagePattern->handle);
388	BEGIN_NV04(push, NV04_RECT(OPERATION), 1);
389	PUSH_DATA (push, NV04_GDI_OPERATION_ROP_AND);
390	BEGIN_NV04(push, NV04_RECT(MONOCHROME_FORMAT), 1);
391	/* XXX why putting 1 like renouveau dump, swap the text */
392#if 1 || X_BYTE_ORDER == X_BIG_ENDIAN
393	PUSH_DATA (push, NV04_GDI_MONOCHROME_FORMAT_LE);
394#else
395	PUSH_DATA (push, NV04_GDI_MONOCHROME_FORMAT_CGA6);
396#endif
397
398	return TRUE;
399}
400
401static Bool
402NVAccelInitImageBlit(ScrnInfoPtr pScrn)
403{
404	NVPtr pNv = NVPTR(pScrn);
405	struct nouveau_pushbuf *push = pNv->pushbuf;
406	uint32_t class;
407
408	class = (pNv->dev->chipset >= 0x11) ? NV15_BLIT_CLASS : NV04_BLIT_CLASS;
409
410	if (nouveau_object_new(pNv->channel, NvImageBlit, class,
411			       NULL, 0, &pNv->NvImageBlit))
412		return FALSE;
413
414	if (!PUSH_SPACE(push, 16))
415		return FALSE;
416
417	BEGIN_NV04(push, NV01_SUBC(BLIT, OBJECT), 1);
418	PUSH_DATA (push, pNv->NvImageBlit->handle);
419	BEGIN_NV04(push, NV01_BLIT(DMA_NOTIFY), 1);
420	PUSH_DATA (push, pNv->notify0->handle);
421	BEGIN_NV04(push, NV01_BLIT(COLOR_KEY), 1);
422	PUSH_DATA (push, pNv->NvNull->handle);
423	BEGIN_NV04(push, NV04_BLIT(SURFACES), 1);
424	PUSH_DATA (push, pNv->NvContextSurfaces->handle);
425	BEGIN_NV04(push, NV01_BLIT(CLIP), 3);
426	PUSH_DATA (push, pNv->NvNull->handle);
427	PUSH_DATA (push, pNv->NvImagePattern->handle);
428	PUSH_DATA (push, pNv->NvRop->handle);
429	BEGIN_NV04(push, NV01_BLIT(OPERATION), 1);
430	PUSH_DATA (push, NV01_BLIT_OPERATION_ROP_AND);
431	if (pNv->NvImageBlit->oclass == NV15_BLIT_CLASS) {
432		BEGIN_NV04(push, NV15_BLIT(FLIP_SET_READ), 3);
433		PUSH_DATA (push, 0);
434		PUSH_DATA (push, 1);
435		PUSH_DATA (push, 2);
436	}
437
438	return TRUE;
439}
440
441static Bool
442NVAccelInitScaledImage(ScrnInfoPtr pScrn)
443{
444	NVPtr pNv = NVPTR(pScrn);
445	struct nouveau_pushbuf *push = pNv->pushbuf;
446	struct nv04_fifo *fifo = pNv->channel->data;
447	uint32_t class;
448
449	switch (pNv->Architecture) {
450	case NV_ARCH_04:
451		class = NV04_SIFM_CLASS;
452		break;
453	case NV_ARCH_10:
454	case NV_ARCH_20:
455	case NV_ARCH_30:
456		class = NV10_SIFM_CLASS;
457		break;
458	case NV_ARCH_40:
459	default:
460		class = NV40_SIFM_CLASS;
461		break;
462	}
463
464	if (nouveau_object_new(pNv->channel, NvScaledImage, class,
465			       NULL, 0, &pNv->NvScaledImage))
466		return FALSE;
467
468	if (!PUSH_SPACE(push, 16))
469		return FALSE;
470
471	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
472	PUSH_DATA (push, pNv->NvScaledImage->handle);
473	BEGIN_NV04(push, NV03_SIFM(DMA_NOTIFY), 7);
474	PUSH_DATA (push, pNv->notify0->handle);
475	PUSH_DATA (push, fifo->vram);
476	PUSH_DATA (push, pNv->NvNull->handle);
477	PUSH_DATA (push, pNv->NvNull->handle);
478	PUSH_DATA (push, pNv->NvContextBeta1->handle);
479	PUSH_DATA (push, pNv->NvContextBeta4->handle);
480	PUSH_DATA (push, pNv->NvContextSurfaces->handle);
481	if (pNv->Architecture>=NV_ARCH_10) {
482		BEGIN_NV04(push, NV05_SIFM(COLOR_CONVERSION), 1);
483		PUSH_DATA (push, NV05_SIFM_COLOR_CONVERSION_DITHER);
484	}
485	BEGIN_NV04(push, NV03_SIFM(OPERATION), 1);
486	PUSH_DATA (push, NV03_SIFM_OPERATION_SRCCOPY);
487
488	return TRUE;
489}
490
491static Bool
492NVAccelInitClipRectangle(ScrnInfoPtr pScrn)
493{
494	NVPtr pNv = NVPTR(pScrn);
495	struct nouveau_pushbuf *push = pNv->pushbuf;
496
497	if (nouveau_object_new(pNv->channel, NvClipRectangle, NV01_CLIP_CLASS,
498			       NULL, 0, &pNv->NvClipRectangle))
499		return FALSE;
500
501	if (!PUSH_SPACE(push, 4))
502		return FALSE;
503
504	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
505	PUSH_DATA (push, pNv->NvClipRectangle->handle);
506	BEGIN_NV04(push, NV01_CLIP(DMA_NOTIFY), 1);
507	PUSH_DATA (push, pNv->NvNull->handle);
508	return TRUE;
509}
510
511static Bool
512NVAccelInitMemFormat(ScrnInfoPtr pScrn)
513{
514	NVPtr pNv = NVPTR(pScrn);
515	struct nouveau_pushbuf *push = pNv->pushbuf;
516
517	if (nouveau_object_new(pNv->channel, NvMemFormat, NV03_M2MF_CLASS,
518			       NULL, 0, &pNv->NvMemFormat))
519		return FALSE;
520
521	if (!PUSH_SPACE(push, 4))
522		return FALSE;
523
524	BEGIN_NV04(push, NV01_SUBC(M2MF, OBJECT), 1);
525	PUSH_DATA (push, pNv->NvMemFormat->handle);
526	BEGIN_NV04(push, NV03_M2MF(DMA_NOTIFY), 1);
527	PUSH_DATA (push, pNv->notify0->handle);
528	return TRUE;
529}
530
531static Bool
532NVAccelInitImageFromCpu(ScrnInfoPtr pScrn)
533{
534	NVPtr pNv = NVPTR(pScrn);
535	struct nouveau_pushbuf *push = pNv->pushbuf;
536	uint32_t class;
537
538	switch (pNv->Architecture) {
539	case NV_ARCH_04:
540		class = NV04_IFC_CLASS;
541		break;
542	case NV_ARCH_10:
543	case NV_ARCH_20:
544	case NV_ARCH_30:
545	case NV_ARCH_40:
546	default:
547		class = NV10_IFC_CLASS;
548		break;
549	}
550
551	if (nouveau_object_new(pNv->channel, NvImageFromCpu, class,
552			       NULL, 0, &pNv->NvImageFromCpu))
553		return FALSE;
554
555	if (!PUSH_SPACE(push, 16))
556		return FALSE;
557
558	BEGIN_NV04(push, NV01_SUBC(IFC, OBJECT), 1);
559	PUSH_DATA (push, pNv->NvImageFromCpu->handle);
560	BEGIN_NV04(push, NV01_IFC(DMA_NOTIFY), 1);
561	PUSH_DATA (push, pNv->notify0->handle);
562	BEGIN_NV04(push, NV01_IFC(CLIP), 1);
563	PUSH_DATA (push, pNv->NvNull->handle);
564	BEGIN_NV04(push, NV01_IFC(PATTERN), 1);
565	PUSH_DATA (push, pNv->NvNull->handle);
566	BEGIN_NV04(push, NV01_IFC(ROP), 1);
567	PUSH_DATA (push, pNv->NvNull->handle);
568	if (pNv->Architecture >= NV_ARCH_10) {
569		BEGIN_NV04(push, NV01_IFC(BETA), 1);
570		PUSH_DATA (push, pNv->NvNull->handle);
571		BEGIN_NV04(push, NV04_IFC(BETA4), 1);
572		PUSH_DATA (push, pNv->NvNull->handle);
573	}
574	BEGIN_NV04(push, NV04_IFC(SURFACE), 1);
575	PUSH_DATA (push, pNv->NvContextSurfaces->handle);
576	BEGIN_NV04(push, NV01_IFC(OPERATION), 1);
577	PUSH_DATA (push, NV01_IFC_OPERATION_SRCCOPY);
578	return TRUE;
579}
580
581#define INIT_CONTEXT_OBJECT(name) do {                                        \
582	ret = NVAccelInit##name(pScrn);                                       \
583	if (!ret) {                                                           \
584		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,                         \
585			   "Failed to initialise context object: "#name       \
586			   " (%d)\n", ret);                                   \
587		return FALSE;                                                 \
588	}                                                                     \
589} while(0)
590
591void
592NVAccelCommonFini(ScrnInfoPtr pScrn)
593{
594	NVPtr pNv = NVPTR(pScrn);
595
596	nouveau_object_del(&pNv->notify0);
597	nouveau_object_del(&pNv->vblank_sem);
598
599	nouveau_object_del(&pNv->NvContextSurfaces);
600	nouveau_object_del(&pNv->NvContextBeta1);
601	nouveau_object_del(&pNv->NvContextBeta4);
602	nouveau_object_del(&pNv->NvImagePattern);
603	nouveau_object_del(&pNv->NvRop);
604	nouveau_object_del(&pNv->NvRectangle);
605	nouveau_object_del(&pNv->NvImageBlit);
606	nouveau_object_del(&pNv->NvScaledImage);
607	nouveau_object_del(&pNv->NvClipRectangle);
608	nouveau_object_del(&pNv->NvImageFromCpu);
609	nouveau_object_del(&pNv->Nv2D);
610	nouveau_object_del(&pNv->NvMemFormat);
611	nouveau_object_del(&pNv->NvSW);
612	nouveau_object_del(&pNv->Nv3D);
613	nouveau_object_del(&pNv->NvCOPY);
614
615	nouveau_bo_ref(NULL, &pNv->scratch);
616
617	nouveau_bufctx_del(&pNv->bufctx);
618	nouveau_pushbuf_del(&pNv->pushbuf);
619	nouveau_object_del(&pNv->channel);
620}
621
622Bool
623NVAccelCommonInit(ScrnInfoPtr pScrn)
624{
625	NVPtr pNv = NVPTR(pScrn);
626	struct nv04_fifo nv04_data = { .vram = NvDmaFB,
627				       .gart = NvDmaTT };
628	struct nvc0_fifo nvc0_data = { };
629	struct nouveau_object *device = &pNv->dev->object;
630	int size, ret;
631	void *data;
632
633	if (pNv->dev->drm_version < 0x01000000 && pNv->dev->chipset >= 0xc0) {
634		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
635			   "Fermi acceleration not supported on old kernel\n");
636		return FALSE;
637	}
638
639	if (pNv->Architecture < NV_FERMI) {
640		data = &nv04_data;
641		size = sizeof(nv04_data);
642	} else {
643		data = &nvc0_data;
644		size = sizeof(nvc0_data);
645	}
646
647	ret = nouveau_object_new(device, 0, NOUVEAU_FIFO_CHANNEL_CLASS,
648				 data, size, &pNv->channel);
649	if (ret) {
650		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
651			   "Error creating GPU channel: %d\n", ret);
652		return FALSE;
653	}
654
655	ret = nouveau_pushbuf_new(pNv->client, pNv->channel, 4, 32 * 1024,
656				  true, &pNv->pushbuf);
657	if (ret) {
658		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
659			   "Error allocating DMA push buffer: %d\n",ret);
660		NVAccelCommonFini(pScrn);
661		return FALSE;
662	}
663
664	ret = nouveau_bufctx_new(pNv->client, 1, &pNv->bufctx);
665	if (ret) {
666		NVAccelCommonFini(pScrn);
667		return FALSE;
668	}
669
670	pNv->pushbuf->user_priv = pNv->bufctx;
671
672	/* Scratch buffer */
673	ret = nouveau_bo_new(pNv->dev, NOUVEAU_BO_VRAM | NOUVEAU_BO_MAP,
674			     128 * 1024, 128 * 1024, NULL, &pNv->scratch);
675	if (!ret)
676		ret = nouveau_bo_map(pNv->scratch, 0, pNv->client);
677	if (ret) {
678		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
679			   "Failed to allocate scratch buffer: %d\n", ret);
680		return FALSE;
681	}
682
683	/* General engine objects */
684	if (pNv->Architecture < NV_FERMI) {
685		INIT_CONTEXT_OBJECT(DmaNotifier0);
686		INIT_CONTEXT_OBJECT(Null);
687	}
688
689	/* 2D engine */
690	if (pNv->Architecture < NV_TESLA) {
691		INIT_CONTEXT_OBJECT(ContextSurfaces);
692		INIT_CONTEXT_OBJECT(ContextBeta1);
693		INIT_CONTEXT_OBJECT(ContextBeta4);
694		INIT_CONTEXT_OBJECT(ImagePattern);
695		INIT_CONTEXT_OBJECT(RasterOp);
696		INIT_CONTEXT_OBJECT(Rectangle);
697		INIT_CONTEXT_OBJECT(ImageBlit);
698		INIT_CONTEXT_OBJECT(ScaledImage);
699		INIT_CONTEXT_OBJECT(ClipRectangle);
700		INIT_CONTEXT_OBJECT(ImageFromCpu);
701	} else
702	if (pNv->Architecture < NV_FERMI) {
703		INIT_CONTEXT_OBJECT(2D_NV50);
704	} else {
705		INIT_CONTEXT_OBJECT(2D_NVC0);
706	}
707
708	if (pNv->Architecture < NV_TESLA)
709		INIT_CONTEXT_OBJECT(MemFormat);
710	else
711	if (pNv->Architecture < NV_FERMI)
712		INIT_CONTEXT_OBJECT(M2MF_NV50);
713	else
714	if (pNv->Architecture < NV_KEPLER)
715		INIT_CONTEXT_OBJECT(M2MF_NVC0);
716	else {
717		INIT_CONTEXT_OBJECT(P2MF_NVE0);
718		INIT_CONTEXT_OBJECT(COPY_NVE0);
719	}
720
721	/* 3D init */
722	switch (pNv->Architecture) {
723	case NV_FERMI:
724	case NV_KEPLER:
725	case NV_MAXWELL:
726	case NV_PASCAL:
727		INIT_CONTEXT_OBJECT(3D_NVC0);
728		break;
729	case NV_TESLA:
730		INIT_CONTEXT_OBJECT(NV50TCL);
731		break;
732	case NV_ARCH_40:
733		INIT_CONTEXT_OBJECT(NV40TCL);
734		break;
735	case NV_ARCH_30:
736		INIT_CONTEXT_OBJECT(NV30TCL);
737		break;
738	case NV_ARCH_20:
739	case NV_ARCH_10:
740		INIT_CONTEXT_OBJECT(NV10TCL);
741		break;
742	default:
743		break;
744	}
745
746	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Channel setup complete.\n");
747	return TRUE;
748}
749