s3_driver.c revision 4178061c
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 *	Credits:
27 *		Thomas Roell <roell@informatik.tu-muenchen.de>
28 *		Mark Vojkovich <markv@valinux.com>
29 *		Kevin E. Martin <martin@valinux.com>
30 *		   - and others for their work on the 3.x S3 driver
31 *
32 *		Dominik Behr
33 *		   - for various hardware donations
34 *
35 *
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#include "xf86.h"
43#include "xf86_OSproc.h"
44#include "xf86Pci.h"
45#include "xf86PciInfo.h"
46#include "xf86Resources.h"
47#include "xf86fbman.h"
48#include "xf86cmap.h"
49#include "xf86RAC.h"
50#include "compiler.h"
51#include "xaa.h"
52#include "mipointer.h"
53#include "micmap.h"
54#include "mibstore.h"
55#include "fb.h"
56#include "inputstr.h"
57#include "shadowfb.h"
58#include "IBM.h"
59#include "TI.h"
60
61#include "s3.h"
62#include "s3_reg.h"
63
64#define TRIO64_RAMDAC	0x8811
65
66
67short s3alu[16] =
68{
69	MIX_0,
70	MIX_AND,
71	MIX_SRC_AND_NOT_DST,
72	MIX_SRC,
73	MIX_NOT_SRC_AND_DST,
74	MIX_DST,
75	MIX_XOR,
76	MIX_OR,
77	MIX_NOR,
78	MIX_XNOR,
79	MIX_NOT_DST,
80	MIX_SRC_OR_NOT_DST,
81	MIX_NOT_SRC,
82	MIX_NOT_SRC_OR_DST,
83	MIX_NAND,
84	MIX_1,
85};
86
87
88/*
89 * Prototypes
90 */
91static const OptionInfoRec * S3AvailableOptions(int chipid, int busid);
92static void S3Identify(int flags);
93static Bool S3Probe(DriverPtr drv, int flags);
94static Bool S3PreInit(ScrnInfoPtr pScrn, int flags);
95static Bool S3EnterVT(int scrnIndex, int flags);
96static void S3LeaveVT(int scrnIndex, int flags);
97static void S3Save(ScrnInfoPtr pScrn);
98static Bool S3ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
99			 char **argv);
100static Bool S3MapMem(ScrnInfoPtr pScrn);
101static void S3UnmapMem(ScrnInfoPtr pScrn);
102static Bool S3ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
103static void S3AdjustFrame(int scrnIndex, int x, int y, int flags);
104Bool S3CloseScreen(int scrnIndex, ScreenPtr pScreen);
105Bool S3SaveScreen(ScreenPtr pScreen, int mode);
106static void S3FreeScreen(int scrnIndex, int flags);
107static void S3GenericLoadPalette(ScrnInfoPtr pScrn, int numColors,
108                                 int *indicies, LOCO *colors,
109                                 VisualPtr pVisual);
110static void S3Restore(ScrnInfoPtr pScrn);
111void S3BankZero(ScrnInfoPtr pScrn);
112void S3Regdump(ScrnInfoPtr pScrn);
113static void S3DisplayPowerManagementSet(ScrnInfoPtr pScrn,
114					int PowerManagementMode, int flags);
115
116
117
118_X_EXPORT DriverRec S3 =
119{
120	S3_VERSION,
121	DRIVER_NAME,
122	S3Identify,
123	S3Probe,
124	S3AvailableOptions,
125	NULL,
126	0
127};
128
129/* supported chipsets */
130static SymTabRec S3Chipsets[] = {
131	{ PCI_CHIP_964_0,	"964-0"},
132	{ PCI_CHIP_964_1,	"964-1"},
133	{ PCI_CHIP_968,		"968" },
134	{ PCI_CHIP_TRIO, 	"Trio32/64" },
135	{ PCI_CHIP_AURORA64VP,	"Aurora64V+" },
136	{ PCI_CHIP_TRIO64UVP, 		"Trio64UV+" },
137	{ PCI_CHIP_TRIO64V2_DXGX,	"Trio64V2/DX/GX" },
138	{ -1, NULL }
139};
140
141
142static PciChipsets S3PciChipsets[] = {
143	{ PCI_CHIP_964_0,	PCI_CHIP_964_0,		RES_SHARED_VGA },
144	{ PCI_CHIP_964_1,	PCI_CHIP_964_1,		RES_SHARED_VGA },
145	{ PCI_CHIP_968, 	PCI_CHIP_968, 		RES_SHARED_VGA },
146	{ PCI_CHIP_TRIO, 	PCI_CHIP_TRIO, 		RES_SHARED_VGA },
147	{ PCI_CHIP_AURORA64VP,	PCI_CHIP_AURORA64VP, 	RES_SHARED_VGA },
148	{ PCI_CHIP_TRIO64UVP,	PCI_CHIP_TRIO64UVP, 	RES_SHARED_VGA },
149	{ PCI_CHIP_TRIO64V2_DXGX,	PCI_CHIP_TRIO64V2_DXGX, 	RES_SHARED_VGA },
150	{ -1,			-1,	      		RES_UNDEFINED }
151};
152
153typedef enum {
154	OPTION_NOACCEL,
155	OPTION_HWCURS,
156	OPTION_SLOW_DRAM_REFRESH,
157	OPTION_SLOW_DRAM,
158	OPTION_SLOW_EDODRAM,
159	OPTION_SLOW_VRAM,
160	OPTION_XVIDEO,
161	OPTION_SHADOW_FB,
162	OPTION_ROTATE
163} S3Opts;
164
165static OptionInfoRec S3Options[] = {
166	{ OPTION_NOACCEL, "noaccel", OPTV_BOOLEAN, {0}, FALSE },
167	{ OPTION_HWCURS, "hwcursor", OPTV_BOOLEAN, {0}, FALSE },
168	{ OPTION_SLOW_DRAM_REFRESH, "slow_dram_refresh", OPTV_BOOLEAN, {0}, FALSE },
169	{ OPTION_SLOW_DRAM, "slow_dram", OPTV_BOOLEAN, {0}, FALSE },
170	{ OPTION_SLOW_EDODRAM, "slow_edodram", OPTV_BOOLEAN, {0}, FALSE },
171	{ OPTION_SLOW_VRAM, "slow_vram", OPTV_BOOLEAN, {0}, FALSE },
172	{ OPTION_XVIDEO, "XVideo", OPTV_BOOLEAN, {0}, FALSE },
173	{ OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE },
174	{ OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE },
175	{ -1, NULL, OPTV_NONE, {0}, FALSE }
176};
177
178RamDacSupportedInfoRec S3IBMRamdacs[] = {
179	{ IBM524_RAMDAC },
180	{ IBM524A_RAMDAC },
181	{ IBM526_RAMDAC },
182	{ IBM526DB_RAMDAC },
183	{ -1 }
184};
185
186static int s3AccelLinePitches[] = { 640, 800, 1024, 1280, 1600 };
187
188#ifdef XFree86LOADER
189
190MODULESETUPPROTO(S3Setup);
191
192static XF86ModuleVersionInfo S3VersRec = {
193        "s3",
194        MODULEVENDORSTRING,
195        MODINFOSTRING1,
196        MODINFOSTRING2,
197        XORG_VERSION_CURRENT,
198        VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
199        ABI_CLASS_VIDEODRV,
200        ABI_VIDEODRV_VERSION,
201        MOD_CLASS_VIDEODRV,
202        {0, 0, 0, 0}
203};
204
205
206_X_EXPORT XF86ModuleData s3ModuleData = { &S3VersRec, S3Setup, NULL };
207
208pointer S3Setup (pointer module, pointer opts, int *errmaj, int *errmin)
209{
210	static Bool setupDone = FALSE;
211
212        if (!setupDone) {
213                setupDone = TRUE;
214                xf86AddDriver(&S3, module, 0);
215                return (pointer) 1;
216        } else {
217                if (errmaj)
218                        *errmaj = LDR_ONCEONLY;
219                return NULL;
220        }
221}
222
223#endif /* XFree86LOADER */
224
225
226static Bool S3GetRec(ScrnInfoPtr pScrn)
227{
228        if (pScrn->driverPrivate)
229                return TRUE;
230
231        pScrn->driverPrivate = xnfcalloc(sizeof(S3Rec), 1);
232
233        return TRUE;
234}
235
236static void S3FreeRec(ScrnInfoPtr pScrn)
237{
238        if (!pScrn->driverPrivate)
239                return;
240
241        xfree(pScrn->driverPrivate);
242        pScrn->driverPrivate = NULL;
243}
244
245static const OptionInfoRec * S3AvailableOptions(int chipid, int busid)
246{
247        return S3Options;
248}
249
250static void S3Identify(int flags)
251{
252        xf86PrintChipsets("S3", "driver (version " DRIVER_VERSION " for S3 chipset",
253                          S3Chipsets);
254}
255
256static Bool S3Probe(DriverPtr drv, int flags)
257{
258	GDevPtr *devSections;
259	int i, *usedChips, numDevSections, numUsed;
260	Bool foundScreen = FALSE;
261
262	/* sanity check */
263	if ((numDevSections = xf86MatchDevice("s3", &devSections)) <= 0)
264                return FALSE;
265
266	/* XXX do ISA later...  some day in the distant future... */
267	numUsed = xf86MatchPciInstances("s3", PCI_VENDOR_S3,
268					S3Chipsets, S3PciChipsets,
269					devSections, numDevSections,
270					drv, &usedChips);
271
272	xfree(devSections);
273
274	if (numUsed <= 0)
275		return FALSE;
276
277	if (flags & PROBE_DETECT)
278		foundScreen = TRUE;
279	else for (i=0; i<numUsed; i++) {
280		ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
281
282		pScrn->driverVersion = VERSION_MAJOR;
283		pScrn->driverName = DRIVER_NAME;
284                pScrn->name = "s3";
285                pScrn->Probe = S3Probe;
286                pScrn->PreInit = S3PreInit;
287                pScrn->ScreenInit = S3ScreenInit;
288                pScrn->SwitchMode = S3SwitchMode;
289                pScrn->AdjustFrame = S3AdjustFrame;
290                pScrn->EnterVT = S3EnterVT;
291                pScrn->LeaveVT = S3LeaveVT;
292		pScrn->FreeScreen = S3FreeScreen;
293
294		foundScreen = TRUE;
295
296                xf86ConfigActivePciEntity(pScrn, usedChips[i], S3PciChipsets,
297                                          NULL, NULL, NULL, NULL, NULL);
298        }
299
300        xfree(usedChips);
301
302        return foundScreen;
303}
304
305static Bool S3PreInit(ScrnInfoPtr pScrn, int flags)
306{
307	EntityInfoPtr pEnt;
308	S3Ptr pS3;
309	vgaHWPtr hwp;
310	ClockRangePtr clockRanges;
311	rgb zeros = {0, 0, 0};
312	Gamma gzeros = {0.0, 0.0, 0.0};
313	int i, vgaCRIndex, vgaCRReg;
314	unsigned char tmp;
315	char *s;
316
317        if (flags & PROBE_DETECT)
318                return FALSE;
319
320        if (!xf86LoadSubModule(pScrn, "vgahw"))
321                return FALSE;
322
323        if (!vgaHWGetHWRec(pScrn))
324                return FALSE;
325
326        hwp = VGAHWPTR(pScrn);
327        vgaHWGetIOBase(hwp);
328
329        pScrn->monitor = pScrn->confScreen->monitor;
330
331        if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb))
332	    return FALSE;
333
334        switch (pScrn->depth) {
335	case 8:
336	case 15:
337	case 16:
338	case 24:
339		/* OK */
340		break;
341	default:
342		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
343			   "Given depth (%d) is not  supported by this driver\n",
344			   pScrn->depth);
345		return FALSE;
346        }
347
348        xf86PrintDepthBpp(pScrn);
349
350        if (pScrn->depth > 8) {
351                if (!xf86SetWeight(pScrn, zeros, zeros))
352                        return FALSE;
353        }
354
355        if (!xf86SetDefaultVisual(pScrn, -1))
356                return FALSE;
357
358        pScrn->progClock = TRUE;
359
360        if (!S3GetRec(pScrn))
361                return FALSE;
362
363	pS3 = S3PTR(pScrn);
364
365	pS3->s3Bpp = (pScrn->bitsPerPixel >> 3);
366
367        xf86CollectOptions(pScrn, NULL);
368        xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, S3Options);
369
370	pS3->XVideo = xf86ReturnOptValBool(S3Options, OPTION_XVIDEO, TRUE);
371	pS3->NoAccel = xf86ReturnOptValBool(S3Options, OPTION_NOACCEL, FALSE);
372	pS3->HWCursor = xf86ReturnOptValBool(S3Options, OPTION_HWCURS, FALSE);
373	pS3->SlowDRAMRefresh = xf86ReturnOptValBool(S3Options, OPTION_SLOW_DRAM_REFRESH, FALSE);
374	pS3->SlowDRAM = xf86ReturnOptValBool(S3Options, OPTION_SLOW_DRAM, FALSE);
375	pS3->SlowEDODRAM = xf86ReturnOptValBool(S3Options, OPTION_SLOW_EDODRAM, FALSE);
376	pS3->SlowVRAM = xf86ReturnOptValBool(S3Options, OPTION_SLOW_VRAM, FALSE);
377
378
379
380	if (xf86GetOptValBool(S3Options, OPTION_SHADOW_FB, &pS3->shadowFB))
381		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n",
382			   pS3->shadowFB ? "enabled" : "disabled");
383
384	pS3->rotate = 0;
385	if ((s = xf86GetOptValString(S3Options, OPTION_ROTATE))) {
386		if(!xf86NameCmp(s, "CW")) {
387			/* accel is disabled below for shadowFB */
388			pS3->shadowFB = TRUE;
389			pS3->rotate = 1;
390			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
391				   "Rotating screen clockwise - acceleration disabled\n");
392		} else if(!xf86NameCmp(s, "CCW")) {
393			pS3->shadowFB = TRUE;
394			pS3->rotate = -1;
395			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
396				   "counter clockwise - acceleration disabled\n");
397		} else {
398			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
399				   "value for Option \"Rotate\"\n", s);
400			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
401				   "Valid options are \"CW\" or \"CCW\"\n");
402		}
403	}
404
405	if(pS3->shadowFB && !pS3->NoAccel) {
406		pS3->NoAccel = TRUE;
407		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
408			   "HW acceleration not supported with \"shadowFB\".\n");
409	}
410
411
412	if (pS3->rotate && pS3->HWCursor) {
413		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
414			   "HW cursor not supported with \"rotate\".\n");
415		pS3->HWCursor = FALSE;
416	}
417
418
419        if (pScrn->numEntities > 1) {
420                S3FreeRec(pScrn);
421                return FALSE;
422        }
423
424        pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
425        if (pEnt->resources) {
426                xfree(pEnt);
427                S3FreeRec(pScrn);
428                return FALSE;
429        }
430
431	if (xf86LoadSubModule(pScrn, "int10")) {
432		pS3->pInt10 = xf86InitInt10(pEnt->index);
433	}
434
435	if (xf86LoadSubModule(pScrn, "vbe")) {
436		pS3->pVBE = VBEInit(pS3->pInt10, pEnt->index);
437	}
438
439	if (pS3->shadowFB) {
440		if (!xf86LoadSubModule(pScrn, "shadowfb")) {
441			S3FreeRec(pScrn);
442			return FALSE;
443		}
444	}
445
446	if (!xf86SetGamma(pScrn, gzeros))
447		return FALSE;
448
449        pS3->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
450        xf86RegisterResources(pEnt->index, NULL, ResNone);
451	/* don't disable PIO funcs */
452        xf86SetOperatingState(resVgaMemShared, pEnt->index, ResDisableOpr);
453
454        if (pEnt->device->chipset && *pEnt->device->chipset) {
455                pScrn->chipset = pEnt->device->chipset;
456                pS3->Chipset = xf86StringToToken(S3Chipsets, pScrn->chipset);
457        } else if (pEnt->device->chipID >= 0) {
458                pS3->Chipset = pEnt->device->chipID;
459                pScrn->chipset = (char *)xf86TokenToString(S3Chipsets,
460                                                           pS3->Chipset);
461                xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
462			   "ChipID override: 0x%04X\n", pS3->Chipset);
463        } else {
464  	        pS3->Chipset = PCI_DEV_DEVICE_ID(pS3->PciInfo);
465                pScrn->chipset = (char *)xf86TokenToString(S3Chipsets,
466                                                           pS3->Chipset);
467        }
468        if (pEnt->device->chipRev >= 0) {
469                pS3->ChipRev = pEnt->device->chipRev;
470                xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
471                           pS3->ChipRev);
472        } else
473	        pS3->ChipRev = PCI_DEV_REVISION(pS3->PciInfo);
474
475        xfree(pEnt);
476
477        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Chipset: \"%s\"\n",
478		   pScrn->chipset);
479
480#ifndef XSERVER_LIBPCIACCESS
481        pS3->PciTag = pciTag(pS3->PciInfo->bus, pS3->PciInfo->device,
482                             pS3->PciInfo->func);
483#endif
484
485	switch (pS3->Chipset) {
486	case PCI_CHIP_964_0:
487	case PCI_CHIP_964_1:
488	case PCI_CHIP_TRIO:
489		if (pS3->ChipRev >= 0x40) { /* S3 Trio64V+ has the New MMIO */
490			pS3->S3NewMMIO = TRUE;
491			break;
492		}
493	case PCI_CHIP_AURORA64VP:		/* ??? */
494		pS3->S3NewMMIO = FALSE;
495		break;
496	case PCI_CHIP_TRIO64V2_DXGX:
497	case PCI_CHIP_TRIO64UVP:
498	case PCI_CHIP_968:
499		pS3->S3NewMMIO = TRUE;
500		break;
501	}
502
503	/* TODO: Streams Processor and Xv for Old MMIO */
504
505	if (((pS3->Chipset == PCI_CHIP_AURORA64VP) ||
506	     (pS3->Chipset == PCI_CHIP_TRIO64UVP) ||
507	     (pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX) ||
508	     ((pS3->Chipset == PCI_CHIP_TRIO) && (pS3->ChipRev >= 0x40)))
509	    && (pS3->S3NewMMIO))
510        	pS3->hasStreams = TRUE;
511        else
512        	pS3->hasStreams = FALSE;
513
514	pS3->FBAddress = PCI_REGION_BASE(pS3->PciInfo, 0, REGION_MEM);
515	pScrn->memPhysBase = pS3->FBAddress;
516	pScrn->fbOffset = 0;
517
518	if (pS3->S3NewMMIO)
519		pS3->IOAddress = pS3->FBAddress + S3_NEWMMIO_REGBASE;
520
521	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Framebuffer @ 0x%lx\n",
522		   pS3->FBAddress);
523	if (pS3->S3NewMMIO)
524		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MMIO @ 0x%lx\n",
525			   pS3->IOAddress);
526
527	pS3->PCIRetry = FALSE;		/* not supported yet */
528
529	pS3->vgaCRIndex = vgaCRIndex = hwp->IOBase + 4;
530	pS3->vgaCRReg = vgaCRReg = hwp->IOBase + 5;
531
532	/* unlock sys regs */
533	outb(vgaCRIndex, 0x38);
534	outb(vgaCRReg, 0x48);
535	outb(vgaCRIndex, 0x39);
536	outb(vgaCRReg, 0xa5);
537
538	outb(vgaCRIndex, 0x40);
539	tmp = inb(vgaCRReg) | 0x01;
540	outb(vgaCRReg, tmp);
541	outb(vgaCRIndex, 0x35);
542	tmp = inb(vgaCRReg) & ~0x30;
543	outb(vgaCRReg, tmp);
544
545	outb(0x3c4, 0x08);
546	outb(0x3c5, 0x06);
547	outb(vgaCRIndex, 0x33);
548	tmp = (inb(vgaCRReg) & ~(0x2 | 0x10 | 0x40)) | 0x20;
549	outb(vgaCRReg, tmp);
550
551	/* unprotect CRTC[0-7] */
552	outb(vgaCRIndex, 0x11);
553	tmp = inb(vgaCRReg) & 0x7f;
554	outb(vgaCRReg, tmp);
555
556	/* wake up */
557	outb(0x46e8, 0x10);
558	outb(0x102, 0x01);
559	outb(0x46e8, 0x08);
560
561	if (pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX)
562	{
563          /* disable DAC power saving to avoid bright left edge */
564	  outb (0x3d4, 0x86);
565	  outb (0x3d5, 0x80);
566	  /* disable the stream display fetch length control */
567	  outb (0x3d4, 0x90);
568	  outb (0x3d5, 0x00);
569	}
570
571	if (!pScrn->videoRam) {
572		/* probe videoram */
573		outb(vgaCRIndex, 0x36);
574		tmp = inb(vgaCRReg);
575
576		switch ((tmp & 0xe0) >> 5) {
577		case 0:
578			pScrn->videoRam = 4096;
579			break;
580		case 2:
581			pScrn->videoRam = 3072;
582			break;
583		case 3:
584			pScrn->videoRam = 8192;
585			break;
586		case 4:
587			pScrn->videoRam = 2048;
588			break;
589		case 5:
590			pScrn->videoRam = 6144;
591			break;
592		case 6:
593			pScrn->videoRam = 1024;
594			break;
595		}
596		xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
597			   "videoRam = %d Kb\n", pScrn->videoRam);
598	} else {
599		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
600			   "videoRam = %d Kb\n", pScrn->videoRam);
601	}
602
603	if (!xf86LoadSubModule(pScrn, "ramdac"))
604		return FALSE;
605
606	pScrn->rgbBits = 8;	/* set default */
607
608	/* probe for dac */
609	if (S3TiDACProbe(pScrn)) {
610		pS3->DacPreInit = S3TiDAC_PreInit;
611		pS3->DacInit = S3TiDAC_Init;
612		pS3->DacSave = S3TiDAC_Save;
613		pS3->DacRestore = S3TiDAC_Restore;
614#if 0
615		/* FIXME, cursor is drawn in wrong position */
616		pS3->CursorInit = S3Ti_CursorInit;
617#endif
618		pS3->MaxClock = 135000;
619		pScrn->rgbBits = 8;
620		if (pScrn->bitsPerPixel > 8)
621			pS3->LoadPalette = S3TiLoadPalette;
622		else
623			pS3->LoadPalette = S3GenericLoadPalette;
624	}
625	if (S3ProbeIBMramdac(pScrn)) {
626		pS3->DacPreInit = S3IBMRGB_PreInit;
627		pS3->DacInit = S3IBMRGB_Init;
628		pS3->DacSave = S3IBMRGB_Save;
629		pS3->DacRestore = S3IBMRGB_Restore;
630		pS3->CursorInit = S3IBMRGB_CursorInit;
631		pS3->RamDac->SetBpp = IBMramdac526SetBppWeak();
632		pS3->MaxClock = 170000;
633		pScrn->rgbBits = 8;
634		pS3->LoadPalette = S3GenericLoadPalette;
635	}
636	if (S3Trio64DACProbe(pScrn)) {
637		pS3->DacPreInit = S3Trio64DAC_PreInit;
638		pS3->DacInit = S3Trio64DAC_Init;
639		pS3->DacSave = S3Trio64DAC_Save;
640		pS3->DacRestore = S3Trio64DAC_Restore;
641#if 0
642		pS3->CursorInit = S3_CursorInit;	/* FIXME broken */
643#endif
644		switch(pScrn->bitsPerPixel) {
645		case 8:
646			if (pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX)
647				pS3->MaxClock = 170000;
648			else
649				pS3->MaxClock = 135000;
650
651			pScrn->rgbBits = 6;
652			break;
653		case 16:
654			pS3->MaxClock = 80000;
655			pScrn->rgbBits = 6;
656			break;
657		case 24:
658		case 32:
659			if (pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX)
660				pS3->MaxClock = 56700;
661			else
662				pS3->MaxClock = 50000;
663
664			pScrn->rgbBits = 8;
665			break;
666		}
667
668		pS3->LoadPalette = S3GenericLoadPalette;
669	}
670
671	if (pS3->RamDac == NULL) {
672		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
673			   "Ramdac probe failed\n");
674		return FALSE;
675	}
676
677	if (!pS3->HWCursor)
678		pS3->CursorInit = NULL;
679
680	pS3->RefClock = S3GetRefClock(pScrn);
681
682	if (pS3->DacPreInit)
683		pS3->DacPreInit(pScrn);
684
685	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "RefClock: %d\n",
686		   pS3->RefClock);
687	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Max pixel clock at this depth is %d Mhz\n",
688		   pS3->MaxClock / 1000);
689
690	clockRanges = xnfcalloc(sizeof(ClockRange), 1);
691	clockRanges->next = NULL;
692	clockRanges->minClock = 15600;
693	clockRanges->maxClock = pS3->MaxClock;
694	clockRanges->clockIndex = -1;
695	clockRanges->interlaceAllowed = TRUE;	/* not yet */
696	clockRanges->doubleScanAllowed = TRUE;	/* not yet */
697
698        i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
699                              pScrn->display->modes, clockRanges,
700                              pS3->NoAccel ? NULL : s3AccelLinePitches,
701			      256, 2048,
702			      pScrn->bitsPerPixel, 128, 2048,
703			      pScrn->display->virtualX,
704			      pScrn->display->virtualY, pScrn->videoRam * 1024,
705                              LOOKUP_BEST_REFRESH);
706
707        if (i == -1) {
708                xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "no valid modes left\n");
709                S3FreeRec(pScrn);
710                return FALSE;
711        }
712
713        xf86PruneDriverModes(pScrn);
714
715        if (i == 0 || pScrn->modes == NULL) {
716                xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "no valid modes found\n");
717                S3FreeRec(pScrn);
718                return FALSE;
719        }
720
721        xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
722        pScrn->currentMode = pScrn->modes;
723        xf86PrintModes(pScrn);
724        xf86SetDpi(pScrn, 0, 0);
725
726        xf86LoadSubModule(pScrn, "fb");
727
728	if (!xf86LoadSubModule(pScrn, "xaa"))
729		return FALSE;
730
731	return TRUE;
732}
733
734
735static Bool S3ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
736			 char **argv)
737{
738	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
739	S3Ptr pS3 = S3PTR(pScrn);
740	BoxRec ScreenArea;
741	int width, height, displayWidth;
742
743	if (pS3->rotate) {
744		height = pScrn->virtualX;
745		width = pScrn->virtualY;
746	} else {
747		width = pScrn->virtualX;
748		height = pScrn->virtualY;
749	}
750
751
752	pScrn->fbOffset = 0;
753
754	if (!S3MapMem(pScrn)) {
755		S3FreeRec(pScrn);
756		return FALSE;
757	}
758
759	S3Save(pScrn);
760
761	vgaHWBlankScreen(pScrn, TRUE);
762
763	if (!S3ModeInit(pScrn, pScrn->currentMode))
764		return FALSE;
765#if 0
766	S3Regdump(pScrn);
767#endif
768	pScrn->vtSema = TRUE;
769
770	S3SaveScreen(pScreen, SCREEN_SAVER_ON);
771
772        miClearVisualTypes();
773        if (pScrn->bitsPerPixel > 8) {
774                if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
775                                      pScrn->rgbBits, pScrn->defaultVisual))
776                        return FALSE;
777        } else {
778                if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
779                                      pScrn->rgbBits, pScrn->defaultVisual))
780                        return FALSE;
781        }
782
783        miSetPixmapDepths ();
784
785        /* no screen rotation assumed */
786        if(pS3->shadowFB) {
787        	pS3->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
788        	pS3->ShadowPtr = xalloc(pS3->ShadowPitch * height);
789		displayWidth = pS3->ShadowPitch / (pScrn->bitsPerPixel >> 3);
790        } else {
791        	pS3->ShadowPtr = NULL;
792		displayWidth = pScrn->displayWidth;
793        }
794
795        if (!fbScreenInit(pScreen, (pS3->shadowFB ? pS3->ShadowPtr : pS3->FBBase),
796			  pScrn->virtualX,
797                          pScrn->virtualY, pScrn->xDpi, pScrn->yDpi,
798                          pScrn->displayWidth, pScrn->bitsPerPixel))
799                return FALSE;
800
801        xf86SetBlackWhitePixels(pScreen);
802
803        if (pScrn->bitsPerPixel > 8) {
804                VisualPtr pVis;
805
806                pVis = pScreen->visuals + pScreen->numVisuals;
807                while (--pVis >= pScreen->visuals) {
808                        if ((pVis->class | DynamicClass) == DirectColor) {
809                                pVis->offsetRed = pScrn->offset.red;
810                                pVis->offsetGreen = pScrn->offset.green;
811                                pVis->offsetBlue = pScrn->offset.blue;
812                                pVis->redMask = pScrn->mask.red;
813                                pVis->greenMask = pScrn->mask.green;
814                                pVis->blueMask = pScrn->mask.blue;
815                        }
816                }
817        }
818	fbPictureInit (pScreen, 0, 0);
819	S3DGAInit(pScreen);
820
821        miInitializeBackingStore(pScreen);
822        xf86SetBackingStore(pScreen);
823
824	/* framebuffer manager setup */
825	ScreenArea.x1 = 0;
826	ScreenArea.y1 = 0;
827	ScreenArea.x2 = pScrn->displayWidth;
828	ScreenArea.y2 = (pScrn->videoRam * 1024) / pS3->s3BppDisplayWidth;
829
830	if (!xf86InitFBManager(pScreen, &ScreenArea)) {
831		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
832			   "Memory manager initialization to (%d,%d) (%d,%d) failed\n",
833			   ScreenArea.x1, ScreenArea.y1,
834			   ScreenArea.x2, ScreenArea.y2);
835		return FALSE;
836	} else
837		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
838			   "Memory manager initialized to (%d,%d) (%d,%d)\n",
839			   ScreenArea.x1, ScreenArea.y1,
840			   ScreenArea.x2, ScreenArea.y2);
841
842	/* 2D acceleration setup */
843
844	if (pS3->NoAccel)
845		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
846			   "Acceleration disabled (by option)\n");
847
848	/* It seems that acceleration isn't supported for 24-bit packed
849	   colour. So disable it. Using shadowFB is recommended in this mode. */
850	if (!pS3->NoAccel && (pScrn->bitsPerPixel == 24)) {
851		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "HW acceleration isn't supported for 24 bpp. Disabled.\n");
852		pS3->NoAccel = TRUE;
853	}
854
855
856	if (!pS3->NoAccel) {
857		if (pS3->S3NewMMIO)
858			if (S3AccelInitNewMMIO(pScreen)) {
859				xf86DrvMsg(pScrn->scrnIndex, X_INFO,
860					   "Acceleration enabled\n");
861				xf86DrvMsg(pScrn->scrnIndex, X_INFO,
862					   "Using NewMMIO\n");
863			} else {
864				xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
865					   "Acceleration initialization failed\n");
866				xf86DrvMsg(pScrn->scrnIndex, X_INFO,
867					   "Acceleration disabled\n");
868			}
869		else {
870			if (S3AccelInitPIO(pScreen)) {
871				xf86DrvMsg(pScrn->scrnIndex, X_INFO,
872					   "Acceleration enabled\n");
873				xf86DrvMsg(pScrn->scrnIndex, X_INFO,
874					   "Using PIO\n");
875			} else {
876				xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
877					   "Acceleration initialization failed\n");
878				xf86DrvMsg(pScrn->scrnIndex, X_INFO,
879					   "Acceleration disabled\n");
880			}
881		}
882	}
883
884        miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
885
886	/* HW cursor setup */
887
888	if (pS3->CursorInit) {
889		if (pS3->CursorInit(pScreen))
890			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using HW cursor\n");
891		else {
892			xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "HW cursor initialization failed\n");
893			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using SW cursor\n");
894		}
895	} else
896		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using SW cursor\n");
897
898
899	/* Shadow framebuffer setup */
900
901	if (pS3->shadowFB) {
902		RefreshAreaFuncPtr refreshArea = S3RefreshArea;
903
904		if (pS3->rotate) {
905			if (!pS3->PointerMoved) {
906				pS3->PointerMoved = pScrn->PointerMoved;
907				pScrn->PointerMoved = S3PointerMoved;
908			}
909
910			switch (pScrn->bitsPerPixel) {
911			case 8: refreshArea = S3RefreshArea8; break;
912			case 16: refreshArea = S3RefreshArea16; break;
913			case 24: refreshArea = S3RefreshArea24; break;
914			case 32: refreshArea = S3RefreshArea32; break;
915			}
916		}
917
918		ShadowFBInit(pScreen, refreshArea);
919	}
920
921
922
923        if (!miCreateDefColormap(pScreen))
924                return FALSE;
925
926        if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits,
927				 pS3->LoadPalette, NULL,
928                                 CMAP_RELOAD_ON_MODE_SWITCH))
929                return FALSE;
930
931	vgaHWBlankScreen(pScrn, FALSE);
932
933        pScreen->SaveScreen = S3SaveScreen;
934        pS3->CloseScreen = pScreen->CloseScreen;
935        pScreen->CloseScreen = S3CloseScreen;
936
937	xf86DPMSInit(pScreen, S3DisplayPowerManagementSet, 0);
938
939	/* XXX Check if I/O and Mem flags need to be the same. */
940	pScrn->racIoFlags = pScrn->racMemFlags = RAC_COLORMAP
941	    | RAC_FB | RAC_VIEWPORT | RAC_CURSOR;
942
943	if (pS3->SlowEDODRAM)
944		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
945			   "SlowEDODRAM: Setting 2-cycle EDO\n");
946
947	if (pS3->SlowVRAM)
948		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
949			   "SlowVRAM: -RAS low time is 4.5 MCLKs\n");
950
951	if (pS3->SlowDRAM)
952		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
953			   "SlowDRAM: -RAS precharge time is 3.5 MCLKs\n");
954
955	if (pS3->SlowDRAMRefresh)
956		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
957			   "SlowDRAMRefresh: three refresh cycles per scanline\n");
958
959	/* XVideo setup */
960
961	if (pS3->XVideo) {
962		if (!pS3->hasStreams) {
963			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Overlay video isn't supported by video hardware. Disabled.\n");
964			pS3->XVideo = FALSE;
965		} else if (pScrn->bitsPerPixel < 16) {
966			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Overlay video isn't supported for %d bpp. Disabled.\n", pScrn->bitsPerPixel);
967			pS3->XVideo = FALSE;
968		}
969	} else
970		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
971			   "Overlay video disabled by option\n");
972
973	/* At present time we support XV only for chips with New MMIO */
974	if ((pS3->XVideo) && (pS3->S3NewMMIO))
975		S3InitVideo(pScreen);
976
977	switch (pScrn->bitsPerPixel) {
978	case 8:
979		pS3->Streams_FIFO = FIFO_PS16_SS8;
980		break;
981	case 15:
982	case 16:
983		pS3->Streams_FIFO = FIFO_PS12_SS12;
984		break;
985	case 24:
986	case 32:
987		pS3->Streams_FIFO = FIFO_PS8_SS16;
988		break;
989	}
990
991        return TRUE;
992}
993
994
995
996
997static void S3Save(ScrnInfoPtr pScrn)
998{
999	S3Ptr pS3 = S3PTR(pScrn);
1000	S3RegPtr save = &pS3->SavedRegs;
1001	vgaHWPtr hwp = VGAHWPTR(pScrn);
1002        vgaRegPtr pVga = &hwp->SavedReg;
1003	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
1004	int i;
1005	unsigned char cr5c = 0;
1006
1007	S3BankZero(pScrn);
1008
1009	save->clock = inb(0x3cc);
1010
1011	vgaHWSave(pScrn, pVga, VGA_SR_ALL);
1012
1013	if (pS3->RamDac->RamDacType == TI3025_RAMDAC) {
1014		outb(vgaCRIndex, 0x5c);
1015		cr5c = inb(vgaCRReg);
1016	}
1017
1018	pS3->DacSave(pScrn);
1019
1020	for(i=0; i<5; i++) {
1021		outb(vgaCRIndex, 0x30 + i);
1022		save->s3save[i] = inb(vgaCRReg);
1023		outb(vgaCRIndex, 0x38 + i);
1024		save->s3save[5 + i] = inb(vgaCRReg);
1025	}
1026
1027	for (i=0; i<16; i++) {
1028		outb(vgaCRIndex, 0x40 + i);
1029		save->s3syssave[i] = inb(vgaCRReg);
1030	}
1031
1032	outb(vgaCRIndex, 0x45);
1033	inb(vgaCRReg);
1034	outb(vgaCRIndex, 0x4a);
1035	for(i=0; i<4; i++) {
1036		save->color_stack[i] = inb(vgaCRReg);
1037		outb(vgaCRReg, save->color_stack[i]);
1038	}
1039
1040	outb(vgaCRIndex, 0x45);
1041	inb(vgaCRReg);
1042	outb(vgaCRIndex, 0x4b);
1043	for(i=4; i<8; i++) {
1044		save->color_stack[i] = inb(vgaCRReg);
1045		outb(vgaCRReg, save->color_stack[i]);
1046	}
1047
1048	for(i=0; i<16; i++) {
1049		for (i=0; i<16; i++) {
1050			if (!((1 << i) & 0x673b))
1051				continue;
1052			outb(vgaCRIndex, 0x50 + i);
1053			save->s3syssave[i + 16] = inb(vgaCRReg);
1054		}
1055	}
1056
1057	if (pS3->RamDac->RamDacType == TI3025_RAMDAC)
1058		save->s3syssave[0x0c + 16] = cr5c;
1059
1060	for(i=32; i<46; i++) {
1061		outb(vgaCRIndex, 0x40 + i);
1062		save->s3syssave[i] = inb(vgaCRReg);
1063	}
1064}
1065
1066
1067Bool S3SaveScreen(ScreenPtr pScreen, int mode)
1068{
1069	return vgaHWSaveScreen(pScreen, mode);
1070}
1071
1072
1073static void S3FreeScreen(int scrnIndex, int flags)
1074{
1075        ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1076
1077        vgaHWFreeHWRec(pScrn);
1078
1079        S3FreeRec(pScrn);
1080}
1081
1082
1083Bool S3CloseScreen(int scrnIndex, ScreenPtr pScreen)
1084{
1085        ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1086        S3Ptr pS3 = S3PTR(pScrn);
1087        vgaHWPtr hwp = VGAHWPTR(pScrn);
1088
1089        if (pScrn->vtSema) {
1090                vgaHWUnlock(hwp);
1091		S3Restore(pScrn);
1092                vgaHWLock(hwp);
1093                S3UnmapMem(pScrn);
1094        }
1095
1096	if (pS3->DGAModes)
1097		xfree(pS3->DGAModes);
1098	pS3->DGAModes = NULL;
1099
1100        pScrn->vtSema = FALSE;
1101        pScreen->CloseScreen = pS3->CloseScreen;
1102
1103        return (*pScreen->CloseScreen)(scrnIndex, pScreen);
1104}
1105
1106
1107Bool S3SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
1108{
1109	return S3ModeInit(xf86Screens[scrnIndex], mode);
1110
1111}
1112
1113
1114static void S3GenericLoadPalette(ScrnInfoPtr pScrn, int numColors,
1115                                 int *indicies, LOCO *colors,
1116                                 VisualPtr pVisual)
1117{
1118        int i, index;
1119
1120        for (i=0; i<numColors; i++) {
1121                index = indicies[i];
1122                outb(0x3c8, index);
1123                outb(0x3c9, colors[index].red);
1124                outb(0x3c9, colors[index].green);
1125                outb(0x3c9, colors[index].blue);
1126        }
1127}
1128
1129
1130static Bool S3MapMem(ScrnInfoPtr pScrn)
1131{
1132	S3Ptr pS3 = S3PTR(pScrn);
1133
1134	if (pS3->S3NewMMIO) {
1135
1136
1137#ifndef XSERVER_LIBPCIACCESS
1138		pS3->MMIOBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
1139					      pS3->PciTag, pS3->IOAddress,
1140					      S3_NEWMMIO_REGSIZE);
1141#else
1142		{
1143			void** result = (void**)&pS3->MMIOBase;
1144			int err = pci_device_map_range(pS3->PciInfo,
1145						       pS3->IOAddress,
1146						       S3_NEWMMIO_REGSIZE,
1147						       PCI_DEV_MAP_FLAG_WRITABLE,
1148						       result);
1149
1150			if (err)
1151				return FALSE;
1152		}
1153#endif
1154		if (!pS3->MMIOBase) {
1155			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1156				   "Could not map MMIO\n");
1157			return FALSE;
1158		}
1159	}
1160
1161#ifndef XSERVER_LIBPCIACCESS
1162	pS3->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1163				    pS3->PciTag, pS3->FBAddress,
1164				    pScrn->videoRam * 1024);
1165
1166#else
1167	{
1168		void** result = (void**)&pS3->FBBase;
1169		int err = pci_device_map_range(pS3->PciInfo,
1170					       pS3->FBAddress,
1171					       pScrn->videoRam * 1024,
1172					       PCI_DEV_MAP_FLAG_WRITABLE |
1173					       PCI_DEV_MAP_FLAG_WRITE_COMBINE,
1174					       result);
1175
1176		if (err)
1177			return FALSE;
1178	}
1179#endif
1180	if (!pS3->FBBase) {
1181		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1182			   "Could not map framebuffer\n");
1183		return FALSE;
1184	}
1185
1186	pS3->FBCursorOffset = pScrn->videoRam - 1;
1187
1188	return TRUE;
1189}
1190
1191
1192static void S3UnmapMem(ScrnInfoPtr pScrn)
1193{
1194	S3Ptr pS3 = S3PTR(pScrn);
1195
1196	if (pS3->S3NewMMIO) {
1197#ifndef XSERVER_LIBPCIACCESS
1198		xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pS3->MMIOBase,
1199				S3_NEWMMIO_REGSIZE);
1200#else
1201		pci_device_unmap_range(pS3->PciInfo, pS3->MMIOBase, S3_NEWMMIO_REGSIZE);
1202#endif
1203	}
1204
1205#ifndef XSERVER_LIBPCIACCESS
1206	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pS3->FBBase,
1207			pScrn->videoRam * 1024);
1208#else
1209	pci_device_unmap_range(pS3->PciInfo, pS3->FBBase, pScrn->videoRam * 1024);
1210#endif
1211
1212	return;
1213}
1214
1215
1216static int S3GetPixMuxShift(ScrnInfoPtr pScrn)
1217{
1218	S3Ptr pS3 = S3PTR(pScrn);
1219	int shift = 0;
1220
1221	if (pS3->Chipset == PCI_CHIP_968)
1222		shift = 1;	/* XXX IBMRGB */
1223	else if (pS3->Chipset == PCI_CHIP_TRIO ||
1224	         pS3->Chipset == PCI_CHIP_TRIO64UVP ||
1225	         pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX) {
1226		if (pS3->s3Bpp == 2)
1227			shift = -1;
1228		else
1229			shift = 0;
1230	}
1231
1232	return shift;
1233}
1234
1235static Bool S3ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
1236{
1237	S3Ptr pS3 = S3PTR(pScrn);
1238	S3RegPtr new = &pS3->ModeRegs;
1239        vgaHWPtr hwp = VGAHWPTR(pScrn);
1240        vgaRegPtr pVga = &hwp->ModeReg;
1241        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
1242	int vgaIOBase = hwp->IOBase;
1243	int r, n, m;
1244	unsigned char tmp;
1245
1246	pS3->pixMuxShift = S3GetPixMuxShift(pScrn);
1247
1248	pS3->s3BppDisplayWidth = pScrn->displayWidth * pS3->s3Bpp;
1249	pS3->hwCursor = (mode->Flags & V_DBLSCAN) ? FALSE : TRUE;
1250	pS3->HDisplay = mode->HDisplay;
1251
1252	pS3->s3ScissB = ((pScrn->videoRam * 1024) / pS3->s3BppDisplayWidth) - 1;
1253	pS3->s3ScissR = pScrn->displayWidth - 1;
1254
1255	/*
1256	   Set correct blanking for S3 Trio64V2. It's also needed
1257	   to clear cr33_5.
1258	*/
1259	if (pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX)
1260		mode->CrtcHBlankStart = mode->CrtcHDisplay + 8;
1261
1262	if ((mode->HTotal == mode->CrtcHTotal) && (pS3->pixMuxShift != 0)) {
1263		if (pS3->pixMuxShift > 0) {
1264			mode->CrtcHTotal >>= pS3->pixMuxShift;
1265			mode->CrtcHDisplay >>= pS3->pixMuxShift;
1266			mode->CrtcHBlankStart >>= pS3->pixMuxShift;
1267			mode->CrtcHBlankEnd >>= pS3->pixMuxShift;
1268			mode->CrtcHSyncStart >>= pS3->pixMuxShift;
1269			mode->CrtcHSyncEnd >>= pS3->pixMuxShift;
1270			mode->CrtcHSkew >>= pS3->pixMuxShift;
1271		} else if (pS3->pixMuxShift < 0) {
1272			mode->CrtcHTotal <<= -pS3->pixMuxShift;
1273			mode->CrtcHDisplay <<= -pS3->pixMuxShift;
1274			mode->CrtcHBlankStart <<= -pS3->pixMuxShift;
1275			mode->CrtcHBlankEnd <<= -pS3->pixMuxShift;
1276			mode->CrtcHSyncStart <<= -pS3->pixMuxShift;
1277			mode->CrtcHSyncEnd <<= -pS3->pixMuxShift;
1278			mode->CrtcHSkew <<= -pS3->pixMuxShift;
1279		}
1280	}
1281
1282        if (!vgaHWInit(pScrn, mode))
1283                return FALSE;
1284
1285
1286
1287	pVga->MiscOutReg |= 0x0c;
1288	pVga->Sequencer[0] = 0x03;
1289	pVga->CRTC[19] = pS3->s3BppDisplayWidth >> 3;
1290	pVga->CRTC[23] = 0xe3;
1291	pVga->Attribute[0x11] = 0xff;
1292
1293	if (vgaIOBase == 0x3b0)
1294		pVga->MiscOutReg &= 0xfe;
1295	else
1296		pVga->MiscOutReg |= 0x01;
1297
1298	/* ok i give up also, i'm writing in here */
1299
1300	vgaHWProtect(pScrn, TRUE);
1301
1302
1303	if (pS3->RamDac->RamDacType == TI3025_RAMDAC) {
1304		outb(vgaCRIndex, 0x5c);
1305		tmp = inb(vgaCRReg);
1306		outb(vgaCRReg, tmp & 0xdf);
1307
1308		S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, 0x7f, 0x00);
1309	}
1310
1311	pS3->DacInit(pScrn, mode);
1312
1313	outb(0x3c2, pVga->MiscOutReg);
1314
1315	for(r=1; r<5; r++) {
1316		outw(0x3c4, (pVga->Sequencer[r] << 8) | r);
1317	}
1318
1319	/* We need to set this first - S3 *is* broken */
1320	outw(vgaCRIndex, (pVga->CRTC[17] << 8) | 17);
1321	for(r=0; r<25; r++)
1322		outw(vgaCRIndex, (pVga->CRTC[r] << 8) | r);
1323
1324	for(r=0; r<9; r++)
1325		outw(0x3ce, (pVga->Graphics[r] << 8) | r);
1326
1327	inb(vgaIOBase + 0x0a);
1328
1329	for(r=0; r<16; r++) {
1330		outb(0x3c0, r);
1331		outb(0x3c0, pVga->Attribute[r]);
1332	}
1333	for(r=16; r<21; r++) {
1334		outb(0x3c0, r | 0x20);
1335		outb(0x3c0, pVga->Attribute[r]);
1336	}
1337
1338
1339	new->cr31 = 0x8d;
1340	outb(vgaCRIndex, 0x31);
1341	outb(vgaCRReg, new->cr31);
1342
1343	new->cr32 = 0x00;
1344	outb(vgaCRIndex, 0x32);
1345	outb(vgaCRReg, new->cr32);
1346
1347	outb(vgaCRIndex, 0x33);
1348	new->cr33 = inb(vgaCRReg) | 0x20;
1349	if ((pS3->Chipset == PCI_CHIP_964_0) ||
1350	    (pS3->Chipset == PCI_CHIP_964_1))
1351		new->cr33 = 0x20;
1352	else if (pS3->Chipset == PCI_CHIP_TRIO64V2_DXGX)
1353		new->cr33 &= ~0x20;
1354	outb(vgaCRReg, new->cr33);
1355
1356	new->cr34 = 0x10;
1357	outb(vgaCRIndex, 0x34);
1358	outb(vgaCRReg, new->cr34);
1359
1360	if (pS3->Chipset != PCI_CHIP_AURORA64VP) {
1361		new->cr3b = (pVga->CRTC[0] + pVga->CRTC[4] + 1) / 2;
1362		outb(vgaCRIndex, 0x3b);
1363		outb(vgaCRReg, new->cr3b);
1364	}
1365
1366	new->cr3c = pVga->CRTC[0] / 2;
1367	outb(vgaCRIndex, 0x3c);
1368	outb(vgaCRReg, new->cr3c);
1369
1370	outb(vgaCRIndex, 0x40);
1371	tmp = inb(vgaCRReg);
1372	new->cr40 = (tmp & 0xf2) | 0x05;
1373	outb(vgaCRReg, new->cr40);
1374
1375	outb(vgaCRIndex, 0x43);
1376	switch (pScrn->bitsPerPixel) {
1377	case 24:
1378	case 32:
1379		new->cr43 = inb(vgaCRReg);
1380		break;
1381	case 15:
1382	case 16:
1383		if ((pS3->RamDac->RamDacType == IBM524_RAMDAC) ||
1384		    (pS3->RamDac->RamDacType == IBM524A_RAMDAC) ||
1385		    (pS3->RamDac->RamDacType == TI3025_RAMDAC))
1386			new->cr43 = 0x10;
1387		else if (pS3->RamDac->RamDacType == TRIO64_RAMDAC)
1388			new->cr43 = 0x09;
1389		break;
1390	case 8:
1391	default:
1392		new->cr43 = 0x00;
1393		break;
1394	}
1395	outb(vgaCRReg, new->cr43);
1396
1397	new->cr44 = 0x00;
1398	outb(vgaCRIndex, 0x44);
1399	outb(vgaCRReg, new->cr44);
1400
1401	outb(vgaCRIndex, 0x45);
1402	new->cr45 = inb(vgaCRReg) & 0xf2;
1403	outb(vgaCRReg, new->cr45);
1404
1405	outb(vgaCRIndex, 0x50);
1406	tmp = inb(vgaCRReg) & ~0xf1;
1407	switch (pScrn->bitsPerPixel) {
1408	case 8:
1409		break;
1410	case 16:
1411		tmp |= 0x10;
1412		break;
1413	case 24:
1414		tmp |= 0x20; /* there is no such value in spec s3.txt */
1415		break;
1416	case 32:
1417		tmp |= 0x30;
1418		break;
1419	}
1420
1421	switch (pScrn->displayWidth) {
1422	case 640:
1423		tmp |= 0x40;
1424		break;
1425	case 800:
1426		tmp |= 0x80;
1427		break;
1428	case 1152:
1429		tmp |= 0x01;
1430		break;
1431	case 1280:
1432		tmp |= 0xc0;
1433		break;
1434	case 1600:
1435		tmp |= 0x81;
1436		break;
1437	}
1438	new->cr50 = tmp;
1439	outb(vgaCRReg, new->cr50);
1440
1441
1442	outb(vgaCRIndex, 0x51);
1443	new->cr51 = (inb(vgaCRReg) & 0xc0) |
1444		    ((pS3->s3BppDisplayWidth >> 7) & 0x30);
1445	outb(vgaCRReg, new->cr51);
1446
1447	outb(vgaCRIndex, 0x53);
1448	new->cr53 = inb(vgaCRReg);
1449	if (pS3->S3NewMMIO)
1450		new->cr53 |= 0x18;
1451	else
1452		new->cr53 &= ~0x18;
1453	outb(vgaCRReg, new->cr53);
1454
1455	n = 255;
1456	outb(vgaCRIndex, 0x54);
1457	{
1458		int clock2, mclk;
1459
1460		clock2 = mode->Clock * pS3->s3Bpp;
1461		if (pScrn->videoRam < 2048)
1462			clock2 *= 2;
1463		mclk = pS3->mclk;
1464		m = (int)((mclk/1000.0*.72+16.867)*89.736/(clock2/1000.0+39)-21.1543);
1465		if (pScrn->videoRam < 2048)
1466			m /= 2;
1467		if (m >31)
1468			m = 31;
1469		else if (m < 0) {
1470			m = 0;
1471			n = 16;
1472		}
1473	}
1474	new->cr54 = m << 3;
1475	outb(vgaCRReg, new->cr54);
1476
1477	if (n < 0)
1478		n = 0;
1479	else if (n > 255)
1480		n = 255;
1481	outb(vgaCRIndex, 0x60);
1482	new->cr60 = n;
1483	outb(vgaCRReg, new->cr60);
1484
1485	if (pS3->hasStreams) {
1486		new->cr60 = 255;
1487		outb(vgaCRIndex, 0x60);
1488		outb(vgaCRReg, new->cr60);
1489
1490		new->cr54 = 31 << 3;
1491		outb(vgaCRIndex, 0x54);
1492		outb(vgaCRReg, new->cr54);
1493	}
1494
1495	outb(vgaCRIndex, 0x55);
1496	new->cr55 = (inb(vgaCRReg) & 0x08) | 0x40;
1497	outb(vgaCRReg, new->cr55);
1498
1499	outb(vgaCRIndex, 0x5e);
1500	new->cr5e = (((mode->CrtcVTotal - 2) & 0x400) >> 10)	|
1501		    (((mode->CrtcVDisplay - 1) & 0x400) >> 9)	|
1502		    (((mode->CrtcVSyncStart) & 0x400) >> 8)	|
1503		    (((mode->CrtcVSyncStart) & 0x400) >> 6)	| 0x40;
1504	outb(vgaCRReg, new->cr5e);
1505
1506	{
1507		int i;
1508		unsigned int j;
1509
1510		i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8)      |
1511		    ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7)    |
1512		    ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6)  |
1513		    ((mode->CrtcHSyncStart & 0x800) >> 7);
1514		if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)
1515			i |= 0x08;
1516		if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)
1517			i |= 0x20;
1518
1519		outb(vgaCRIndex, 0x3b);
1520		j = ((pVga->CRTC[0] + ((i & 0x01) << 8) +
1521		      pVga->CRTC[4] + ((i & 0x10) << 4) + 1) / 2);
1522
1523            	if (j - (pVga->CRTC[4] + ((i & 0x10) << 4)) < 4) {
1524                	if (pVga->CRTC[4] + ((i & 0x10) << 4) + 4 <= pVga->CRTC[0] + ((i & 0x01) << 8))
1525                    		j = pVga->CRTC[4] + ((i & 0x10) << 4) + 4;
1526                	else
1527                    		j = pVga->CRTC[0] + ((i & 0x01) << 8) + 1;
1528		}
1529		if (pS3->Chipset == PCI_CHIP_AURORA64VP) {
1530			outb(vgaCRReg, 0x00);
1531			i &= ~0x40;
1532		} else {
1533			new->cr3b = j & 0xff;
1534			outb(vgaCRReg, new->cr3b);
1535			i |= (j & 0x100) >> 2;
1536		}
1537
1538		outb(vgaCRIndex, 0x3c);
1539		new->cr3c = (pVga->CRTC[0] + ((i & 0x01) << 8)) / 2;
1540		outb(vgaCRReg, new->cr3c);
1541
1542		outb(vgaCRIndex, 0x5d);
1543		new->cr5d = (inb(vgaCRReg) & 0x80) | i;
1544		outb(vgaCRReg, new->cr5d);
1545	}
1546
1547	{
1548		int i;
1549
1550		if (pScrn->videoRam > 1024)
1551			i = mode->HDisplay * pS3->s3Bpp / 8 + 1;
1552		else
1553			i = mode->HDisplay * pS3->s3Bpp / 4 + 1;
1554
1555		outb(vgaCRIndex, 0x61);
1556		tmp = 0x80 | (inb(vgaCRReg) & 0x60) | (i >> 8);
1557		new->cr61 = tmp;
1558		outb(vgaCRReg, new->cr61);
1559		outb(vgaCRIndex, 0x62);
1560		new->cr62 = i & 0xff;
1561		outb(vgaCRReg, new->cr62);
1562	}
1563
1564	if (mode->Flags & V_INTERLACE) {
1565		outb(vgaCRIndex, 0x42);
1566		new->cr42 = inb(vgaCRReg) | 0x20;
1567		outb(vgaCRReg, new->cr42);
1568	} else {
1569		outb(vgaCRIndex, 0x42);
1570		new->cr42 = inb(vgaCRReg) & ~0x20;
1571		outb(vgaCRReg, new->cr42);
1572	}
1573
1574	if (pS3->hasStreams) {
1575		unsigned char a;
1576
1577		outb(vgaCRIndex, 0x67);
1578		a = inb(vgaCRReg) & 0xfe;
1579
1580		switch (pScrn->depth) {
1581		case 8:
1582			break;
1583		case 15:
1584			a |= (3 << 4);
1585			break;
1586		case 16:
1587			a |= (5 << 4);
1588			break;
1589		case 24:
1590			a |= (13 << 4);
1591			break;
1592		}
1593
1594		if (pS3->hasStreams)
1595			a |= (3 << 2);
1596
1597		WaitVSync(); /* Wait for VSync before setting mode */
1598		outb(vgaCRReg, a);
1599	}
1600
1601	if (pS3->Chipset == PCI_CHIP_968) {
1602		unsigned char a;
1603
1604		outb(vgaCRIndex, 0x67);
1605		a = inb(vgaCRReg) & 0xfe;
1606#if 0
1607		switch (pScrn->depth) {
1608			case 8:
1609				break;
1610			case 15:
1611				a |= (3 << 4);
1612				break;
1613			case 16:
1614				a |= (5 << 4);
1615				a |= (3 << 2);	/* streams */
1616				break;
1617			case 24:
1618				a |= (13 << 4);
1619				a |= (3 << 2);	/* streams */
1620				break;
1621		}
1622#endif
1623		outb(vgaCRReg, a);
1624
1625		outb(vgaCRIndex, 0x6d);
1626		outb(vgaCRReg, 0x00);
1627	}
1628
1629	if ((pS3->Chipset == PCI_CHIP_964_0) ||
1630	    (pS3->Chipset == PCI_CHIP_964_1)) {
1631		unsigned char bdelay;
1632
1633		outb(vgaCRIndex, 0x6d);
1634		bdelay = inb(vgaCRReg);
1635
1636		if (pS3->RamDac->RamDacType == TI3025_RAMDAC) {
1637			if (pS3->s3Bpp == 1) {
1638				if (mode->Clock > 80000)
1639					bdelay = 0x02;
1640				else
1641					bdelay = 0x03;
1642			} else if (pS3->s3Bpp == 2) {
1643				if (mode->Clock > 80000)
1644					bdelay = 0x00;
1645				else
1646					bdelay = 0x01;
1647			} else
1648				bdelay = 0x00;
1649		}
1650
1651		outb(vgaCRReg, bdelay);
1652	}
1653
1654	outb(vgaCRIndex, 0x66);
1655	new->cr66 = inb(vgaCRReg);
1656	if (pS3->S3NewMMIO)
1657		new->cr66 |= 0x88;
1658	else
1659		new->cr66 |= 0x80;
1660	outb(vgaCRReg, new->cr66);
1661
1662
1663	if (pS3->SlowDRAMRefresh)
1664		new->cr3a = 0xb7;
1665       	else
1666		new->cr3a = 0xb5;
1667	outb(vgaCRIndex, 0x3a);
1668	outb(vgaCRReg, new->cr3a);
1669
1670	if (pS3->SlowVRAM) {
1671		/*
1672		 * some Diamond Stealth 64 VRAM cards have a problem with
1673		 * VRAM timing, increas -RAS low timing from 3.5 MCLKs
1674		 * to 4.5 MCLKs
1675		 */
1676		outb(vgaCRIndex, 0x39);
1677		outb(vgaCRReg, 0xa5);
1678		outb(vgaCRIndex, 0x68);
1679		tmp = inb(vgaCRReg);
1680		if (tmp & 0x30)				/* 3.5 MCLKs */
1681			outb(vgaCRReg, tmp & 0xef);	/* 4.5 MCLKs */
1682	}
1683
1684	if (pS3->SlowDRAM) {
1685		/*
1686		 * fixes some pixel errors for a SPEA Trio64V+ card
1687		 * increase -RAS precharge timing from 2.5 MCLKs
1688		 * to 3.5 MCLKs
1689		 */
1690		outb(vgaCRIndex, 0x39);
1691		outb(vgaCRReg, 0xa5);
1692		outb(vgaCRIndex, 0x68);
1693		tmp = inb(vgaCRReg) & 0xf7;
1694		outb(vgaCRReg, tmp);			/* 3.5 MCLKs */
1695	}
1696
1697	if (pS3->SlowEDODRAM) {
1698		/*
1699		 * fixes some pixel errors for a SPEA Trio64V+ card
1700		 * increase from 1-cycle to 2-cycle EDO mode
1701		 */
1702		outb(vgaCRIndex, 0x39);
1703
1704		outb(vgaCRReg, 0xa5);
1705		outb(vgaCRIndex, 0x36);
1706		tmp = inb(vgaCRReg);
1707		if (!(tmp & 0x0c))			/* 1-cycle EDO */
1708			outb(vgaCRReg, tmp | 0x08);	/* 2-cycle EDO */
1709	}
1710
1711	if (pS3->Chipset == PCI_CHIP_AURORA64VP) {
1712		outb(0x3c4, 0x08);
1713		outb(0x3c5, 0x06);
1714#if 0
1715		outb(0x3c4, 0x54);
1716		outb(0x3c5, 0x10);
1717		outb(0x3c4, 0x55);
1718		outb(0x3c5, 0x00);
1719		outb(0x3c4, 0x56);
1720		outb(0x3c5, 0x1c);
1721		outb(0x3c4, 0x57);
1722		outb(0x3c5, 0x00);
1723#else
1724		outb(0x3c4, 0x54);
1725		outb(0x3c5, 0x1f);
1726		outb(0x3c4, 0x55);
1727		outb(0x3c5, 0x1f);
1728		outb(0x3c4, 0x56);
1729		outb(0x3c5, 0x1f);
1730		outb(0x3c4, 0x57);
1731		outb(0x3c5, 0x1f);
1732#endif
1733
1734		outb(0x3c4, 0x08);
1735		outb(0x3c5, 0x00);
1736	}
1737
1738	pScrn->AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1739
1740       	vgaHWProtect(pScrn, FALSE);
1741
1742	if (pScrn->displayWidth == 1024)
1743		outw(ADVFUNC_CNTL, 0x0007);
1744	else
1745		outw(ADVFUNC_CNTL, 0x0003);
1746
1747	outb(0x3c6, 0x00);
1748
1749	outw(SUBSYS_CNTL, 0x8000 | 0x1000);
1750	outw(SUBSYS_CNTL, 0x4000 | 0x1000);
1751
1752	inw(SUBSYS_STAT);
1753
1754	outw(0xbee8, 0x5000 | 0x0004 | 0x000c);
1755
1756	outb(0x3c6, 0xff);
1757
1758	new->cr59 = pS3->FBAddress >> 24;
1759	new->cr5a = pS3->FBAddress >> 16;
1760
1761	if (pScrn->videoRam <= 1024)
1762		new->cr58 = 0x15;
1763	else if (pScrn->videoRam <= 2048)
1764		new->cr58 = 0x16;
1765	else
1766		new->cr58 = 0x17;
1767
1768	if ((pS3->Chipset == PCI_CHIP_968) ||
1769	    (pS3->Chipset == PCI_CHIP_964_0) ||
1770	    (pS3->Chipset == PCI_CHIP_964_1))
1771		new->cr58 |= 0x40;
1772
1773	outb(vgaCRIndex, 0x59);
1774	outb(vgaCRReg, new->cr59);
1775	outb(vgaCRIndex, 0x5a);
1776	outb(vgaCRReg, new->cr5a);
1777	outb(vgaCRIndex, 0x58);
1778	outb(vgaCRReg, new->cr58);
1779
1780	WaitQueue(5);
1781	SET_SCISSORS(0, 0, pS3->s3ScissR, pS3->s3ScissB);
1782
1783	if (pS3->hasStreams)
1784		S3InitStreams(pScrn, mode);
1785
1786	return TRUE;
1787}
1788
1789
1790static Bool S3EnterVT(int scrnIndex, int flags)
1791{
1792        ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1793        vgaHWPtr hwp = VGAHWPTR(pScrn);
1794
1795        vgaHWUnlock(hwp);
1796        if (!S3ModeInit(pScrn, pScrn->currentMode))
1797                return FALSE;
1798
1799        return TRUE;
1800}
1801
1802
1803static void S3Restore(ScrnInfoPtr pScrn)
1804{
1805        S3Ptr pS3 = S3PTR(pScrn);
1806        S3RegPtr restore = &pS3->SavedRegs;
1807        vgaHWPtr hwp = VGAHWPTR(pScrn);
1808        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
1809	int i;
1810
1811	vgaHWProtect(pScrn, TRUE);
1812	WaitQueue(8);
1813
1814	S3BankZero(pScrn);
1815
1816	outw(ADVFUNC_CNTL, 0x0000);
1817
1818	if (pS3->S3NewMMIO) {
1819		outb(vgaCRIndex, 0x53);
1820		outb(vgaCRReg, 0x00);
1821	}
1822
1823	pS3->DacRestore(pScrn);
1824
1825	if (pS3->RamDac->RamDacType == TI3025_RAMDAC) {
1826		outb(vgaCRIndex, 0x5c);
1827		outb(vgaCRReg, restore->s3syssave[0x0c + 16]);
1828	}
1829
1830	for(i=32; i<46; i++) {
1831		outb(vgaCRIndex, 0x40 + i);
1832		outb(vgaCRReg, restore->s3syssave[i]);
1833	}
1834
1835	for(i=0; i<16; i++) {
1836		if (!((1 << i) & 0x673b))
1837			continue;
1838		outb(vgaCRIndex, 0x50 + i);
1839		outb(vgaCRReg, restore->s3syssave[i+16]);
1840	}
1841
1842	for(i=0; i<5; i++) {
1843		outb(vgaCRIndex, 0x30 + i);
1844		outb(vgaCRReg, restore->s3save[i]);
1845		outb(vgaCRIndex, 0x38 + i);
1846		outb(vgaCRReg, restore->s3save[i + 5]);
1847	}
1848
1849	for(i=0; i<16; i++) {
1850		outb(vgaCRIndex, 0x40 + i);
1851		outb(vgaCRReg, restore->s3syssave[i]);
1852	}
1853
1854	outb(vgaCRIndex, 0x45);
1855	inb(vgaCRReg);
1856	outb(vgaCRIndex, 0x4a);
1857	for(i=0; i<4; i++)
1858		outb(vgaCRReg, restore->color_stack[i]);
1859
1860	outb(vgaCRIndex, 0x45);
1861	inb(vgaCRReg);
1862	outb(vgaCRIndex, 0x4b);
1863	for(i=4; i<8; i++)
1864		outb(vgaCRReg, restore->color_stack[i]);
1865
1866        vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_ALL);
1867
1868	outb(0x3c2, restore->clock);
1869
1870	vgaHWProtect(pScrn, FALSE);
1871
1872}
1873
1874
1875static void S3LeaveVT(int scrnIndex, int flags)
1876{
1877        ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1878        vgaHWPtr hwp = VGAHWPTR(pScrn);
1879
1880        S3Restore(pScrn);
1881        vgaHWLock(hwp);
1882
1883        return;
1884}
1885
1886
1887static void S3AdjustFrame(int scrnIndex, int x, int y, int flags)
1888{
1889        ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1890        S3Ptr pS3 = S3PTR(pScrn);
1891	S3RegPtr regs = &pS3->ModeRegs;
1892        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
1893	int base, orig_base;
1894	unsigned char tmp;
1895
1896	if (x > pScrn->displayWidth - pS3->HDisplay)
1897		x = pScrn->displayWidth - pS3->HDisplay;
1898
1899	orig_base = (y * pScrn->displayWidth + x) * pS3->s3Bpp;
1900	base = (orig_base >> 2) & ~1;
1901
1902	/* for IBMRGB and TI only */
1903	if (pS3->RamDac->RamDacType == IBM524A_RAMDAC)
1904	{
1905		int px, py, a;
1906
1907		miPointerGetPosition(inputInfo.pointer, &px, &py);
1908
1909		if (pS3->s3Bpp == 1)
1910			a = 4 - 1;
1911		else
1912			a = 8 - 1;
1913		if (px-x > pS3->HDisplay/2)
1914			base = ((orig_base + a*4) >> 2) & ~1;
1915		base &= ~a;
1916	}
1917
1918	outb(vgaCRIndex, 0x31);
1919	outb(vgaCRReg, ((base & 0x030000) >> 12) | regs->cr31);
1920	regs->cr51 &= ~0x03;
1921	regs->cr51 |= ((base & 0x0c0000) >> 18);
1922	outb(vgaCRIndex, 0x51);
1923	tmp = (inb(vgaCRReg) & ~0x03) | (regs->cr51 & 0x03);
1924	outb(vgaCRReg, tmp);
1925
1926	outw(vgaCRIndex, (base & 0x00ff00) | 0x0c);
1927	outw(vgaCRIndex, ((base & 0x00ff) << 8) | 0x0d);
1928}
1929
1930
1931void S3Regdump(ScrnInfoPtr pScrn)
1932{
1933        S3Ptr pS3 = S3PTR(pScrn);
1934        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
1935	{
1936		int j;
1937
1938		for(j=0; j<0x100; j++) {
1939			outb(vgaCRIndex, j);
1940			ErrorF("CRTC 0x%x = 0x%x\n", j, inb(vgaCRReg));
1941		}
1942	}
1943#if 0
1944	ErrorF("DAC regs\n");
1945
1946	{
1947		int j;
1948
1949		for(j=0; j<0x100; j++)
1950			ErrorF("0x%x = 0x%x\n", j, S3InTiIndReg(pScrn, j));
1951#if 0
1952		outb(vgaCRIndex, 0x22);
1953		ErrorF("cr22 = 0x%x\n", inb(vgaCRReg));
1954#endif
1955	}
1956#endif
1957}
1958
1959
1960void S3BankZero(ScrnInfoPtr pScrn)
1961{
1962        S3Ptr pS3 = S3PTR(pScrn);
1963	unsigned char tmp;
1964        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
1965
1966	outb(vgaCRIndex, 0x35);
1967	tmp = inb(vgaCRReg) & 0xf0;
1968	outb(vgaCRReg, tmp);
1969
1970	outb(vgaCRIndex, 0x51);
1971	tmp = inb(vgaCRReg) & 0xf3;
1972	outb(vgaCRReg, tmp);
1973}
1974
1975static void
1976S3DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
1977			    int flags)
1978{
1979     S3Ptr pS3 = S3PTR(pScrn);
1980     switch (pS3->Chipset) {
1981     case PCI_CHIP_TRIO64V2_DXGX:
1982     case PCI_CHIP_TRIO:
1983     case PCI_CHIP_AURORA64VP:
1984     case PCI_CHIP_TRIO64UVP:
1985     {
1986	  int srd;
1987
1988	  outb(0x3c4, 0x08);
1989	  outb(0x3c5, 0x06);	  /* unlock extended sequence registers */
1990
1991	  outb(0x3c4, 0x0d);
1992	  srd = inb(0x3c5) & 0xf;  /* clear the sync control bits */
1993
1994	  switch (PowerManagementMode) {
1995	  case DPMSModeOn:
1996	       /* Screen: On; HSync: On, VSync: On */
1997	       break;
1998	  case DPMSModeStandby:
1999	       /* Screen: Off; HSync: Off, VSync: On */
2000	       srd |= 0x10;
2001	       break;
2002	  case DPMSModeSuspend:
2003	       /* Screen: Off; HSync: On, VSync: Off */
2004	       srd |= 0x40;
2005	       break;
2006	  case DPMSModeOff:
2007	       /* Screen: Off; HSync: Off, VSync: Off */
2008	       srd |= 0x50;
2009	       break;
2010	  }
2011	  outb(0x3c4, 0x0d);
2012	  outb(0x3c5, srd);
2013	  break;
2014     }
2015     default:
2016	  vgaHWDPMSSet(pScrn, PowerManagementMode, flags);
2017     }
2018}
2019