1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include "xf86.h"
6#include "xf86_OSproc.h"
7#include "xf86Pci.h"
8#include "mga.h"
9#include "mga_reg.h"
10#include "dgaproc.h"
11
12
13static Bool MGA_OpenFramebuffer(ScrnInfoPtr, char **, unsigned char **,
14					int *, int *, int *);
15static Bool MGA_SetMode(ScrnInfoPtr, DGAModePtr);
16static int  MGA_GetViewport(ScrnInfoPtr);
17static void MGA_SetViewport(ScrnInfoPtr, int, int, int);
18#ifdef USE_XAA
19static void MGA_FillRect(ScrnInfoPtr, int, int, int, int, unsigned long);
20static void MGA_BlitRect(ScrnInfoPtr, int, int, int, int, int, int);
21static void MGA_BlitTransRect(ScrnInfoPtr, int, int, int, int, int, int,
22					unsigned long);
23#endif
24
25static
26DGAFunctionRec MGA_DGAFuncs = {
27   MGA_OpenFramebuffer,
28   NULL,
29   MGA_SetMode,
30   MGA_SetViewport,
31   MGA_GetViewport,
32   MGAStormSync,
33#ifdef USE_XAA
34   MGA_FillRect,
35   MGA_BlitRect,
36   MGA_BlitTransRect
37#else
38   NULL, NULL, NULL
39#endif
40};
41
42
43static int
44FindSmallestPitch(
45   MGAPtr pMga,
46   int Bpp,
47   int width
48){
49   int Pitches1[] =
50	  {640, 768, 800, 960, 1024, 1152, 1280, 1600, 1920, 2048, 0};
51   int Pitches2[] =
52	  {512, 640, 768, 800, 832, 960, 1024, 1152, 1280, 1600, 1664,
53		1920, 2048, 0};
54   int *linePitches = NULL;
55   int pitch;
56
57
58   if(!pMga->NoAccel) {
59	switch(pMga->Chipset) {
60	case PCI_CHIP_MGA2064:
61	    linePitches = Pitches1;
62	    break;
63	case PCI_CHIP_MGA2164:
64	case PCI_CHIP_MGA2164_AGP:
65	case PCI_CHIP_MGA1064:
66	    linePitches = Pitches2;
67	    break;
68	}
69   }
70
71   pitch = pMga->Roundings[Bpp - 1] - 1;
72
73   if(linePitches) {
74	while((*linePitches < width) || (*linePitches & pitch))
75	   linePitches++;
76	return *linePitches;
77   }
78
79   return ((width + pitch) & ~pitch);
80}
81
82static DGAModePtr
83MGASetupDGAMode(
84   ScrnInfoPtr pScrn,
85   DGAModePtr modes,
86   int *num,
87   int bitsPerPixel,
88   int depth,
89   Bool pixmap,
90   int secondPitch,
91   unsigned long red,
92   unsigned long green,
93   unsigned long blue,
94   short visualClass
95){
96   DisplayModePtr firstMode, pMode;
97   MGAPtr pMga = MGAPTR(pScrn);
98   DGAModePtr mode, newmodes;
99   int size, pitch, Bpp = bitsPerPixel >> 3;
100
101SECOND_PASS:
102
103   pMode = firstMode = pScrn->modes;
104
105   while(1) {
106
107
108	pitch = FindSmallestPitch(pMga, Bpp, pMode->HDisplay);
109	size = pitch * Bpp * pMode->VDisplay;
110
111	if((!secondPitch || (pitch != secondPitch)) &&
112		(size <= pMga->FbUsableSize)) {
113
114	    if(secondPitch)
115		pitch = secondPitch;
116
117	    if(!(newmodes = realloc(modes, (*num + 1) * sizeof(DGAModeRec))))
118		break;
119
120	    modes = newmodes;
121	    mode = modes + *num;
122
123	    mode->mode = pMode;
124	    mode->flags = DGA_CONCURRENT_ACCESS;
125            if(pixmap)
126		mode->flags |= DGA_PIXMAP_AVAILABLE;
127#ifdef USE_XAA
128	    if(!pMga->NoAccel) {
129		mode->flags |= DGA_FILL_RECT | DGA_BLIT_RECT;
130		if((Bpp != 3) && (pMga->Chipset != PCI_CHIP_MGA2064))
131		    mode->flags |= DGA_BLIT_RECT_TRANS;
132	    }
133#endif
134	    if(pMode->Flags & V_DBLSCAN)
135		mode->flags |= DGA_DOUBLESCAN;
136	    if(pMode->Flags & V_INTERLACE)
137		mode->flags |= DGA_INTERLACED;
138	    mode->byteOrder = pScrn->imageByteOrder;
139	    mode->depth = depth;
140	    mode->bitsPerPixel = bitsPerPixel;
141	    mode->red_mask = red;
142	    mode->green_mask = green;
143	    mode->blue_mask = blue;
144	    mode->visualClass = visualClass;
145	    mode->viewportWidth = pMode->HDisplay;
146	    mode->viewportHeight = pMode->VDisplay;
147	    mode->xViewportStep = (3 - pMga->BppShifts[Bpp - 1]);
148	    if((Bpp == 3) &&
149		    (pMga->Chipset == PCI_CHIP_MGAG400 || pMga->Chipset == PCI_CHIP_MGAG550))
150		mode->xViewportStep <<= 1;
151	    mode->yViewportStep = 1;
152	    mode->viewportFlags = DGA_FLIP_RETRACE;
153	    mode->offset = pMga->YDstOrg * Bpp;  /* gonna need to fix that */
154	    mode->address = pMga->FbStart;
155	    mode->bytesPerScanline = pitch * Bpp;
156	    mode->imageWidth = pitch;
157	    mode->imageHeight =  pMga->FbUsableSize / mode->bytesPerScanline;
158	    mode->pixmapWidth = pitch;
159	    switch (pMga->Chipset) {
160	    case PCI_CHIP_MGAG200_SE_A_PCI:
161	    case PCI_CHIP_MGAG200_SE_B_PCI:
162		mode->pixmapHeight = (min(pMga->FbUsableSize, 1*1024*1024)) /
163				     mode->bytesPerScanline;
164		break;
165	    default:
166		mode->pixmapHeight = (min(pMga->FbUsableSize, 16*1024*1024)) /
167				     mode->bytesPerScanline;
168	    }
169	    mode->maxViewportX = mode->imageWidth - mode->viewportWidth;
170	    mode->maxViewportY = (pMga->FbUsableSize / mode->bytesPerScanline) -
171				 	mode->viewportHeight;
172
173	    if( (pMga->Chipset == PCI_CHIP_MGA2064) ||
174		(pMga->Chipset == PCI_CHIP_MGA2164) ||
175		(pMga->Chipset == PCI_CHIP_MGA2164_AGP))
176	    {
177		int tmp;
178
179		tmp = (8*1024*1024 / mode->bytesPerScanline) -
180					mode->viewportHeight;
181		if(tmp < 0) tmp = 0;
182		if(tmp < mode->maxViewportY)
183		    mode->maxViewportY = tmp;
184	    }
185
186	    (*num)++;
187	}
188
189	pMode = pMode->next;
190	if(pMode == firstMode)
191	   break;
192    }
193
194    if(secondPitch) {
195	secondPitch = 0;
196	goto SECOND_PASS;
197    }
198
199    return modes;
200}
201
202
203Bool
204MGADGAInit(ScreenPtr pScreen)
205{
206   ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
207   MGAPtr pMga = MGAPTR(pScrn);
208   DGAModePtr modes = NULL;
209   int num = 0;
210
211   /* 8 */
212   modes = MGASetupDGAMode (pScrn, modes, &num, 8, 8,
213		(pScrn->bitsPerPixel == 8),
214		(pScrn->bitsPerPixel != 8) ? 0 : pScrn->displayWidth,
215		0, 0, 0, PseudoColor);
216
217   /* 15 */
218   modes = MGASetupDGAMode (pScrn, modes, &num, 16, 15,
219		(pScrn->bitsPerPixel == 16),
220		(pScrn->depth != 15) ? 0 : pScrn->displayWidth,
221		0x7c00, 0x03e0, 0x001f, TrueColor);
222
223   modes = MGASetupDGAMode (pScrn, modes, &num, 16, 15,
224		(pScrn->bitsPerPixel == 16),
225		(pScrn->depth != 15) ? 0 : pScrn->displayWidth,
226		0x7c00, 0x03e0, 0x001f, DirectColor);
227
228   /* 16 */
229   modes = MGASetupDGAMode (pScrn, modes, &num, 16, 16,
230		(pScrn->bitsPerPixel == 16),
231		(pScrn->depth != 16) ? 0 : pScrn->displayWidth,
232		0xf800, 0x07e0, 0x001f, TrueColor);
233
234   modes = MGASetupDGAMode (pScrn, modes, &num, 16, 16,
235		(pScrn->bitsPerPixel == 16),
236		(pScrn->depth != 16) ? 0 : pScrn->displayWidth,
237		0xf800, 0x07e0, 0x001f, DirectColor);
238
239   /* 24 */
240   modes = MGASetupDGAMode (pScrn, modes, &num, 24, 24,
241		(pScrn->bitsPerPixel == 24),
242		(pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth,
243		0xff0000, 0x00ff00, 0x0000ff, TrueColor);
244
245   modes = MGASetupDGAMode (pScrn, modes, &num, 24, 24,
246		(pScrn->bitsPerPixel == 24),
247		(pScrn->bitsPerPixel != 24) ? 0 : pScrn->displayWidth,
248		0xff0000, 0x00ff00, 0x0000ff, DirectColor);
249
250   /* 32 */
251   modes = MGASetupDGAMode (pScrn, modes, &num, 32, 24,
252		(pScrn->bitsPerPixel == 32),
253		(pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth,
254		0xff0000, 0x00ff00, 0x0000ff, TrueColor);
255
256   modes = MGASetupDGAMode (pScrn, modes, &num, 32, 24,
257		(pScrn->bitsPerPixel == 32),
258		(pScrn->bitsPerPixel != 32) ? 0 : pScrn->displayWidth,
259		0xff0000, 0x00ff00, 0x0000ff, DirectColor);
260
261   pMga->numDGAModes = num;
262   pMga->DGAModes = modes;
263
264   return DGAInit(pScreen, &MGA_DGAFuncs, modes, num);
265}
266
267
268static int
269BitsSet(unsigned long data)
270{
271   unsigned long mask;
272   int set = 0;
273
274   for(mask = 1; mask; mask <<= 1)
275        if(mask & data) set++;
276
277   return set;
278}
279
280/*
281 * This is not strictly required - but it will load a 'sane'
282 * palette when starting DGA.
283 */
284static void
285mgaDGASetPalette(ScrnInfoPtr pScrn)
286{
287    MGAPtr pMga = MGAPTR(pScrn);
288    MGARamdacPtr MGAdac = &pMga->Dac;
289    unsigned char DAC[256*3];
290    int i;
291
292    if (!MGAdac->RestorePalette)
293	return;
294
295    for (i = 0; i < 256; i++) {
296	DAC[i*3] = i;
297	DAC[i*3 + 1] = i;
298	DAC[i*3 + 2] = i;
299    }
300    MGAdac->RestorePalette(pScrn, DAC);
301}
302
303
304static Bool
305MGA_SetMode(
306   ScrnInfoPtr pScrn,
307   DGAModePtr pMode
308){
309   static MGAFBLayout SavedLayouts[MAXSCREENS];
310   int index = pScrn->pScreen->myNum;
311
312   MGAPtr pMga = MGAPTR(pScrn);
313
314   if(!pMode) { /* restore the original mode */
315      if(pMga->DGAactive)
316        memcpy(&pMga->CurrentLayout, &SavedLayouts[index], sizeof(MGAFBLayout));
317
318      pScrn->currentMode = pMga->CurrentLayout.mode;
319      pScrn->SwitchMode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode));
320      MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
321      pMga->DGAactive = FALSE;
322   } else {
323      if(!pMga->DGAactive) {  /* save the old parameters */
324	memcpy(&SavedLayouts[index], &pMga->CurrentLayout, sizeof(MGAFBLayout));
325	pMga->DGAactive = TRUE;
326      }
327      /* update CurrentLayout */
328      pMga->CurrentLayout.bitsPerPixel = pMode->bitsPerPixel;
329      pMga->CurrentLayout.depth = pMode->depth;
330      pMga->CurrentLayout.displayWidth = pMode->bytesPerScanline /
331                              (pMode->bitsPerPixel >> 3);
332      pMga->CurrentLayout.weight.red = BitsSet(pMode->red_mask);
333      pMga->CurrentLayout.weight.green = BitsSet(pMode->green_mask);
334      pMga->CurrentLayout.weight.blue = BitsSet(pMode->blue_mask);
335      /* MGAModeInit() will set the mode field */
336
337      pScrn->SwitchMode(SWITCH_MODE_ARGS(pScrn, pMode->mode));
338      /* not strictly required but nice */
339      mgaDGASetPalette(pScrn);
340   }
341
342   return TRUE;
343}
344
345
346
347static int
348MGA_GetViewport(
349  ScrnInfoPtr pScrn
350){
351    MGAPtr pMga = MGAPTR(pScrn);
352
353    return pMga->DGAViewportStatus;
354}
355
356static void
357MGA_SetViewport(
358   ScrnInfoPtr pScrn,
359   int x, int y,
360   int flags
361){
362   MGAPtr pMga = MGAPTR(pScrn);
363
364   MGAAdjustFrame(ADJUST_FRAME_ARGS(pScrn, x, y));
365   pMga->DGAViewportStatus = 0;  /* MGAAdjustFrame loops until finished */
366}
367
368#ifdef USE_XAA
369static void
370MGA_FillRect (
371   ScrnInfoPtr pScrn,
372   int x, int y, int w, int h,
373   unsigned long color
374){
375    MGAPtr pMga = MGAPTR(pScrn);
376
377    if(!pMga->AccelInfoRec) return;
378
379    mgaDoSetupForSolidFill(pScrn, color, GXcopy, ~0,
380			   pMga->CurrentLayout.bitsPerPixel);
381    (*pMga->AccelInfoRec->SubsequentSolidFillRect)(pScrn, x, y, w, h);
382
383    SET_SYNC_FLAG(pMga->AccelInfoRec);
384}
385
386static void
387MGA_BlitRect(
388   ScrnInfoPtr pScrn,
389   int srcx, int srcy,
390   int w, int h,
391   int dstx, int dsty
392){
393    MGAPtr pMga = MGAPTR(pScrn);
394    int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
395    int ydir = (srcy < dsty) ? -1 : 1;
396
397    if(!pMga->AccelInfoRec) return;
398
399    mgaDoSetupForScreenToScreenCopy( pScrn, xdir, ydir, GXcopy, ~0, -1,
400				     pMga->CurrentLayout.bitsPerPixel );
401
402    (*pMga->AccelInfoRec->SubsequentScreenToScreenCopy)(
403		pScrn, srcx, srcy, dstx, dsty, w, h);
404
405    SET_SYNC_FLAG(pMga->AccelInfoRec);
406}
407
408
409static void MGA_BlitTransRect( ScrnInfoPtr pScrn, int srcx, int srcy,
410			       int w, int h, int dstx, int dsty,
411			       unsigned long color )
412{
413    MGAPtr pMga = MGAPTR(pScrn);
414
415    if( (pMga->AccelInfoRec != NULL)
416	&& (pMga->CurrentLayout.bitsPerPixel != 24)
417	&& (pMga->Chipset != PCI_CHIP_MGA2064) ) {
418	const int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1;
419	const int ydir = (srcy < dsty) ? -1 : 1;
420
421	pMga->DrawTransparent = TRUE;
422
423	mgaDoSetupForScreenToScreenCopy( pScrn, xdir, ydir, GXcopy, ~0, color,
424					 pMga->CurrentLayout.bitsPerPixel );
425
426	pMga->DrawTransparent = FALSE;
427
428	(*pMga->AccelInfoRec->SubsequentScreenToScreenCopy)(
429	    pScrn, srcx, srcy, dstx, dsty, w, h);
430
431	SET_SYNC_FLAG(pMga->AccelInfoRec);
432    }
433}
434#endif
435
436static Bool
437MGA_OpenFramebuffer(
438   ScrnInfoPtr pScrn,
439   char **name,
440   unsigned char **mem,
441   int *size,
442   int *offset,
443   int *flags
444){
445    MGAPtr pMga = MGAPTR(pScrn);
446
447    *name = NULL; 		/* no special device */
448    *mem = (unsigned char*)pMga->FbAddress;
449    *size = pMga->FbMapSize;
450    *offset = 0;
451    *flags = DGA_NEED_ROOT;
452
453    return TRUE;
454}
455