1/*
2 *      Copyright 2001  Ani Joshi <ajoshi@unixbox.com>
3 *
4 *      XFree86 4.x driver for S3 chipsets
5 *
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that copyright
10 * notice and this permission notice appear in supporting documentation and
11 * that the name of Ani Joshi not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission.  Ani Joshi makes no representations
14 * about the suitability of this software for any purpose.  It is provided
15 * "as-is" without express or implied warranty.
16 *
17 * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 *
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "xf86.h"
33
34#include "miline.h"
35
36#include "s3.h"
37#include "s3_reg.h"
38
39#ifdef HAVE_XAA_H
40
41#if 0
42static Bool NicePattern;
43static int DashPatternSize;
44#define MAX_LINE_PATTERN_LENGTH	512
45#define LINE_PATTERN_START	((MAX_LINE_PATTERN_LENGTH >> 5) - 1)
46static CARD32 DashPattern[MAX_LINE_PATTERN_LENGTH >> 5];
47#endif
48
49
50static void S3Sync(ScrnInfoPtr pScrn)
51{
52	WaitIdle();
53}
54
55static void S3SetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop,
56				unsigned int planemask)
57{
58	S3Ptr pS3 = S3PTR(pScrn);
59
60	WaitQueue16_32(4,6);
61	SET_PIX_CNTL(0);
62	SET_FRGD_COLOR(color);
63	SET_FRGD_MIX(FSS_FRGDCOL | s3alu[rop]);
64	SET_WRT_MASK(planemask);
65}
66
67static void S3SubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y,
68				      int w, int h)
69{
70#ifdef S3_NEWMMIO
71	S3Ptr pS3 = S3PTR(pScrn);
72#endif
73
74	WaitQueue(5);
75	SET_CURPT((short)x, (short)y);
76	SET_AXIS_PCNT(w - 1, h - 1);
77	SET_CMD(CMD_RECT | DRAW | INC_X | INC_Y | WRTDATA);
78}
79
80
81static void S3SetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir,
82					 int ydir, int rop,
83					 unsigned int planemask,
84					 int trans_color)
85{
86	S3Ptr pS3 = S3PTR(pScrn);
87
88	pS3->BltDir = CMD_BITBLT | DRAW | WRTDATA;
89
90	if (xdir == 1)
91		pS3->BltDir |= INC_X;
92	if (ydir == 1)
93		pS3->BltDir |= INC_Y;
94
95	pS3->trans_color = trans_color;
96
97	WaitQueue16_32(3,4);
98	SET_PIX_CNTL(0);
99	SET_FRGD_MIX(FSS_BITBLT | s3alu[rop]);
100	SET_WRT_MASK(planemask);
101}
102
103
104static void S3SubsequentScreenToScreenCopy(ScrnInfoPtr pScrn,
105					   int srcx, int srcy,
106					   int dstx, int dsty,
107					   int w, int h)
108{
109	S3Ptr pS3 = S3PTR(pScrn);
110
111	w--;
112	h--;
113
114	if (!(pS3->BltDir & INC_Y)) {
115		srcy += h;
116		dsty += h;
117	}
118
119	if (!(pS3->BltDir & INC_X)) {
120		srcx += w;
121		dstx += w;
122	}
123
124	if (pS3->trans_color == -1) {
125		WaitQueue(7);
126		SET_CURPT((short)srcx, (short)srcy);
127		SET_DESTSTP((short)dstx, (short)dsty);
128		SET_AXIS_PCNT((short)w, (short)h);
129		SET_CMD(pS3->BltDir);
130	} else {
131		WaitQueue16_32(2,3);
132		SET_MULT_MISC(CMD_REG_WIDTH | 0x0100);
133		SET_COLOR_CMP(pS3->trans_color);
134
135		WaitQueue(8);
136		SET_CURPT((short)srcx, (short)srcy);
137		SET_DESTSTP((short)dstx, (short)dsty);
138		SET_AXIS_PCNT((short)w, (short)h);
139		SET_CMD(pS3->BltDir);
140		SET_MULT_MISC(CMD_REG_WIDTH);
141	}
142}
143
144#if 0
145static void S3SetupForColor8x8PatternFill(ScrnInfoPtr pScrn,
146					  int patx, int paty,
147					  int rop, unsigned int planemask,
148					  int trans_color)
149{
150	S3Ptr pS3 = S3PTR(pScrn);
151
152	pS3->trans_color = trans_color;
153
154	WaitQueue16_32(3,4);
155	SET_PIX_CNTL(0);
156	SET_FRGD_MIX(FSS_BITBLT | s3alu[rop]);
157	SET_WRT_MASK(planemask);
158}
159
160static void S3SubsequentColor8x8PatternFillRect(ScrnInfoPtr pScrn,
161					    	int patx, int paty,
162					    	int x, int y,
163					    	int w, int h)
164{
165	S3Ptr pS3 = S3PTR(pScrn);
166
167	if (pS3->trans_color == -1) {
168		WaitQueue(7);
169		SET_CURPT((short)patx, (short)paty);
170		SET_DESTSTP((short)x, (short)y);
171		SET_AXIS_PCNT(w - 1, h - 1);
172		SET_CMD(CMD_PFILL | DRAW | INC_Y | INC_X | WRTDATA);
173	} else {
174		WaitQueue16_32(2,3);
175		SET_MULT_MISC(CMD_REG_WIDTH | 0x0100);
176		SET_COLOR_CMP(pS3->trans_color);
177
178		WaitQueue(8);
179		SET_CURPT((short)patx, (short)paty);
180		SET_DESTSTP((short)x, (short)y);
181		SET_AXIS_PCNT(w - 1, h - 1);
182		SET_CMD(CMD_PFILL | DRAW | INC_Y | INC_X | WRTDATA);
183		SET_MULT_MISC(CMD_REG_WIDTH);
184	}
185}
186#endif
187
188#ifdef S3_NEWMMIO
189static void S3SetupForCPUToScreenColorExpandFill(ScrnInfoPtr pScrn,
190						 int fg, int bg,
191						 int rop,
192						 unsigned int planemask)
193{
194	S3Ptr pS3 = S3PTR(pScrn);
195
196	WaitQueue16_32(3,4);
197	if (bg == -1) {
198		if (pS3->ColorExpandBug) {
199			SET_MIX(FSS_FRGDCOL | s3alu[rop], BSS_BKGDCOL | MIX_XOR);
200			SET_BKGD_COLOR(0);
201		} else
202			SET_MIX(FSS_FRGDCOL | s3alu[rop], BSS_BKGDCOL | MIX_DST);
203	} else {
204		SET_MIX(FSS_FRGDCOL | s3alu[rop], BSS_BKGDCOL | s3alu[rop]);
205		SET_BKGD_COLOR(bg);
206	}
207
208	WaitQueue16_32(3,5);
209	SET_FRGD_COLOR(fg);
210	SET_WRT_MASK(planemask);
211	SET_PIX_CNTL(MIXSEL_EXPPC);
212}
213
214
215static void S3SubsequentCPUToScreenColorExpandFill32(ScrnInfoPtr pScrn,
216						     int x, int y,
217						     int w, int h,
218						     int skipleft)
219{
220	S3Ptr pS3 = S3PTR(pScrn);
221
222	WaitQueue(4);
223	SET_CURPT((short)x, (short)y);
224	SET_AXIS_PCNT((short)w-1, (short)h-1);
225
226	WaitIdle();
227	SET_CMD(CMD_RECT | BYTSEQ | _32BIT | PCDATA | DRAW |
228		PLANAR | INC_Y | INC_X | WRTDATA);
229}
230#endif
231
232#if 0
233#ifndef S3_NEWMMIO
234
235static void S3SetupForScanlineImageWriteNoMMIO(ScrnInfoPtr pScrn, int rop,
236					       unsigned int planemask,
237					       int trans_color,
238					       int bpp, int depth)
239{
240	S3Ptr pS3 = S3PTR(pScrn);
241
242	WaitQueue16_32(3,4)
243	SET_FRGD_MIX(FSS_PCDATA | s3alu[rop]);
244	SET_WRT_MASK(planemask);
245	SET_PIX_CNTL(0);
246}
247
248static void S3SubsequentScanlineImageWriteRectNoMMIO(ScrnInfoPtr pScrn,
249						     int x, int y,
250						     int w, int h,
251						     int skipleft)
252{
253	S3Ptr pS3 = S3PTR(pScrn);
254
255	pS3->imageWidth = w;
256	pS3->imageHeight = h;
257
258	WaitQueue(5);
259	SET_CURPT((short)x, (short)y);
260	SET_AXIS_PCNT((short)w-1, (short)h-1);
261	WaitIdle();
262	SET_CMD(CMD_RECT | BYTSEQ | _16BIT | INC_Y | INC_X | DRAW |
263		PCDATA | WRTDATA);
264}
265
266
267static void S3SubsequentImageWriteScanlineNoMMIO(ScrnInfoPtr pScrn,
268						 int bufno)
269{
270	S3Ptr pS3 = S3PTR(pScrn);
271	int i, j;
272	int w, h;
273	CARD16 *src = (CARD16 *)&pS3->imageBuffer;
274
275	w = pS3->imageWidth * pS3->s3Bpp;
276	h = pS3->imageHeight;
277
278	for(j=0; j<h; j++) {
279		for(i=0; i<(w & ~1); ) {
280			/* XXX not for 32bpp */
281			SET_PIX_TRANS_W(ldw_u(src));
282			src++;
283			i += 2;
284		}
285	}
286}
287
288#endif
289#endif
290
291
292static void S3SetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop,
293				unsigned int planemask)
294{
295	S3Ptr pS3 = S3PTR(pScrn);
296
297	WaitQueue16_32(4,6);
298	SET_PIX_CNTL(0);
299	SET_FRGD_COLOR(color);
300	SET_FRGD_MIX(FSS_FRGDCOL | s3alu[rop]);
301	SET_WRT_MASK(planemask);
302}
303
304
305static void S3SubsequentSolidBresenhamLine(ScrnInfoPtr pScrn,
306					   int x, int y,
307					   int major, int minor,
308					   int err, int len, int octant)
309{
310#ifdef S3_NEWMMIO
311	S3Ptr pS3 = S3PTR(pScrn);
312#endif
313	unsigned short cmd;
314	int error, e1, e2;
315
316	error = minor + err;
317	e1 = minor;   /* was: major, wrong (twini@xfree86.org) */
318	e2 = minor - major;
319
320	if (major) {
321		cmd = CMD_LINE | DRAW | WRTDATA | LASTPIX;
322
323		if (octant & YMAJOR)
324			cmd |= YMAJAXIS;
325		if (!(octant & XDECREASING))
326			cmd |= INC_X;
327		if (!(octant & YDECREASING))
328			cmd |= INC_Y;
329
330		WaitQueue(7);
331		SET_CURPT((short)x, (short)y);
332		SET_ERR_TERM((short)error);
333		SET_DESTSTP((short)e2, (short)e1);
334		SET_MAJ_AXIS_PCNT((short)len);
335		SET_CMD(cmd);
336	} else {
337		WaitQueue(4);
338		SET_CURPT((short)x, (short)y);
339		SET_MAJ_AXIS_PCNT((short)len-1);
340		SET_CMD(CMD_LINE | DRAW | LINETYPE | WRTDATA | VECDIR_270);
341	}
342}
343
344
345
346static void S3SubsequentSolidHorVertLine(ScrnInfoPtr pScrn,
347					 int x, int y, int len, int dir)
348{
349	if (dir == DEGREES_0)
350		S3SubsequentSolidFillRect(pScrn, x, y, len, 1);
351	else
352		S3SubsequentSolidFillRect(pScrn, x, y, 1, len);
353}
354
355
356#if 0
357
358static void S3SetupForDashedLine(ScrnInfoPtr pScrn,
359                                 int fg, int bg,
360                                 int rop, unsigned int planemask,
361                                 int len, unsigned char *pattern)
362{
363#ifdef S3_NEWMMIO
364	S3Ptr pS3 = S3PTR(pScrn);
365
366	S3SetupForCPUToScreenColorExpandFill(pScrn, bg, fg, rop, planemask);
367#endif
368
369	WaitQueue(4);
370
371	NicePattern = FALSE;
372
373	if (len <= 32) {
374		register CARD32 scratch = DashPattern[LINE_PATTERN_START];
375
376		if (len & (len - 1)) {
377			while (len < 16) {
378				scratch |= (scratch >> len);
379				len <<= 1;
380			}
381			scratch |= (scratch >> len);
382			DashPattern[LINE_PATTERN_START] = scratch;
383		} else {
384			switch (len) {
385				case 2:
386					scratch |= scratch >> 2;
387				case 4:
388					scratch |= scratch >> 4;
389				case 8:
390					scratch |= scratch >> 8;
391				case 16:
392					scratch |= scratch >> 16;
393					DashPattern[LINE_PATTERN_START] = scratch;
394				case 32:
395					NicePattern = TRUE;
396				default:
397					break;
398			}
399		}
400	}
401
402	DashPatternSize = len;
403}
404
405
406static void S3SubsequentDashedBresenhamLine32(ScrnInfoPtr pScrn,
407					      int x, int y,
408					      int absmaj, int absmin,
409					      int err, int len,
410					      int octant, int phase)
411{
412#ifdef S3_NEWMMIO
413	S3Ptr pS3 = S3PTR(pScrn);
414#endif
415	register int count = (len + 31) >> 5;
416	register CARD32 pattern;
417	int error, e1, e2;
418
419	error = absmin + err;
420	e1 = absmaj;
421	e2 = absmin - absmaj;
422
423	if (err) {
424		unsigned short cmd = _32BIT | PLANAR | WRTDATA | DRAW |
425				     PCDATA | LASTPIX | CMD_LINE;
426
427		if (octant & YMAJOR)
428			cmd |= YMAJAXIS;
429		if (!(octant & XDECREASING))
430			cmd |= INC_X;
431		if (!(octant & YDECREASING))
432			cmd |= INC_Y;
433
434		WaitQueue(7);
435		SET_CURPT((short)x, (short)y);
436		SET_ERR_TERM((short)error);
437		SET_DESTSTP((short)e2, (short)e1);
438		SET_MAJ_AXIS_PCNT((short)len);
439		SET_CMD(cmd);
440	} else {
441		if (octant & YMAJOR) {
442			WaitQueue(4);
443			SET_CURPT((short)x, (short)y);
444			SET_MAJ_AXIS_PCNT((short)len - 1);
445
446			if (octant & YDECREASING) {
447				SET_CMD(_32BIT | PLANAR | WRTDATA | DRAW |
448					CMD_LINE | LINETYPE | VECDIR_090);
449			} else {
450				SET_CMD(_32BIT | PLANAR | WRTDATA | DRAW |
451					CMD_LINE | LINETYPE | VECDIR_270);
452			}
453		} else {
454			if (octant & XDECREASING) {
455				WaitQueue(4);
456				SET_CURPT((short)x, (short)y);
457				SET_MAJ_AXIS_PCNT((short)len - 1);
458				SET_CMD(_32BIT | PLANAR | WRTDATA | DRAW |
459					PCDATA | CMD_LINE | LINETYPE | VECDIR_180);
460			} else {
461				WaitQueue(4);
462				SET_CURPT((short)x, (short)y);
463				SET_MAJ_AXIS_PCNT((short)len - 1);
464				SET_CMD(_32BIT | PLANAR | WRTDATA | DRAW |
465					PCDATA | CMD_RECT | INC_Y | INC_X);
466			}
467		}
468	}
469
470	if (NicePattern) {
471#ifdef S3_NEWMMIO
472		register CARD32 *dest = (CARD32*)&IMG_TRANS;
473#endif
474
475		pattern = (phase) ? (DashPattern[LINE_PATTERN_START] << phase) |
476			(DashPattern[LINE_PATTERN_START] >> (32 - phase)) :
477			 DashPattern[LINE_PATTERN_START];
478
479#ifdef S3_NEWMMIO
480		while (count & ~0x03) {
481			dest[0] = dest[1] = dest[2] = dest[3] = pattern;
482			dest += 4;
483			count -= 4;
484		}
485		switch (count) {
486		case 1:
487			dest[0] = pattern;
488			break;
489		case 2:
490			dest[0] = dest[1] = pattern;
491			break;
492		case 3:
493			dest[0] = dest[1] = dest[2] = pattern;
494			break;
495		}
496#else
497
498		while (count--)
499			SET_PIX_TRANS_L(pattern);
500#endif
501	} else if (DashPatternSize < 32) {
502		register int offset = phase;
503
504		while (count--) {
505			SET_PIX_TRANS_L((DashPattern[LINE_PATTERN_START] << offset) |
506				(DashPattern[LINE_PATTERN_START] >>
507				(DashPatternSize - offset)));
508			offset += 32;
509			while (offset > DashPatternSize)
510				offset -= DashPatternSize;
511		}
512	} else {
513		int offset = phase;
514		register unsigned char *srcp = (unsigned char *)(DashPattern) +
515			(MAX_LINE_PATTERN_LENGTH >> 3) - 1;
516		register CARD32 *scratch;
517		int scratch2, shift;
518
519		while (count--) {
520			shift = DashPatternSize - offset;
521			scratch = (CARD32*)(srcp - (offset >> 3) - 3);
522			scratch2 = offset & 0x07;
523
524			if (shift & ~31) {
525				if (scratch2) {
526					pattern = (*scratch << scratch2) |
527						  (*(scratch - 1) >> (32 - scratch2));
528				} else
529					pattern = *scratch;
530			} else {
531				pattern = (*((CARD32*)(srcp - 3)) >> shift) |
532					  (*scratch << scratch2);
533			}
534			SET_PIX_TRANS_L(pattern);
535			offset += 32;
536			while (offset >= DashPatternSize)
537				offset -= DashPatternSize;
538		}
539	}
540}
541
542#endif
543#endif
544
545#ifdef S3_NEWMMIO
546Bool S3AccelInitNewMMIO(ScreenPtr pScreen)
547#else
548Bool S3AccelInitPIO(ScreenPtr pScreen)
549#endif
550{
551#ifdef HAVE_XAA_H
552	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
553	S3Ptr pS3 = S3PTR(pScrn);
554	XAAInfoRecPtr pXAA;
555
556	if (pS3->Chipset == PCI_CHIP_968)
557		pS3->ColorExpandBug = TRUE;
558	else
559		pS3->ColorExpandBug = FALSE;
560
561	if (!(pXAA = XAACreateInfoRec()))
562		return FALSE;
563
564	pS3->pXAA = pXAA;
565
566	pXAA->Flags = (PIXMAP_CACHE | OFFSCREEN_PIXMAPS |
567		       LINEAR_FRAMEBUFFER);
568
569	pXAA->Sync = S3Sync;
570
571	pXAA->SetupForSolidFill = S3SetupForSolidFill;
572	pXAA->SubsequentSolidFillRect = S3SubsequentSolidFillRect;
573
574	pXAA->SetupForScreenToScreenCopy = S3SetupForScreenToScreenCopy;
575	pXAA->SubsequentScreenToScreenCopy = S3SubsequentScreenToScreenCopy;
576	pXAA->ScreenToScreenCopyFlags = NO_TRANSPARENCY;
577
578#if 0
579/*
580  8x8 color pattern filling doesn't work properly after introducing
581  framebuffer manager initialization before XAA initialization. There
582  are problems with addressing a colour patterns from offscreen area.
583*/
584	pXAA->SetupForColor8x8PatternFill = S3SetupForColor8x8PatternFill;
585	pXAA->SubsequentColor8x8PatternFillRect = S3SubsequentColor8x8PatternFillRect;
586	pXAA->Color8x8PatternFillFlags = NO_TRANSPARENCY |
587		HARDWARE_PATTERN_SCREEN_ORIGIN |
588		BIT_ORDER_IN_BYTE_MSBFIRST;
589
590	pXAA->CachePixelGranularity = 0;
591#endif
592
593#ifdef S3_NEWMMIO
594	pXAA->SetupForCPUToScreenColorExpandFill =
595		S3SetupForCPUToScreenColorExpandFill;
596	pXAA->SubsequentCPUToScreenColorExpandFill =
597		S3SubsequentCPUToScreenColorExpandFill32;
598	pXAA->ColorExpandBase = (void *) &IMG_TRANS;
599	pXAA->ColorExpandRange = 0x8000;
600	pXAA->CPUToScreenColorExpandFillFlags = CPU_TRANSFER_PAD_DWORD |
601						BIT_ORDER_IN_BYTE_MSBFIRST |
602						SCANLINE_PAD_DWORD;
603#endif
604
605#if 0
606#ifndef S3_NEWMMIO
607	pXAA->ScanlineImageWriteFlags = NO_TRANSPARENCY;
608	pXAA->SetupForScanlineImageWrite =
609		S3SetupForScanlineImageWriteNoMMIO;
610	pXAA->SubsequentScanlineImageWriteRect =
611		S3SubsequentScanlineImageWriteRectNoMMIO;
612	pXAA->SubsequentImageWriteScanline =
613		S3SubsequentImageWriteScanlineNoMMIO;
614	pXAA->NumScanlineImageWriteBuffers = 1;
615	pXAA->ScanlineImageWriteBuffers = &pS3->imageBuffer;
616#endif
617#endif
618
619	pXAA->SetupForSolidLine = S3SetupForSolidLine;
620	pXAA->SubsequentSolidBresenhamLine = S3SubsequentSolidBresenhamLine;
621	pXAA->SubsequentSolidHorVertLine = S3SubsequentSolidHorVertLine;
622	pXAA->SolidBresenhamLineErrorTermBits = 12;
623#if 0
624	/* kinda buggy...  and its faster without it */
625	pXAA->SetupForDashedLine = S3SetupForDashedLine;
626	pXAA->SubsequentDashedBresenhamLine = S3SubsequentDashedBresenhamLine32;
627	pXAA->DashPatternMaxLength = MAX_LINE_PATTERN_LENGTH;
628#endif
629
630	return XAAInit(pScreen, pXAA);
631#else
632	return FALSE;
633#endif
634}
635