1/*
2 *  DGA handling
3 *
4 * Copyright (C) 2000 by Alan Hourihane, Sychdyn, North Wales, UK.
5 * Copyright (C) 2001-2004 by Thomas Winischhofer, Vienna, Austria
6 *
7 * Portions from radeon_dga.c which is
8 *          Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
9 *                         VA Linux Systems Inc., Fremont, California.
10 *
11 * Licensed under the following terms:
12 *
13 * Permission to use, copy, modify, distribute, and sell this software and its
14 * documentation for any purpose is hereby granted without fee, provided that
15 * the above copyright notice appear in all copies and that both that
16 * copyright notice and this permission notice appear in supporting
17 * documentation, and that the name of the providers not be used in
18 * advertising or publicity pertaining to distribution of the software without
19 * specific, written prior permission.  The providers make no representations
20 * about the suitability of this software for any purpose.  It is provided
21 * "as is" without express or implied warranty.
22 *
23 * THE PROVIDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
24 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
25 * EVENT SHALL THE PROVIDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
26 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
27 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
28 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
29 * PERFORMANCE OF THIS SOFTWARE.
30 *
31 * Authors:  Alan Hourihane, <alanh@fairlite.demon.co.uk>
32 *           Thomas Winischhofer <thomas@winischhofer.net>
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39#include "xf86.h"
40#include "xf86_OSproc.h"
41#include "xf86Pci.h"
42#include "xf86PciInfo.h"
43#include "xaa.h"
44#include "xaalocal.h"
45#include "xgi.h"
46#include "xgi_regs.h"
47#include "dgaproc.h"
48
49#ifndef NEW_DGAOPENFRAMEBUFFER
50static Bool XGI_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **,
51                                int *, int *, int *);
52#else
53static Bool XGI_OpenFramebuffer(ScrnInfoPtr, char **, unsigned int *,
54                                unsigned int *, unsigned int *, unsigned int *);
55#endif
56
57static Bool XGI_SetMode(ScrnInfoPtr, DGAModePtr);
58static void XGI_Sync(ScrnInfoPtr);
59static int  XGI_GetViewport(ScrnInfoPtr);
60static void XGI_SetViewport(ScrnInfoPtr, int, int, int);
61static void XGI_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
62static void XGI_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);
63
64static
65DGAFunctionRec XGIDGAFuncs = {
66   XGI_OpenFramebuffer,
67   NULL,
68   XGI_SetMode,
69   XGI_SetViewport,
70   XGI_GetViewport,
71   XGI_Sync,
72   XGI_FillRect,
73   XGI_BlitRect,
74   NULL
75};
76
77
78static DGAModePtr
79XGISetupDGAMode(
80   ScrnInfoPtr pScrn,
81   DGAModePtr modes,
82   int *num,
83   int bitsPerPixel,
84   int depth,
85   Bool pixmap,
86   int secondPitch,
87   unsigned long red,
88   unsigned long green,
89   unsigned long blue,
90   short visualClass
91){
92   XGIPtr pXGI = XGIPTR(pScrn);
93   DGAModePtr newmodes = NULL, currentMode;
94   DisplayModePtr pMode, firstMode;
95   int otherPitch, Bpp = bitsPerPixel >> 3;
96   Bool oneMore;
97
98   pMode = firstMode = pScrn->modes;
99
100   while(pMode) {
101
102	otherPitch = secondPitch ? secondPitch : pMode->HDisplay;
103
104	if(pMode->HDisplay != otherPitch) {
105
106	    newmodes = xrealloc(modes, (*num + 2) * sizeof(DGAModeRec));
107	    oneMore  = TRUE;
108
109	} else {
110
111	    newmodes = xrealloc(modes, (*num + 1) * sizeof(DGAModeRec));
112	    oneMore  = FALSE;
113
114	}
115
116	if(!newmodes) {
117	    xfree(modes);
118	    return NULL;
119	}
120	modes = newmodes;
121
122SECOND_PASS:
123
124	currentMode = modes + *num;
125	(*num)++;
126
127	currentMode->mode           = pMode;
128	currentMode->flags          = DGA_CONCURRENT_ACCESS;
129	if(pixmap)
130	    currentMode->flags     |= DGA_PIXMAP_AVAILABLE;
131	if(!pXGI->NoAccel) {
132	    currentMode->flags     |= DGA_FILL_RECT | DGA_BLIT_RECT;
133	}
134	if(pMode->Flags & V_DBLSCAN)
135	    currentMode->flags     |= DGA_DOUBLESCAN;
136	if(pMode->Flags & V_INTERLACE)
137	    currentMode->flags     |= DGA_INTERLACED;
138	currentMode->byteOrder      = pScrn->imageByteOrder;
139	currentMode->depth          = depth;
140	currentMode->bitsPerPixel   = bitsPerPixel;
141	currentMode->red_mask       = red;
142	currentMode->green_mask     = green;
143	currentMode->blue_mask      = blue;
144	currentMode->visualClass    = visualClass;
145	currentMode->viewportWidth  = pMode->HDisplay;
146	currentMode->viewportHeight = pMode->VDisplay;
147	currentMode->xViewportStep  = 1;
148	currentMode->yViewportStep  = 1;
149	currentMode->viewportFlags  = DGA_FLIP_RETRACE;
150	currentMode->offset         = 0;
151	currentMode->address        = pXGI->FbBase;
152
153	if(oneMore) {
154
155	    /* first one is narrow width */
156	    currentMode->bytesPerScanline = (((pMode->HDisplay * Bpp) + 3) & ~3L);
157	    currentMode->imageWidth   = pMode->HDisplay;
158	    currentMode->imageHeight  = pMode->VDisplay;
159	    currentMode->pixmapWidth  = currentMode->imageWidth;
160	    currentMode->pixmapHeight = currentMode->imageHeight;
161	    currentMode->maxViewportX = currentMode->imageWidth -
162					currentMode->viewportWidth;
163	    /* this might need to get clamped to some maximum */
164	    currentMode->maxViewportY = (currentMode->imageHeight -
165					 currentMode->viewportHeight);
166	    oneMore = FALSE;
167	    goto SECOND_PASS;
168
169	} else {
170
171	    currentMode->bytesPerScanline = ((otherPitch * Bpp) + 3) & ~3L;
172	    currentMode->imageWidth       = otherPitch;
173	    currentMode->imageHeight      = pMode->VDisplay;
174	    currentMode->pixmapWidth      = currentMode->imageWidth;
175	    currentMode->pixmapHeight     = currentMode->imageHeight;
176	    currentMode->maxViewportX     = (currentMode->imageWidth -
177					     currentMode->viewportWidth);
178            /* this might need to get clamped to some maximum */
179	    currentMode->maxViewportY     = (currentMode->imageHeight -
180					     currentMode->viewportHeight);
181	}
182
183	pMode = pMode->next;
184	if(pMode == firstMode)
185	   break;
186    }
187
188    return modes;
189}
190
191
192Bool
193XGIDGAInit(ScreenPtr pScreen)
194{
195   ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
196   XGIPtr pXGI = XGIPTR(pScrn);
197   DGAModePtr modes = NULL;
198   int num = 0;
199
200   /* 8 */
201   /* We don't support 8bpp modes in dual head or MergedFB mode,
202    * so don't offer them to DGA either.
203    */
204   if (!IS_DUAL_HEAD(pXGI)
205#ifdef XGIMERGED
206       && !(pXGI->MergedFB)
207#endif
208       ) {
209       modes = XGISetupDGAMode(pScrn, modes, &num, 8, 8,
210			       (pScrn->bitsPerPixel == 8),
211			       ((pScrn->bitsPerPixel != 8)
212				? 0 : pScrn->displayWidth),
213			       0, 0, 0, PseudoColor);
214   }
215
216   /* 16 */
217   modes = XGISetupDGAMode(pScrn, modes, &num, 16, 16,
218			   (pScrn->bitsPerPixel == 16),
219			   ((pScrn->depth != 16)
220				? 0 : pScrn->displayWidth),
221			   0xf800, 0x07e0, 0x001f, TrueColor);
222
223    /* 32 */
224    modes = XGISetupDGAMode(pScrn, modes, &num, 32, 24,
225			    (pScrn->bitsPerPixel == 32),
226			    ((pScrn->bitsPerPixel != 32)
227			     ? 0 : pScrn->displayWidth),
228			    0xff0000, 0x00ff00, 0x0000ff, TrueColor);
229
230    pXGI->numDGAModes = num;
231    pXGI->DGAModes = modes;
232
233    if (num) {
234	return DGAInit(pScreen, &XGIDGAFuncs, modes, num);
235    }
236    else {
237	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
238		   "No DGA-suitable modes found, disabling DGA\n");
239	return TRUE;
240    }
241}
242
243
244static Bool
245XGI_SetMode(
246   ScrnInfoPtr pScrn,
247   DGAModePtr pMode
248){
249   static XGIFBLayout BackupLayouts[MAXSCREENS];
250   int index = pScrn->pScreen->myNum;
251   XGIPtr pXGI = XGIPTR(pScrn);
252
253    if(!pMode) { /* restore the original mode */
254
255        if(pXGI->DGAactive) {
256           /* put the ScreenParameters back */
257	   memcpy(&pXGI->CurrentLayout, &BackupLayouts[index], sizeof(XGIFBLayout));
258        }
259
260	pScrn->currentMode = pXGI->CurrentLayout.mode;
261
262        (*pScrn->SwitchMode)(index, pScrn->currentMode, 0);
263	(*pScrn->AdjustFrame)(index, pScrn->frameX0, pScrn->frameY0, 0);
264        pXGI->DGAactive = FALSE;
265
266    } else {	/* set new mode */
267
268        if(!pXGI->DGAactive) {
269	    /* save the old parameters */
270            memcpy(&BackupLayouts[index], &pXGI->CurrentLayout, sizeof(XGIFBLayout));
271            pXGI->DGAactive = TRUE;
272    	}
273
274	pXGI->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel;
275	pXGI->CurrentLayout.depth        = pMode->depth;
276	pXGI->CurrentLayout.displayWidth = pMode->bytesPerScanline / (pMode->bitsPerPixel >> 3);
277
278    	(*pScrn->SwitchMode)(index, pMode->mode, 0);
279	/* TW: Adjust viewport to 0/0 after mode switch */
280	/* This should fix the vmware-in-dualhead problems */
281	(*pScrn->AdjustFrame)(index, 0, 0, 0);
282    }
283
284    return TRUE;
285}
286
287static int
288XGI_GetViewport(ScrnInfoPtr pScrn)
289{
290    (void) pScrn;
291
292    /* There are never pending Adjusts */
293    return 0;
294}
295
296static void
297XGI_SetViewport(ScrnInfoPtr pScrn, int x, int y, int flags)
298{
299   (*pScrn->AdjustFrame)(pScrn->pScreen->myNum, x, y, flags);
300}
301
302static void
303XGI_FillRect (
304   ScrnInfoPtr pScrn,
305   int x, int y, int w, int h,
306   unsigned long color
307){
308    XGIPtr pXGI = XGIPTR(pScrn);
309
310#ifdef XGI_USE_XAA
311    if(pXGI->AccelInfoPtr) {
312      (*pXGI->AccelInfoPtr->SetupForSolidFill)(pScrn, color, GXcopy, ~0);
313      (*pXGI->AccelInfoPtr->SubsequentSolidFillRect)(pScrn, x, y, w, h);
314      SET_SYNC_FLAG(pXGI->AccelInfoPtr);
315    }
316#endif
317}
318
319static void
320XGI_Sync(
321   ScrnInfoPtr pScrn
322){
323    XGIPtr pXGI = XGIPTR(pScrn);
324
325#ifdef XGI_USE_XAA
326    if(pXGI->AccelInfoPtr) {
327      (*pXGI->AccelInfoPtr->Sync)(pScrn);
328    }
329#endif
330}
331
332static void
333XGI_BlitRect(
334   ScrnInfoPtr pScrn,
335   int srcx, int srcy,
336   int w, int h,
337   int dstx, int dsty
338){
339    XGIPtr pXGI = XGIPTR(pScrn);
340
341#ifdef XGI_USE_XAA
342    if(pXGI->AccelInfoPtr) {
343      int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
344      int ydir = (srcy < dsty) ? -1 : 1;
345
346      (*pXGI->AccelInfoPtr->SetupForScreenToScreenCopy)(
347          pScrn, xdir, ydir, GXcopy, (CARD32)~0, -1);
348      (*pXGI->AccelInfoPtr->SubsequentScreenToScreenCopy)(
349          pScrn, srcx, srcy, dstx, dsty, w, h);
350      SET_SYNC_FLAG(pXGI->AccelInfoPtr);
351    }
352#endif
353}
354
355static Bool
356XGI_OpenFramebuffer(
357   ScrnInfoPtr pScrn,
358   char **name,
359#ifndef NEW_DGAOPENFRAMEBUFFER
360   unsigned char **mem,
361   int *size,
362   int *offset,
363   int *flags
364#else
365   unsigned int *mem,
366   unsigned int *size,
367   unsigned int *offset,
368   unsigned int *flags
369#endif
370){
371    XGIPtr pXGI = XGIPTR(pScrn);
372
373    *name = NULL;       /* no special device */
374#ifndef NEW_DGAOPENFRAMEBUFFER
375    *mem = (unsigned char*)pXGI->FbAddress;
376#else
377    *mem = pXGI->FbAddress;
378#endif
379    *size = pXGI->maxxfbmem;
380    *offset = 0;
381    *flags = DGA_NEED_ROOT;
382
383    return TRUE;
384}
385