1692f60a7Smrg/*
2692f60a7Smrg * Copyright 2000 by Alan Hourihane, Sychdyn, North Wales, UK.
3692f60a7Smrg *
4692f60a7Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5692f60a7Smrg * documentation for any purpose is hereby granted without fee, provided that
6692f60a7Smrg * the above copyright notice appear in all copies and that both that
7692f60a7Smrg * copyright notice and this permission notice appear in supporting
8692f60a7Smrg * documentation, and that the name of Alan Hourihane not be used in
9692f60a7Smrg * advertising or publicity pertaining to distribution of the software without
10692f60a7Smrg * specific, written prior permission.  Alan Hourihane makes no representations
11692f60a7Smrg * about the suitability of this software for any purpose.  It is provided
12692f60a7Smrg * "as is" without express or implied warranty.
13692f60a7Smrg *
14692f60a7Smrg * ALAN HOURIHANE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15692f60a7Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16692f60a7Smrg * EVENT SHALL ALAN HOURIHANE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17692f60a7Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18692f60a7Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19692f60a7Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20692f60a7Smrg * PERFORMANCE OF THIS SOFTWARE.
21692f60a7Smrg *
22692f60a7Smrg * Authors:  Alan Hourihane, <alanh@fairlite.demon.co.uk>
23692f60a7Smrg */
24692f60a7Smrg
25692f60a7Smrg#ifdef HAVE_CONFIG_H
26692f60a7Smrg#include "config.h"
27692f60a7Smrg#endif
28692f60a7Smrg
29692f60a7Smrg#include "xf86.h"
30692f60a7Smrg#include "xf86_OSproc.h"
31692f60a7Smrg#include "xf86Pci.h"
32692f60a7Smrg#include "neo.h"
33692f60a7Smrg#include "neo_reg.h"
34692f60a7Smrg#include "dgaproc.h"
35692f60a7Smrg#include "vgaHW.h"
36692f60a7Smrg
37692f60a7Smrgstatic Bool NEO_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **,
38692f60a7Smrg					int *, int *, int *);
39692f60a7Smrgstatic Bool NEO_SetMode(ScrnInfoPtr, DGAModePtr);
40692f60a7Smrgstatic int  NEO_GetViewport(ScrnInfoPtr);
41692f60a7Smrgstatic void NEO_SetViewport(ScrnInfoPtr, int, int, int);
423f6d0e1dSmrg#ifdef HAVE_XAA_H
43eaa3dbe0Smrgstatic void NEO_Sync(ScrnInfoPtr);
44692f60a7Smrgstatic void NEO_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
45692f60a7Smrgstatic void NEO_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);
46692f60a7Smrg#if 0
47692f60a7Smrgstatic void NEO_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int,
48692f60a7Smrg					unsigned long);
49692f60a7Smrg#endif
503f6d0e1dSmrg#endif
51692f60a7Smrg
52692f60a7Smrgstatic
53692f60a7SmrgDGAFunctionRec NEODGAFuncs = {
54692f60a7Smrg   NEO_OpenFramebuffer,
55692f60a7Smrg   NULL,
56692f60a7Smrg   NEO_SetMode,
57692f60a7Smrg   NEO_SetViewport,
58692f60a7Smrg   NEO_GetViewport,
593f6d0e1dSmrg#ifdef HAVE_XAA_H
60eaa3dbe0Smrg   NEO_Sync,
61692f60a7Smrg   NEO_FillRect,
62692f60a7Smrg   NEO_BlitRect,
63692f60a7Smrg#if 0
64692f60a7Smrg   NEO_BlitTransRect
65692f60a7Smrg#else
66692f60a7Smrg   NULL
67692f60a7Smrg#endif
683f6d0e1dSmrg#else
693f6d0e1dSmrg   NULL, NULL, NULL
703f6d0e1dSmrg#endif
71692f60a7Smrg};
72692f60a7Smrg
73692f60a7SmrgBool
74692f60a7SmrgNEODGAInit(ScreenPtr pScreen)
75692f60a7Smrg{
763f6d0e1dSmrg   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
77692f60a7Smrg   NEOPtr pNEO = NEOPTR(pScrn);
78692f60a7Smrg   DGAModePtr modes = NULL, newmodes = NULL, currentMode;
79692f60a7Smrg   DisplayModePtr pMode, firstMode;
80692f60a7Smrg   int Bpp = pScrn->bitsPerPixel >> 3;
81692f60a7Smrg   int num = 0, imlines, pixlines;
82692f60a7Smrg
83692f60a7Smrg   imlines =  (pScrn->videoRam * 1024) /
84692f60a7Smrg      (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
85692f60a7Smrg
86692f60a7Smrg   pixlines =  (imlines > 1024 && !pNEO->noAccel)  ? 1024 : imlines;
87692f60a7Smrg
88692f60a7Smrg   pMode = firstMode = pScrn->modes;
89692f60a7Smrg
90692f60a7Smrg   while(pMode) {
91692f60a7Smrg
923f6d0e1dSmrg	newmodes = realloc(modes, (num + 1) * sizeof(DGAModeRec));
93692f60a7Smrg
94692f60a7Smrg	if(!newmodes) {
953f6d0e1dSmrg	   free(modes);
96692f60a7Smrg	   return FALSE;
97692f60a7Smrg	}
98692f60a7Smrg	modes = newmodes;
99692f60a7Smrg
100692f60a7Smrg	currentMode = modes + num;
101692f60a7Smrg	num++;
102692f60a7Smrg
103692f60a7Smrg	currentMode->mode = pMode;
104692f60a7Smrg	currentMode->flags = DGA_CONCURRENT_ACCESS | DGA_PIXMAP_AVAILABLE;
1053f6d0e1dSmrg#ifdef HAVE_XAA_H
106692f60a7Smrg	if (!pNEO->noAccel)
107692f60a7Smrg	    currentMode->flags |= (DGA_FILL_RECT | DGA_BLIT_RECT);
1083f6d0e1dSmrg#endif
109692f60a7Smrg	if(pMode->Flags & V_DBLSCAN)
110692f60a7Smrg	   currentMode->flags |= DGA_DOUBLESCAN;
111692f60a7Smrg	if(pMode->Flags & V_INTERLACE)
112692f60a7Smrg	   currentMode->flags |= DGA_INTERLACED;
113692f60a7Smrg	currentMode->byteOrder = pScrn->imageByteOrder;
114692f60a7Smrg	currentMode->depth = pScrn->depth;
115692f60a7Smrg	currentMode->bitsPerPixel = pScrn->bitsPerPixel;
116692f60a7Smrg	currentMode->red_mask = pScrn->mask.red;
117692f60a7Smrg	currentMode->green_mask = pScrn->mask.green;
118692f60a7Smrg	currentMode->blue_mask = pScrn->mask.blue;
119692f60a7Smrg	currentMode->visualClass = (Bpp == 1) ? PseudoColor : TrueColor;
120692f60a7Smrg	currentMode->viewportWidth = pMode->HDisplay;
121692f60a7Smrg	currentMode->viewportHeight = pMode->VDisplay;
122692f60a7Smrg	currentMode->xViewportStep = 1;
123692f60a7Smrg	currentMode->yViewportStep = 1;
124692f60a7Smrg	currentMode->viewportFlags = DGA_FLIP_RETRACE;
125692f60a7Smrg	currentMode->offset = 0;
126692f60a7Smrg	currentMode->address = pNEO->NeoFbBase;
127692f60a7Smrg
128692f60a7Smrg	currentMode->bytesPerScanline =
129692f60a7Smrg			((pScrn->displayWidth * Bpp) + 3) & ~3L;
130692f60a7Smrg	currentMode->imageWidth = pScrn->displayWidth;
131692f60a7Smrg	currentMode->imageHeight =  imlines;
132692f60a7Smrg	currentMode->pixmapWidth = currentMode->imageWidth;
133692f60a7Smrg	currentMode->pixmapHeight = pixlines;
134692f60a7Smrg	currentMode->maxViewportX = currentMode->imageWidth -
135692f60a7Smrg					currentMode->viewportWidth;
136692f60a7Smrg	currentMode->maxViewportY = currentMode->imageHeight -
137692f60a7Smrg					currentMode->viewportHeight;
138692f60a7Smrg
139692f60a7Smrg	pMode = pMode->next;
140692f60a7Smrg	if(pMode == firstMode)
141692f60a7Smrg	   break;
142692f60a7Smrg   }
143692f60a7Smrg
144692f60a7Smrg   pNEO->numDGAModes = num;
145692f60a7Smrg   pNEO->DGAModes = modes;
146692f60a7Smrg
147692f60a7Smrg   return DGAInit(pScreen, &NEODGAFuncs, modes, num);
148692f60a7Smrg}
149692f60a7Smrg
150692f60a7Smrgstatic DisplayModePtr NEOSavedDGAModes[MAXSCREENS];
151692f60a7Smrg
152692f60a7Smrgstatic Bool
153692f60a7SmrgNEO_SetMode(
154692f60a7Smrg   ScrnInfoPtr pScrn,
155692f60a7Smrg   DGAModePtr pMode
156692f60a7Smrg){
157692f60a7Smrg   int index = pScrn->pScreen->myNum;
158692f60a7Smrg   NEOPtr pNEO = NEOPTR(pScrn);
159692f60a7Smrg
160692f60a7Smrg   if(!pMode) { /* restore the original mode */
161692f60a7Smrg 	if(pNEO->DGAactive) {
162692f60a7Smrg	    pScrn->currentMode = NEOSavedDGAModes[index];
1633f6d0e1dSmrg            NEOSwitchMode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode));
1643f6d0e1dSmrg	    NEOAdjustFrame(ADJUST_FRAME_ARGS(pScrn, 0, 0));
165692f60a7Smrg 	    pNEO->DGAactive = FALSE;
166692f60a7Smrg	}
167692f60a7Smrg   } else {
168692f60a7Smrg	if(!pNEO->DGAactive) {  /* save the old parameters */
169692f60a7Smrg	    NEOSavedDGAModes[index] = pScrn->currentMode;
170692f60a7Smrg	    pNEO->DGAactive = TRUE;
171692f60a7Smrg	}
172692f60a7Smrg
1733f6d0e1dSmrg        NEOSwitchMode(SWITCH_MODE_ARGS(pScrn, pMode->mode));
174692f60a7Smrg   }
175692f60a7Smrg
176692f60a7Smrg   return TRUE;
177692f60a7Smrg}
178692f60a7Smrg
179692f60a7Smrgstatic int
180692f60a7SmrgNEO_GetViewport(
181692f60a7Smrg  ScrnInfoPtr pScrn
182692f60a7Smrg){
183692f60a7Smrg    NEOPtr pNEO = NEOPTR(pScrn);
184692f60a7Smrg
185692f60a7Smrg    return pNEO->DGAViewportStatus;
186692f60a7Smrg}
187692f60a7Smrg
188692f60a7Smrgstatic void
189692f60a7SmrgNEO_SetViewport(
190692f60a7Smrg   ScrnInfoPtr pScrn,
191692f60a7Smrg   int x, int y,
192692f60a7Smrg   int flags
193692f60a7Smrg){
194692f60a7Smrg   NEOPtr pNEO = NEOPTR(pScrn);
195692f60a7Smrg   vgaHWPtr hwp = VGAHWPTR(pScrn);
196692f60a7Smrg
1973f6d0e1dSmrg   NEOAdjustFrame(ADJUST_FRAME_ARGS(pScrn, x, y));
198692f60a7Smrg   /* wait for retrace */
199692f60a7Smrg   while((hwp->readST01(hwp) & 0x08));
200692f60a7Smrg   while(!(hwp->readST01(hwp) & 0x08));
201692f60a7Smrg
202692f60a7Smrg   pNEO->DGAViewportStatus = 0;
203692f60a7Smrg}
204692f60a7Smrg
2053f6d0e1dSmrg#ifdef HAVE_XAA_H
206692f60a7Smrgstatic void
207692f60a7SmrgNEO_FillRect (
208692f60a7Smrg   ScrnInfoPtr pScrn,
209692f60a7Smrg   int x, int y, int w, int h,
210692f60a7Smrg   unsigned long color
211692f60a7Smrg){
212692f60a7Smrg    NEOPtr pNEO = NEOPTR(pScrn);
213692f60a7Smrg
214692f60a7Smrg    if(pNEO->AccelInfoRec) {
215692f60a7Smrg	(*pNEO->AccelInfoRec->SetupForSolidFill)(pScrn, color, GXcopy, ~0);
216692f60a7Smrg	(*pNEO->AccelInfoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h);
217692f60a7Smrg	SET_SYNC_FLAG(pNEO->AccelInfoRec);
218692f60a7Smrg    }
219692f60a7Smrg}
220692f60a7Smrg
221692f60a7Smrgstatic void
222692f60a7SmrgNEO_Sync(
223692f60a7Smrg   ScrnInfoPtr pScrn
224692f60a7Smrg){
225692f60a7Smrg    NEOPtr pNEO = NEOPTR(pScrn);
226692f60a7Smrg    if(pNEO->AccelInfoRec) {
227692f60a7Smrg	(*pNEO->AccelInfoRec->Sync)(pScrn);
228692f60a7Smrg    }
229692f60a7Smrg}
230692f60a7Smrg
231692f60a7Smrgstatic void
232692f60a7SmrgNEO_BlitRect(
233692f60a7Smrg   ScrnInfoPtr pScrn,
234692f60a7Smrg   int srcx, int srcy,
235692f60a7Smrg   int w, int h,
236692f60a7Smrg   int dstx, int dsty
237692f60a7Smrg){
238692f60a7Smrg    NEOPtr pNEO = NEOPTR(pScrn);
239692f60a7Smrg
240692f60a7Smrg    if(pNEO->AccelInfoRec) {
241692f60a7Smrg	int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
242692f60a7Smrg	int ydir = (srcy < dsty) ? -1 : 1;
243692f60a7Smrg
244692f60a7Smrg	(*pNEO->AccelInfoRec->SetupForScreenToScreenCopy)(
245692f60a7Smrg		pScrn, xdir, ydir, GXcopy, ~0, -1);
246692f60a7Smrg	(*pNEO->AccelInfoRec->SubsequentScreenToScreenCopy)(
247692f60a7Smrg		pScrn, srcx, srcy, dstx, dsty, w, h);
248692f60a7Smrg	SET_SYNC_FLAG(pNEO->AccelInfoRec);
249692f60a7Smrg    }
250692f60a7Smrg}
251692f60a7Smrg
252692f60a7Smrg#if 0
253692f60a7Smrgstatic void
254692f60a7SmrgNEO_BlitTransRect(
255692f60a7Smrg   ScrnInfoPtr pScrn,
256692f60a7Smrg   int srcx, int srcy,
257692f60a7Smrg   int w, int h,
258692f60a7Smrg   int dstx, int dsty,
259692f60a7Smrg   unsigned long color
260692f60a7Smrg){
261692f60a7Smrg  /* this one should be separate since the XAA function would
262692f60a7Smrg     prohibit usage of ~0 as the key */
263692f60a7Smrg}
264692f60a7Smrg#endif
2653f6d0e1dSmrg#endif
266692f60a7Smrgstatic Bool
267692f60a7SmrgNEO_OpenFramebuffer(
268692f60a7Smrg   ScrnInfoPtr pScrn,
269692f60a7Smrg   char **name,
270692f60a7Smrg   unsigned char **mem,
271692f60a7Smrg   int *size,
272692f60a7Smrg   int *offset,
273692f60a7Smrg   int *flags
274692f60a7Smrg){
275692f60a7Smrg    NEOPtr pNEO = NEOPTR(pScrn);
276692f60a7Smrg
277692f60a7Smrg    *name = NULL; 		/* no special device */
278692f60a7Smrg    *mem = (unsigned char*)pNEO->NeoLinearAddr;
279692f60a7Smrg    *size = pNEO->NeoFbMapSize;
280692f60a7Smrg    *offset = 0;
281692f60a7Smrg    *flags = DGA_NEED_ROOT;
282692f60a7Smrg
283692f60a7Smrg    return TRUE;
284692f60a7Smrg}
2853f6d0e1dSmrg
286