1/*
2 * file: apm_dga.c
3 * ported from s3virge, ported from mga
4 *
5 */
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#include "xf86.h"
12#include "xf86_OSproc.h"
13#include "xf86Pci.h"
14#include "apm.h"
15#include "dgaproc.h"
16
17
18static Bool ApmOpenFramebuffer(ScrnInfoPtr, char **, unsigned char **,
19					int *, int *, int *);
20static Bool ApmSetMode(ScrnInfoPtr, DGAModePtr);
21static int  ApmGetViewport(ScrnInfoPtr);
22static void ApmSetViewport(ScrnInfoPtr, int, int, int);
23#ifdef HAVE_XAA_H
24static void ApmFillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
25static void ApmBlitRect(ScrnInfoPtr, int, int, int, int, int, int);
26static void ApmBlitTransRect(ScrnInfoPtr, int, int, int, int, int, int,
27					unsigned long);
28#endif
29static void ApmSync(ScrnInfoPtr);
30
31static
32DGAFunctionRec ApmDGAFuncs = {
33    ApmOpenFramebuffer,
34    NULL,
35    ApmSetMode,
36    ApmSetViewport,
37    ApmGetViewport,
38    ApmSync,
39#ifdef HAVE_XAA_H
40    ApmFillRect,
41    ApmBlitRect,
42    ApmBlitTransRect
43#else
44    NULL, NULL, NULL
45#endif
46};
47
48/*
49 * Placeholder
50 */
51void
52ApmSync(ScrnInfoPtr pScrn)
53{
54}
55
56static __inline__ int FindSmallestPitch(ApmPtr pApm, int Bpp, int width)
57{
58    if (width <= 640)
59	return 640;
60    else if (width <= 800)
61	return 800;
62    else if (width <= 1024)
63	return 1024;
64    else if (width <= 1152)
65	return 1152;
66    else if (width <= 1280)
67	return 1280;
68    else if (width <= 1600)
69	return 1600;
70    return (width + 7) & ~7;
71}
72
73static DGAModePtr
74ApmSetupDGAMode(ScrnInfoPtr pScrn, DGAModePtr modes, int *num,
75		   int bitsPerPixel, int depth, Bool pixmap, int secondPitch,
76		   unsigned long red, unsigned long green, unsigned long blue,
77		   short visualClass)
78{
79   DisplayModePtr firstMode, pMode;
80   APMDECL(pScrn);
81   DGAModePtr mode, newmodes;
82   int size, pitch, Bpp = bitsPerPixel >> 3;
83   Bool reduced_pitch = TRUE;
84
85SECOND_PASS:
86
87   firstMode = NULL;
88
89   for (pMode = pScrn->modes; pMode != firstMode; pMode = pMode->next) {
90
91	if (!firstMode)
92	    firstMode = pMode;
93
94	if (reduced_pitch)
95	    pitch = FindSmallestPitch(pApm, Bpp, pMode->HDisplay);
96	else
97	    pitch = pMode->HDisplay;
98	if (!reduced_pitch && pitch == FindSmallestPitch(pApm, Bpp, pMode->HDisplay))
99	    continue;
100
101	size = pitch * Bpp * pMode->VDisplay;
102
103	if((!secondPitch || (pitch != secondPitch)) &&
104		(size <= pScrn->videoRam * 1024 - pApm->OffscreenReserved)) {
105
106	    if(secondPitch)
107		pitch = secondPitch;
108
109	    if(!(newmodes = realloc(modes, (*num + 1) * sizeof(DGAModeRec))))
110		break;
111
112	    modes = newmodes;
113	    mode = modes + *num;
114
115	    mode->mode = pMode;
116	    mode->flags = DGA_CONCURRENT_ACCESS;
117
118	    if(pixmap)
119		mode->flags |= DGA_PIXMAP_AVAILABLE;
120	    if(!pApm->NoAccel) {
121		mode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT;
122		if (Bpp != 3)
123		    mode->flags |= DGA_BLIT_RECT_TRANS;
124	    }
125	    if(pMode->Flags & V_DBLSCAN)
126		mode->flags |= DGA_DOUBLESCAN;
127	    if(pMode->Flags & V_INTERLACE)
128		mode->flags |= DGA_INTERLACED;
129	    mode->byteOrder = pScrn->imageByteOrder;
130	    mode->depth = depth;
131	    mode->bitsPerPixel = bitsPerPixel;
132	    mode->red_mask = red;
133	    mode->green_mask = green;
134	    mode->blue_mask = blue;
135	    mode->visualClass = visualClass;
136	    mode->viewportWidth = pMode->HDisplay;
137	    mode->viewportHeight = pMode->VDisplay;
138	    mode->xViewportStep = (bitsPerPixel == 24) ? 4 : 1;
139	    mode->yViewportStep = 1;
140	    mode->viewportFlags = DGA_FLIP_RETRACE;
141	    mode->offset = 0;
142	    mode->address = pApm->FbBase;
143	    mode->bytesPerScanline = pitch * Bpp;
144	    mode->imageWidth = pitch;
145	    mode->imageHeight =  (pScrn->videoRam * 1024 -
146			pApm->OffscreenReserved) / mode->bytesPerScanline;
147	    mode->pixmapWidth = mode->imageWidth;
148	    mode->pixmapHeight = mode->imageHeight;
149	    mode->maxViewportX = mode->imageWidth - mode->viewportWidth;
150	   /* this might need to get clamped to some maximum */
151	    mode->maxViewportY = mode->imageHeight - mode->viewportHeight;
152
153	    (*num)++;
154	}
155
156    }
157
158    if(secondPitch) {
159	secondPitch = 0;
160	goto SECOND_PASS;
161    }
162
163    if (reduced_pitch) {
164	reduced_pitch = FALSE;
165	goto SECOND_PASS;
166    }
167
168    return modes;
169}
170
171Bool
172ApmDGAInit(ScreenPtr pScreen)
173{
174   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
175   APMDECL(pScrn);
176   DGAModePtr modes = NULL;
177   int num = 0;
178
179   /* 8 */
180   modes = ApmSetupDGAMode (pScrn, modes, &num, 8, 8,
181		(pScrn->bitsPerPixel != 24),
182		(pScrn->bitsPerPixel != 8) ? 0 : pScrn->displayWidth,
183		0, 0, 0, PseudoColor);
184
185   /* 15 */
186   modes = ApmSetupDGAMode (pScrn, modes, &num, 16, 15,
187		(pScrn->bitsPerPixel != 24),
188		(pScrn->depth != 15) ? 0 : pScrn->displayWidth,
189		0x7C00, 0x03E0, 0x001F, TrueColor);
190
191   modes = ApmSetupDGAMode (pScrn, modes, &num, 16, 15,
192		(pScrn->bitsPerPixel != 24),
193		(pScrn->depth != 15) ? 0 : pScrn->displayWidth,
194		0x7C00, 0x03E0, 0x001F, DirectColor);
195
196   /* 16 */
197   modes = ApmSetupDGAMode (pScrn, modes, &num, 16, 16,
198		(pScrn->bitsPerPixel != 24),
199		(pScrn->depth != 16) ? 0 : pScrn->displayWidth,
200		0xF800, 0x07E0, 0x001F, TrueColor);
201
202   modes = ApmSetupDGAMode (pScrn, modes, &num, 16, 16,
203		(pScrn->bitsPerPixel != 24),
204		(pScrn->depth != 16) ? 0 : pScrn->displayWidth,
205		0xF800, 0x07E0, 0x001F, DirectColor);
206
207   /* 24 */
208   modes = ApmSetupDGAMode (pScrn, modes, &num, 24, 24,
209		(pScrn->bitsPerPixel == 24),
210		(pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth,
211		0xFF0000, 0x00FF00, 0x0000FF, TrueColor);
212
213   modes = ApmSetupDGAMode (pScrn, modes, &num, 24, 24,
214		(pScrn->bitsPerPixel == 24),
215		(pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth,
216		0xFF0000, 0x00FF00, 0x0000FF, DirectColor);
217
218   /* 32 */
219   modes = ApmSetupDGAMode (pScrn, modes, &num, 32, 24,
220		(pScrn->bitsPerPixel != 24),
221		(pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth,
222		0xFF0000, 0x00FF00, 0x0000FF, TrueColor);
223
224   modes = ApmSetupDGAMode (pScrn, modes, &num, 32, 24,
225		(pScrn->bitsPerPixel != 24),
226		(pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth,
227		0xFF0000, 0x00FF00, 0x0000FF, DirectColor);
228
229   pApm->numDGAModes = num;
230   pApm->DGAModes = modes;
231
232   return DGAInit(pScreen, &ApmDGAFuncs, modes, num);
233}
234
235
236static Bool
237ApmSetMode(ScrnInfoPtr pScrn, DGAModePtr pMode)
238{
239    APMDECL(pScrn);
240
241    if (!pMode) { /* restore the original mode */
242	if (pApm->DGAactive) {
243	    memcpy(&pApm->CurrentLayout, &pApm->SavedLayout,
244						sizeof pApm->CurrentLayout);
245	    pApm->DGAactive = FALSE;
246	}
247
248	pScrn->currentMode = pApm->CurrentLayout.pMode;
249        ApmSwitchMode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode));
250	ApmAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
251#if 0
252	if (pApm->AccelInfoRec)
253	    XAAInit(pScrn->pScreen, pApm->AccelInfoRec);
254#endif
255    }
256    else {
257	if (!pApm->DGAactive) {
258	    memcpy(&pApm->SavedLayout, &pApm->CurrentLayout,
259						sizeof pApm->CurrentLayout);
260	    pApm->DGAactive = TRUE;
261	}
262
263	pApm->CurrentLayout.displayWidth	= pMode->imageWidth;
264	pApm->CurrentLayout.displayHeight	= pMode->imageHeight;
265	pApm->CurrentLayout.Scanlines		= pMode->imageHeight + 1;
266	pApm->CurrentLayout.depth		= pMode->depth;
267	pApm->CurrentLayout.bitsPerPixel	= pMode->bitsPerPixel;
268	pApm->CurrentLayout.bytesPerScanline	= pMode->bytesPerScanline;
269	pApm->CurrentLayout.pMode		= pMode->mode;
270	if (pMode->bitsPerPixel == 24)
271	    pApm->CurrentLayout.mask32		= 3;
272	else
273	    pApm->CurrentLayout.mask32		= 32 / pMode->bitsPerPixel - 1;
274
275        ApmSwitchMode(SWITCH_MODE_ARGS(pScrn, pMode->mode));
276#ifdef HAVE_XAA_H
277	ApmSetupXAAInfo(pApm, NULL);
278#endif
279
280#if 0
281	if (pApm->DGAXAAInfo)
282	    bzero(pApm->DGAXAAInfo, sizeof(*pApm->DGAXAAInfo));
283	else
284	    pApm->DGAXAAInfo = XAACreateInfoRec();
285	ApmSetupXAAInfo(pApm, pApm->DGAXAAInfo);
286	/*
287	 * Let's hope this won't fail, that is reinitialize XAA for this
288	 * setup...
289	 */
290	XAAInit(pScrn->pScreen, pApm->DGAXAAInfo);
291#endif
292    }
293
294    return TRUE;
295}
296
297
298
299static int
300ApmGetViewport(
301  ScrnInfoPtr pScrn
302)
303{
304    return 0;
305}
306
307static void
308ApmSetViewport(
309    ScrnInfoPtr pScrn,
310    int x, int y,
311    int flags
312)
313{
314    unsigned char tmp;
315
316    APMDECL(pScrn);
317
318    if (pApm->apmLock) {
319	/*
320	 * This is just an attempt, because Daryll is tampering with MY
321	 * registers.
322	 */
323	tmp = (RDXB(0xDB) & 0xF4) |  0x0A;
324	WRXB(0xDB, tmp);
325	ApmWriteSeq(0x1B, 0x20);
326	ApmWriteSeq(0x1C, 0x2F);
327	pApm->apmLock = FALSE;
328    }
329    pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, x, y));
330    if (pApm->VGAMap) {
331	/* Wait until vertical retrace is in progress. */
332	while (APMVGAB(0x3DA) & 0x08);
333	while (!(APMVGAB(0x3DA) & 0x08));
334    }
335    else {
336	/* Wait until vertical retrace is in progress. */
337	while (inb(pApm->iobase + 0x3DA) & 0x08);
338	while (!(inb(pApm->iobase + 0x3DA) & 0x08));
339    }
340}
341
342#ifdef HAVE_XAA_H
343static void
344ApmFillRect (
345    ScrnInfoPtr pScrn,
346    int x, int y, int w, int h,
347    unsigned long color
348)
349{
350    APMDECL(pScrn);
351
352    if(pApm->CurrentLayout.depth != 24) {
353	(*pApm->SetupForSolidFill)(pScrn, color, GXcopy, ~0);
354	(*pApm->SubsequentSolidFillRect)(pScrn, x, y, w, h);
355    }
356    else {
357	(*pApm->SetupForSolidFill24)(pScrn, color, GXcopy, ~0);
358	(*pApm->SubsequentSolidFillRect24)(pScrn, x, y, w, h);
359    }
360    SET_SYNC_FLAG(pApm->AccelInfoRec);
361}
362
363static void
364ApmBlitRect(
365    ScrnInfoPtr pScrn,
366    int srcx, int srcy,
367    int w, int h,
368    int dstx, int dsty
369)
370{
371    APMDECL(pScrn);
372    int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
373    int ydir = (srcy < dsty) ? -1 : 1;
374
375    if(pApm->CurrentLayout.depth != 24) {
376	(*pApm->SetupForScreenToScreenCopy)(
377		pScrn, xdir, ydir, GXcopy, ~0, -1);
378	(*pApm->SubsequentScreenToScreenCopy)(
379		pScrn, srcx, srcy, dstx, dsty, w, h);
380    }
381    else {
382	(*pApm->SetupForScreenToScreenCopy24)(
383		pScrn, xdir, ydir, GXcopy, ~0, -1);
384	(*pApm->SubsequentScreenToScreenCopy24)(
385		pScrn, srcx, srcy, dstx, dsty, w, h);
386    }
387    SET_SYNC_FLAG(pApm->AccelInfoRec);
388}
389
390static void
391ApmBlitTransRect(
392    ScrnInfoPtr pScrn,
393    int srcx, int srcy,
394    int w, int h,
395    int dstx, int dsty,
396    unsigned long color
397)
398{
399    APMDECL(pScrn);
400
401    if(pApm->AccelInfoRec) {
402	int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
403	int ydir = (srcy < dsty) ? -1 : 1;
404
405	(*pApm->AccelInfoRec->SetupForScreenToScreenCopy)(
406		pScrn, xdir, ydir, GXcopy, ~0, (int)color);
407	(*pApm->AccelInfoRec->SubsequentScreenToScreenCopy)(
408		pScrn, srcx, srcy, dstx, dsty, w, h);
409	SET_SYNC_FLAG(pApm->AccelInfoRec);
410    }
411}
412#endif
413
414static Bool
415ApmOpenFramebuffer(
416    ScrnInfoPtr pScrn,
417    char **name,
418    unsigned char **mem,
419    int *size,
420    int *offset,
421    int *flags
422)
423{
424    APMDECL(pScrn);
425
426    *name = NULL; 		/* no special device */
427    *mem = (unsigned char*)(pApm->LinAddress +
428			0*((char *)pApm->FbBase - (char *)pApm->LinMap));
429    *size = pScrn->videoRam << 10;
430    *offset = 0;
431    *flags = DGA_NEED_ROOT;
432
433    return TRUE;
434}
435