1/*
2 * SiS DGA handling
3 *
4 * Copyright (C) 2000 by Alan Hourihane, Sychdyn, North Wales, UK.
5 * Copyright (C) 2001-2005 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 "sis.h"
40#include "dgaproc.h"
41
42#include "sis_regs.h"
43
44#ifndef NEW_DGAOPENFRAMEBUFFER
45static Bool SIS_OpenFramebuffer(ScrnInfoPtr, char **, UChar **,
46			int *, int *, int *);
47#else
48static Bool SIS_OpenFramebuffer(ScrnInfoPtr, char **, unsigned int *,
49			unsigned int *, unsigned int *, unsigned int *);
50#endif
51static Bool SIS_SetMode(ScrnInfoPtr, DGAModePtr);
52static void SIS_Sync(ScrnInfoPtr);
53static int  SIS_GetViewport(ScrnInfoPtr);
54static void SIS_SetViewport(ScrnInfoPtr, int, int, int);
55static void SIS_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
56static void SIS_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);
57static void SIS_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int, unsigned long);
58
59static
60DGAFunctionRec SISDGAFuncs = {
61   SIS_OpenFramebuffer,
62   NULL,
63   SIS_SetMode,
64   SIS_SetViewport,
65   SIS_GetViewport,
66   SIS_Sync,
67   SIS_FillRect,
68   SIS_BlitRect,
69   NULL
70};
71
72static
73DGAFunctionRec SISDGAFuncs3xx = {
74   SIS_OpenFramebuffer,
75   NULL,
76   SIS_SetMode,
77   SIS_SetViewport,
78   SIS_GetViewport,
79   SIS_Sync,
80   SIS_FillRect,
81   SIS_BlitRect,
82   SIS_BlitTransRect
83};
84
85static DGAModePtr
86SISSetupDGAMode(
87   ScrnInfoPtr pScrn,
88   DGAModePtr modes,
89   int *num,
90   int bitsPerPixel,
91   int depth,
92   Bool pixmap,
93   int secondPitch,
94   ULong red,
95   ULong green,
96   ULong blue,
97   short visualClass
98){
99   SISPtr pSiS = SISPTR(pScrn);
100   DGAModePtr newmodes = NULL, currentMode;
101   DisplayModePtr pMode, firstMode;
102   int otherPitch, Bpp = bitsPerPixel >> 3;
103   Bool oneMore;
104
105   pMode = firstMode = pScrn->modes;
106
107   while(pMode) {
108
109#ifdef SISMERGED
110	if(pSiS->MergedFB) {
111	   Bool nogood = FALSE;
112	   /* Filter out all meta modes that would require driver-side panning */
113	   switch(((SiSMergedDisplayModePtr)pMode->Private)->CRT2Position) {
114	   case sisClone:
115	      if( (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->HDisplay !=
116		   ((SiSMergedDisplayModePtr)pMode->Private)->CRT2->HDisplay)	||
117		  (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->VDisplay !=
118		   ((SiSMergedDisplayModePtr)pMode->Private)->CRT2->VDisplay)	||
119		  (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->HDisplay !=
120		   pMode->HDisplay)						||
121		  (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->VDisplay !=
122		   pMode->VDisplay) )
123		 nogood = TRUE;
124	      break;
125	   case sisRightOf:
126	   case sisLeftOf:
127	      if( (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->VDisplay !=
128		   ((SiSMergedDisplayModePtr)pMode->Private)->CRT2->VDisplay)	||
129		  (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->VDisplay != pMode->VDisplay) )
130		 nogood = TRUE;
131	      break;
132	   default:
133	      if( (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->HDisplay !=
134		   ((SiSMergedDisplayModePtr)pMode->Private)->CRT2->HDisplay)	||
135		  (((SiSMergedDisplayModePtr)pMode->Private)->CRT1->HDisplay != pMode->HDisplay) )
136		 nogood = TRUE;
137	   }
138	   if(nogood) {
139	      if(depth == 16) { /* Print this only the first time */
140		 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
141			"DGA: MetaMode %dx%d not suitable for DGA, skipping\n",
142			pMode->HDisplay, pMode->VDisplay);
143	      }
144	      goto mode_nogood;
145	   }
146	}
147#endif
148
149	otherPitch = secondPitch ? secondPitch : pMode->HDisplay;
150
151	if(pMode->HDisplay != otherPitch) {
152
153	    newmodes = realloc(modes, (*num + 2) * sizeof(DGAModeRec));
154	    oneMore  = TRUE;
155
156	} else {
157
158	    newmodes = realloc(modes, (*num + 1) * sizeof(DGAModeRec));
159	    oneMore  = FALSE;
160
161	}
162
163	if(!newmodes) {
164	    free(modes);
165	    return NULL;
166	}
167	modes = newmodes;
168
169SECOND_PASS:
170
171	currentMode = modes + *num;
172	(*num)++;
173
174	currentMode->mode           = pMode;
175	currentMode->flags          = DGA_CONCURRENT_ACCESS;
176	if(pixmap)
177	    currentMode->flags     |= DGA_PIXMAP_AVAILABLE;
178	if(!pSiS->NoAccel) {
179	    currentMode->flags     |= DGA_FILL_RECT | DGA_BLIT_RECT;
180	    if((pSiS->VGAEngine == SIS_300_VGA) ||
181	       (pSiS->VGAEngine == SIS_315_VGA) ||
182	       (pSiS->VGAEngine == SIS_530_VGA)) {
183               currentMode->flags  |= DGA_BLIT_RECT_TRANS;
184            }
185	}
186	if(pMode->Flags & V_DBLSCAN)
187	    currentMode->flags     |= DGA_DOUBLESCAN;
188	if(pMode->Flags & V_INTERLACE)
189	    currentMode->flags     |= DGA_INTERLACED;
190	currentMode->byteOrder      = pScrn->imageByteOrder;
191	currentMode->depth          = depth;
192	currentMode->bitsPerPixel   = bitsPerPixel;
193	currentMode->red_mask       = red;
194	currentMode->green_mask     = green;
195	currentMode->blue_mask      = blue;
196	currentMode->visualClass    = visualClass;
197	currentMode->viewportWidth  = pMode->HDisplay;
198	currentMode->viewportHeight = pMode->VDisplay;
199	currentMode->xViewportStep  = 1;
200	currentMode->yViewportStep  = 1;
201	currentMode->viewportFlags  = DGA_FLIP_RETRACE;
202	currentMode->offset         = 0;
203	currentMode->address        = pSiS->FbBase;
204
205	if(oneMore) {
206
207	    /* first one is narrow width */
208	    currentMode->bytesPerScanline = (((pMode->HDisplay * Bpp) + 3) & ~3L);
209	    currentMode->imageWidth   = pMode->HDisplay;
210	    currentMode->imageHeight  = pMode->VDisplay;
211	    currentMode->pixmapWidth  = currentMode->imageWidth;
212	    currentMode->pixmapHeight = currentMode->imageHeight;
213	    currentMode->maxViewportX = currentMode->imageWidth -
214					currentMode->viewportWidth;
215	    /* this might need to get clamped to some maximum */
216	    currentMode->maxViewportY = (currentMode->imageHeight -
217					 currentMode->viewportHeight);
218	    oneMore = FALSE;
219	    goto SECOND_PASS;
220
221	} else {
222
223	    currentMode->bytesPerScanline = ((otherPitch * Bpp) + 3) & ~3L;
224	    currentMode->imageWidth       = otherPitch;
225	    currentMode->imageHeight      = pMode->VDisplay;
226	    currentMode->pixmapWidth      = currentMode->imageWidth;
227	    currentMode->pixmapHeight     = currentMode->imageHeight;
228	    currentMode->maxViewportX     = (currentMode->imageWidth -
229					     currentMode->viewportWidth);
230            /* this might need to get clamped to some maximum */
231	    currentMode->maxViewportY     = (currentMode->imageHeight -
232					     currentMode->viewportHeight);
233	}
234
235#ifdef SISMERGED
236mode_nogood:
237#endif
238
239	pMode = pMode->next;
240	if(pMode == firstMode)
241	   break;
242    }
243
244    return modes;
245}
246
247Bool
248SISDGAInit(ScreenPtr pScreen)
249{
250   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
251   SISPtr pSiS = SISPTR(pScrn);
252   DGAModePtr modes = NULL;
253   int num = 0;
254
255   /* 8 */
256   /* We don't support 8bpp modes in dual head or MergedFB mode,
257    * so don't offer them to DGA either.
258    */
259#ifdef SISDUALHEAD
260   if(!pSiS->DualHeadMode) {
261#endif
262#ifdef SISMERGED
263      if(!(pSiS->MergedFB)) {
264#endif
265         modes = SISSetupDGAMode(pScrn, modes, &num, 8, 8,
266				 (pScrn->bitsPerPixel == 8),
267				 ((pScrn->bitsPerPixel != 8)
268				     ? 0 : pScrn->displayWidth),
269				 0, 0, 0, PseudoColor);
270#ifdef SISMERGED
271      }
272#endif
273#ifdef SISDUALHEAD
274   }
275#endif
276
277   /* 16 */
278   modes = SISSetupDGAMode(pScrn, modes, &num, 16, 16,
279			   (pScrn->bitsPerPixel == 16),
280			   ((pScrn->depth != 16)
281				? 0 : pScrn->displayWidth),
282			   0xf800, 0x07e0, 0x001f, TrueColor);
283
284   if((pSiS->VGAEngine == SIS_530_VGA) || (pSiS->VGAEngine == SIS_OLD_VGA)) {
285      /* 24 */
286      modes = SISSetupDGAMode(pScrn, modes, &num, 24, 24,
287			      (pScrn->bitsPerPixel == 24),
288			      ((pScrn->bitsPerPixel != 24)
289				 ? 0 : pScrn->displayWidth),
290			      0xff0000, 0x00ff00, 0x0000ff, TrueColor);
291   }
292
293   if(pSiS->VGAEngine != SIS_OLD_VGA) {
294      /* 32 */
295      modes = SISSetupDGAMode(pScrn, modes, &num, 32, 24,
296			      (pScrn->bitsPerPixel == 32),
297			      ((pScrn->bitsPerPixel != 32)
298				  ? 0 : pScrn->displayWidth),
299			      0xff0000, 0x00ff00, 0x0000ff, TrueColor);
300   }
301
302   pSiS->numDGAModes = num;
303   pSiS->DGAModes = modes;
304
305   if(num) {
306      if((pSiS->VGAEngine == SIS_300_VGA) ||
307         (pSiS->VGAEngine == SIS_315_VGA) ||
308         (pSiS->VGAEngine == SIS_530_VGA)) {
309         return DGAInit(pScreen, &SISDGAFuncs3xx, modes, num);
310      } else {
311         return DGAInit(pScreen, &SISDGAFuncs, modes, num);
312      }
313   } else {
314      xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
315		"No DGA-suitable modes found, disabling DGA\n");
316      return TRUE;
317   }
318}
319
320static Bool
321SIS_OpenFramebuffer(
322   ScrnInfoPtr pScrn,
323   char **name,
324#ifndef NEW_DGAOPENFRAMEBUFFER
325   UChar **mem,
326   int *size,
327   int *offset,
328   int *flags
329#else
330   unsigned int *mem,
331   unsigned int *size,
332   unsigned int *offset,
333   unsigned int *flags
334#endif
335){
336    SISPtr pSiS = SISPTR(pScrn);
337
338    *name = NULL;       /* no special device */
339#ifndef NEW_DGAOPENFRAMEBUFFER
340    *mem = (UChar *)pSiS->FbAddress;
341#else
342    *mem = pSiS->FbAddress;
343#endif
344    *size = pSiS->maxxfbmem;
345    *offset = 0;
346#ifndef NEW_DGAOPENFRAMEBUFFER
347    *flags = DGA_NEED_ROOT;
348#else
349    *flags = 0;
350#endif
351
352    return TRUE;
353}
354
355static Bool
356SIS_SetMode(
357   ScrnInfoPtr pScrn,
358   DGAModePtr pMode
359){
360   static SISFBLayout BackupLayouts[MAXSCREENS];
361   int index = pScrn->pScreen->myNum;
362   SISPtr pSiS = SISPTR(pScrn);
363
364    if(!pMode) { /* restore the original mode */
365
366	if(pSiS->DGAactive) {
367	   /* put the ScreenParameters back */
368	   memcpy(&pSiS->CurrentLayout, &BackupLayouts[index], sizeof(SISFBLayout));
369	}
370
371	pScrn->currentMode = pSiS->CurrentLayout.mode;
372	pSiS->DGAactive = FALSE;
373
374	(*pScrn->SwitchMode)(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode));
375	(*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
376
377    } else {	/* set new mode */
378
379        if(!pSiS->DGAactive) {
380	    /* save the old parameters */
381	    memcpy(&BackupLayouts[index], &pSiS->CurrentLayout, sizeof(SISFBLayout));
382	    pSiS->DGAactive = TRUE;
383	}
384
385	pSiS->CurrentLayout.bitsPerPixel  = pMode->bitsPerPixel;
386	pSiS->CurrentLayout.depth         = pMode->depth;
387	pSiS->CurrentLayout.displayWidth  = pMode->bytesPerScanline / (pMode->bitsPerPixel >> 3);
388	pSiS->CurrentLayout.displayHeight = pMode->imageHeight;
389
390	(*pScrn->SwitchMode)(SWITCH_MODE_ARGS(pScrn, pMode->mode));
391	/* Adjust viewport to 0/0 after mode switch */
392	/* This fixes the vmware-in-dualhead problems */
393	(*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, 0, 0));
394	pSiS->CurrentLayout.DGAViewportX = pSiS->CurrentLayout.DGAViewportY = 0;
395    }
396
397    return TRUE;
398}
399
400static int
401SIS_GetViewport(
402  ScrnInfoPtr pScrn
403){
404    SISPtr pSiS = SISPTR(pScrn);
405
406    return pSiS->DGAViewportStatus;
407}
408
409static void
410SIS_SetViewport(
411   ScrnInfoPtr pScrn,
412   int x, int y,
413   int flags
414){
415   SISPtr pSiS = SISPTR(pScrn);
416
417   (*pScrn->AdjustFrame)(ADJUST_FRAME_ARGS(pScrn, x, y));
418   pSiS->DGAViewportStatus = 0;  /* There are never pending Adjusts */
419   pSiS->CurrentLayout.DGAViewportX = x;
420   pSiS->CurrentLayout.DGAViewportY = y;
421}
422
423static void
424SIS_Sync(
425   ScrnInfoPtr pScrn
426){
427    SISPtr pSiS = SISPTR(pScrn);
428
429    (*pSiS->SyncAccel)(pScrn);
430}
431
432static void
433SIS_FillRect(
434   ScrnInfoPtr pScrn,
435   int x, int y, int w, int h,
436   unsigned long color
437){
438    SISPtr pSiS = SISPTR(pScrn);
439
440    if(pSiS->FillRect) {
441       (*pSiS->FillRect)(pScrn, x, y, w, h, (int)color);
442#ifdef SIS_USE_XAA
443       if(!pSiS->useEXA && pSiS->AccelInfoPtr) {
444          SET_SYNC_FLAG(pSiS->AccelInfoPtr);
445       }
446#endif
447    }
448}
449
450static void
451SIS_BlitRect(
452   ScrnInfoPtr pScrn,
453   int srcx, int srcy,
454   int w, int h,
455   int dstx, int dsty
456){
457    SISPtr pSiS = SISPTR(pScrn);
458
459    if(pSiS->BlitRect) {
460       (*pSiS->BlitRect)(pScrn, srcx, srcy, dstx, dsty, w, h, -1);
461#ifdef SIS_USE_XAA
462       if(!pSiS->useEXA && pSiS->AccelInfoPtr) {
463          SET_SYNC_FLAG(pSiS->AccelInfoPtr);
464       }
465#endif
466    }
467}
468
469static void
470SIS_BlitTransRect(
471   ScrnInfoPtr pScrn,
472   int srcx, int srcy,
473   int w, int h,
474   int dstx, int dsty,
475   ULong color
476){
477    SISPtr pSiS = SISPTR(pScrn);
478
479    if(pSiS->BlitRect) {
480       (*pSiS->BlitRect)(pScrn, srcx, srcy, dstx, dsty, w, h, (int)color);
481#ifdef SIS_USE_XAA
482       if(!pSiS->useEXA && pSiS->AccelInfoPtr) {
483          SET_SYNC_FLAG(pSiS->AccelInfoPtr);
484       }
485#endif
486    }
487}
488
489
490
491