smi_driver.c revision 09885543
1/* Header:   //Mercury/Projects/archives/XFree86/4.0/smi_driver.c-arc   1.42   03 Jan 2001 13:52:16   Frido  $ */
2
3/*
4Copyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
5Copyright (C) 2000 Silicon Motion, Inc.  All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of
8this software and associated documentation files (the "Software"), to deal in
9the Software without restriction, including without limitation the rights to
10use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11of the Software, and to permit persons to whom the Software is furnished to do
12so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
19NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the names of The XFree86 Project and
25Silicon Motion shall not be used in advertising or otherwise to promote the
26sale, use or other dealings in this Software without prior written
27authorization from The XFree86 Project or Silicon Motion.
28*/
29/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/siliconmotion/smi_driver.c,v 1.36tsi Exp $ */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include "xf86Resources.h"
36#include "xf86RAC.h"
37#include "xf86DDC.h"
38#include "xf86int10.h"
39#include "vbe.h"
40#include "shadowfb.h"
41
42#include "smi.h"
43
44#include "globals.h"
45#define DPMS_SERVER
46#include <X11/extensions/dpms.h>
47
48/*
49 * Internals
50 */
51static void SMI_EnableMmio(ScrnInfoPtr pScrn);
52static void SMI_DisableMmio(ScrnInfoPtr pScrn);
53
54/*
55 * Forward definitions for the functions that make up the driver.
56 */
57
58static const OptionInfoRec * SMI_AvailableOptions(int chipid, int busid);
59static void SMI_Identify(int flags);
60static Bool SMI_Probe(DriverPtr drv, int flags);
61static Bool SMI_PreInit(ScrnInfoPtr pScrn, int flags);
62static Bool SMI_EnterVT(int scrnIndex, int flags);
63static void SMI_LeaveVT(int scrnIndex, int flags);
64static void SMI_Save (ScrnInfoPtr pScrn);
65static void SMI_WriteMode (ScrnInfoPtr pScrn, vgaRegPtr, SMIRegPtr);
66static Bool SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
67                           char **argv);
68static int SMI_InternalScreenInit(int scrnIndex, ScreenPtr pScreen);
69static void SMI_PrintRegs(ScrnInfoPtr);
70static ModeStatus SMI_ValidMode(int scrnIndex, DisplayModePtr mode,
71                                Bool verbose, int flags);
72static void SMI_DisableVideo(ScrnInfoPtr pScrn);
73static void SMI_EnableVideo(ScrnInfoPtr pScrn);
74static Bool SMI_MapMem(ScrnInfoPtr pScrn);
75static void SMI_UnmapMem(ScrnInfoPtr pScrn);
76static Bool SMI_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
77static Bool SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen);
78static Bool SMI_SaveScreen(ScreenPtr pScreen, int mode);
79static void SMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
80                            LOCO *colors, VisualPtr pVisual);
81static void SMI_DisplayPowerManagementSet(ScrnInfoPtr pScrn,
82                                          int PowerManagementMode, int flags);
83static Bool SMI_ddc1(int scrnIndex);
84static unsigned int SMI_ddc1Read(ScrnInfoPtr pScrn);
85static void SMI_FreeScreen(int ScrnIndex, int flags);
86static void SMI_ProbeDDC(ScrnInfoPtr pScrn, int index);
87static void SMI_DetectPanelSize(ScrnInfoPtr pScrn);
88
89
90#define SILICONMOTION_NAME          "Silicon Motion"
91#define SILICONMOTION_DRIVER_NAME   "siliconmotion"
92#define SILICONMOTION_VERSION_NAME  "1.4.1"
93#define SILICONMOTION_VERSION_MAJOR 1
94#define SILICONMOTION_VERSION_MINOR 4
95#define SILICONMOTION_PATCHLEVEL    1
96#define SILICONMOTION_DRIVER_VERSION ((SILICONMOTION_VERSION_MAJOR << 24) | \
97                                      (SILICONMOTION_VERSION_MINOR << 16) | \
98                                      (SILICONMOTION_PATCHLEVEL))
99
100/*
101 * This contains the functions needed by the server after loading the
102 * driver module.  It must be supplied, and gets added the driver list by
103 * the Module Setup funtion in the dynamic case.  In the static case a
104 * reference to this is compiled in, and this requires that the name of
105 * this DriverRec be an upper-case version of the driver name.
106 */
107
108_X_EXPORT DriverRec SILICONMOTION =
109{
110    SILICONMOTION_DRIVER_VERSION,
111    SILICONMOTION_DRIVER_NAME,
112    SMI_Identify,
113    SMI_Probe,
114    SMI_AvailableOptions,
115    NULL,
116    0
117};
118
119/* Supported chipsets */
120static SymTabRec SMIChipsets[] =
121{
122    { PCI_CHIP_SMI910, "Lynx"    },
123    { PCI_CHIP_SMI810, "LynxE"   },
124    { PCI_CHIP_SMI820, "Lynx3D"  },
125    { PCI_CHIP_SMI710, "LynxEM"  },
126    { PCI_CHIP_SMI712, "LynxEM+" },
127    { PCI_CHIP_SMI720, "Lynx3DM" },
128    { PCI_CHIP_SMI731, "Cougar3DR" },
129    { -1,             NULL      }
130};
131
132static PciChipsets SMIPciChipsets[] =
133{
134    /* numChipset,		PciID,				Resource */
135    { PCI_CHIP_SMI910,	PCI_CHIP_SMI910,	RES_SHARED_VGA },
136    { PCI_CHIP_SMI810,	PCI_CHIP_SMI810,	RES_SHARED_VGA },
137    { PCI_CHIP_SMI820,	PCI_CHIP_SMI820,	RES_SHARED_VGA },
138    { PCI_CHIP_SMI710,	PCI_CHIP_SMI710,	RES_SHARED_VGA },
139    { PCI_CHIP_SMI712,	PCI_CHIP_SMI712,	RES_SHARED_VGA },
140    { PCI_CHIP_SMI720,	PCI_CHIP_SMI720,	RES_SHARED_VGA },
141    { PCI_CHIP_SMI731,	PCI_CHIP_SMI731,	RES_SHARED_VGA },
142    { -1,				-1,					RES_UNDEFINED  }
143};
144
145typedef enum
146{
147    OPTION_PCI_BURST,
148    OPTION_FIFO_CONSERV,
149    OPTION_FIFO_MODERATE,
150    OPTION_FIFO_AGGRESSIVE,
151    OPTION_PCI_RETRY,
152    OPTION_NOACCEL,
153    OPTION_MCLK,
154    OPTION_SHOWCACHE,
155    OPTION_SWCURSOR,
156    OPTION_HWCURSOR,
157    OPTION_SHADOW_FB,
158    OPTION_ROTATE,
159    OPTION_VIDEOKEY,
160    OPTION_BYTESWAP,
161    /* CZ 26.10.2001: interlaced video */
162    OPTION_INTERLACED,
163    /* end CZ */
164    OPTION_USEBIOS,
165    OPTION_ZOOMONLCD,
166    OPTION_DUALHEAD,
167    OPTION_ACCELMETHOD,
168    NUMBER_OF_OPTIONS
169} SMIOpts;
170
171static const OptionInfoRec SMIOptions[] =
172{
173    { OPTION_PCI_BURST,	     "pci_burst",	  OPTV_BOOLEAN, {0}, FALSE },
174    { OPTION_FIFO_CONSERV,    "fifo_conservative", OPTV_BOOLEAN, {0}, FALSE },
175    { OPTION_FIFO_MODERATE,   "fifo_moderate",	  OPTV_BOOLEAN, {0}, FALSE },
176    { OPTION_FIFO_AGGRESSIVE, "fifo_aggressive",	  OPTV_BOOLEAN, {0}, FALSE },
177    { OPTION_PCI_RETRY,	     "pci_retry",	  OPTV_BOOLEAN, {0}, FALSE },
178    { OPTION_NOACCEL,	     "NoAccel",		  OPTV_BOOLEAN, {0}, FALSE },
179    { OPTION_MCLK,	     "set_mclk",	  OPTV_FREQ,	{0}, FALSE },
180    { OPTION_SHOWCACHE,	     "show_cache",	  OPTV_BOOLEAN, {0}, FALSE },
181    { OPTION_HWCURSOR,	     "HWCursor",	  OPTV_BOOLEAN, {0}, FALSE },
182    { OPTION_SWCURSOR,	     "SWCursor",	  OPTV_BOOLEAN, {0}, FALSE },
183    { OPTION_SHADOW_FB,	     "ShadowFB",	  OPTV_BOOLEAN, {0}, FALSE },
184    { OPTION_ROTATE,	     "Rotate",		  OPTV_ANYSTR,  {0}, FALSE },
185    { OPTION_VIDEOKEY,	     "VideoKey",	  OPTV_INTEGER, {0}, FALSE },
186    { OPTION_BYTESWAP,	     "ByteSwap",	  OPTV_BOOLEAN, {0}, FALSE },
187    /* CZ 26.10.2001: interlaced video */
188    { OPTION_INTERLACED,	     "Interlaced",        OPTV_BOOLEAN, {0}, FALSE },
189    /* end CZ */
190    { OPTION_USEBIOS,	     "UseBIOS",		  OPTV_BOOLEAN,	{0}, FALSE },
191    { OPTION_ZOOMONLCD,	     "ZoomOnLCD",	  OPTV_BOOLEAN,	{0}, FALSE },
192    { OPTION_DUALHEAD,	     "Dualhead",	  OPTV_BOOLEAN,	{0}, FALSE },
193    { OPTION_ACCELMETHOD,    "AccelMethod",       OPTV_STRING,  {0}, FALSE },
194    { -1,		     NULL,		  OPTV_NONE,	{0}, FALSE }
195};
196
197/*
198 * Lists of symbols that may/may not be required by this driver.
199 * This allows the loader to know which ones to issue warnings for.
200 *
201 * Note that vgahwSymbols and xaaSymbols are referenced outside the
202 * XFree86LOADER define in later code, so are defined outside of that
203 * define here also.
204 */
205
206static const char *vgahwSymbols[] =
207{
208    "vgaHWCopyReg",
209    "vgaHWGetHWRec",
210    "vgaHWGetIOBase",
211    "vgaHWGetIndex",
212    "vgaHWInit",
213    "vgaHWLock",
214    "vgaHWMapMem",
215    "vgaHWProtect",
216    "vgaHWRestore",
217    "vgaHWSave",
218    "vgaHWSaveScreen",
219    "vgaHWSetMmioFuncs",
220    "vgaHWSetStdFuncs",
221    "vgaHWUnmapMem",
222    "vgaHWddc1SetSpeedWeak",
223    NULL
224};
225
226static const char *xaaSymbols[] =
227{
228    "XAAGetCopyROP",
229    "XAACreateInfoRec",
230    "XAADestroyInfoRec",
231    "XAAGetFallbackOps",
232    "XAAInit",
233    "XAAGetPatternROP",
234    NULL
235};
236
237static const char *exaSymbols[] =
238{
239    "exaDriverAlloc",
240    "exaDriverInit",
241    "exaDriverFini",
242    "exaOffscreenAlloc",
243    "exaOffscreenFree",
244    "exaGetPixmapPitch",
245    "exaGetPixmapOffset",
246    "exaGetPixmapSize",
247    NULL
248};
249
250static const char *ramdacSymbols[] =
251{
252    "xf86CreateCursorInfoRec",
253    "xf86DestroyCursorInfoRec",
254    "xf86InitCursor",
255    NULL
256};
257
258static const char *ddcSymbols[] =
259{
260    "xf86PrintEDID",
261    "xf86DoEDID_DDC1",
262    "xf86DoEDID_DDC2",
263    "xf86SetDDCproperties",
264    NULL
265};
266
267static const char *i2cSymbols[] =
268{
269    "xf86CreateI2CBusRec",
270    "xf86CreateI2CDevRec",
271    "xf86DestroyI2CBusRec",
272    "xf86DestroyI2CDevRec",
273    "xf86I2CBusInit",
274    "xf86I2CDevInit",
275    "xf86I2CReadBytes",
276    "xf86I2CWriteByte",
277    NULL
278};
279
280static const char *shadowSymbols[] =
281{
282    "ShadowFBInit",
283    NULL
284};
285
286static const char *int10Symbols[] =
287{
288    "xf86ExecX86int10",
289    "xf86FreeInt10",
290    "xf86InitInt10",
291    NULL
292};
293
294static const char *vbeSymbols[] =
295{
296    "VBEInit",
297    "vbeDoEDID",
298    "vbeFree",
299    NULL
300};
301
302static const char *fbSymbols[] =
303{
304    "fbPictureInit",
305    "fbScreenInit",
306    NULL
307};
308
309#ifdef XFree86LOADER
310
311static MODULESETUPPROTO(siliconmotionSetup);
312
313static XF86ModuleVersionInfo SMIVersRec =
314{
315    "siliconmotion",
316    MODULEVENDORSTRING,
317    MODINFOSTRING1,
318    MODINFOSTRING2,
319    XORG_VERSION_CURRENT,
320    SILICONMOTION_VERSION_MAJOR,
321    SILICONMOTION_VERSION_MINOR,
322    SILICONMOTION_PATCHLEVEL,
323    ABI_CLASS_VIDEODRV,
324    ABI_VIDEODRV_VERSION,
325    MOD_CLASS_VIDEODRV,
326    {0, 0, 0, 0}
327};
328
329/*
330 * This is the module init data for XFree86 modules.
331 *
332 * Its name has to be the driver name followed by ModuleData.
333 */
334_X_EXPORT XF86ModuleData siliconmotionModuleData =
335{
336    &SMIVersRec,
337    siliconmotionSetup,
338    NULL
339};
340
341static pointer
342siliconmotionSetup(pointer module, pointer opts, int *errmaj, int *errmin)
343{
344    static Bool setupDone = FALSE;
345
346    if (!setupDone) {
347	setupDone = TRUE;
348	xf86AddDriver(&SILICONMOTION, module, 0);
349
350	/*
351	 * Modules that this driver always requires can be loaded here
352	 * by calling LoadSubModule().
353	 */
354
355	/*
356	 * Tell the loader about symbols from other modules that this module
357	 * might refer to.
358	 */
359	LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, exaSymbols, ramdacSymbols,
360					  ddcSymbols, i2cSymbols, int10Symbols, vbeSymbols,
361					  shadowSymbols, NULL);
362
363	/*
364	 * The return value must be non-NULL on success even though there
365	 * is no TearDownProc.
366	 */
367	return (pointer) 1;
368
369    } else {
370	if (errmaj) {
371	    *errmaj = LDR_ONCEONLY;
372	}
373	return NULL;
374    }
375}
376
377#endif /* XFree86LOADER */
378
379static Bool
380SMI_GetRec(ScrnInfoPtr pScrn)
381{
382    ENTER_PROC("SMI_GetRec");
383
384    /*
385     * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate.
386     * pScrn->driverPrivate is initialised to NULL, so we can check if
387     * the allocation has already been done.
388     */
389    if (pScrn->driverPrivate == NULL) {
390	pScrn->driverPrivate = xnfcalloc(sizeof(SMIRec), 1);
391    }
392
393    LEAVE_PROC("SMI_GetRec");
394    return TRUE;
395}
396
397static void
398SMI_FreeRec(ScrnInfoPtr pScrn)
399{
400    ENTER_PROC("SMI_FreeRec");
401
402    if (pScrn->driverPrivate != NULL) {
403	xfree(pScrn->driverPrivate);
404	pScrn->driverPrivate = NULL;
405    }
406
407    LEAVE_PROC("SMI_FreeRec");
408}
409
410static const OptionInfoRec *
411SMI_AvailableOptions(int chipid, int busid)
412{
413    ENTER_PROC("SMI_AvailableOptions");
414    LEAVE_PROC("SMI_AvailableOptions");
415    return SMIOptions;
416}
417
418static void
419SMI_Identify(int flags)
420{
421    ENTER_PROC("SMI_Identify");
422
423    xf86PrintChipsets(SILICONMOTION_NAME, "driver (version "
424		SILICONMOTION_VERSION_NAME ") for Silicon Motion Lynx chipsets",
425		SMIChipsets);
426
427    LEAVE_PROC("SMI_Identify");
428}
429
430static Bool
431SMI_Probe(DriverPtr drv, int flags)
432{
433    int i;
434    GDevPtr *devSections;
435    int *usedChips;
436    int numDevSections;
437    int numUsed;
438    Bool foundScreen = FALSE;
439
440    ENTER_PROC("SMI_Probe");
441
442    numDevSections = xf86MatchDevice(SILICONMOTION_DRIVER_NAME, &devSections);
443
444    if (numDevSections <= 0) {
445	/* There's no matching device section in the config file, so quit now. */
446	LEAVE_PROC("SMI_Probe");
447	return FALSE;
448    }
449
450    if (xf86GetPciVideoInfo() == NULL) {
451	LEAVE_PROC("SMI_Probe");
452	return FALSE;
453    }
454
455    numUsed = xf86MatchPciInstances(SILICONMOTION_NAME, PCI_SMI_VENDOR_ID,
456				    SMIChipsets, SMIPciChipsets, devSections,
457				    numDevSections, drv, &usedChips);
458
459    /* Free it since we don't need that list after this */
460    xfree(devSections);
461    if (numUsed <= 0) {
462	LEAVE_PROC("SMI_Probe");
463	return FALSE;
464    }
465
466    if (flags & PROBE_DETECT) {
467		foundScreen = TRUE;
468    } else {
469	for (i = 0; i < numUsed; i++) {
470	    /* Allocate a ScrnInfoRec and claim the slot */
471	    ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
472
473	    /* Fill in what we can of the ScrnInfoRec */
474	    pScrn->driverVersion = SILICONMOTION_DRIVER_VERSION;
475	    pScrn->driverName	 = SILICONMOTION_DRIVER_NAME;
476	    pScrn->name		 = SILICONMOTION_NAME;
477	    pScrn->Probe	 = SMI_Probe;
478	    pScrn->PreInit	 = SMI_PreInit;
479	    pScrn->ScreenInit	 = SMI_ScreenInit;
480	    pScrn->SwitchMode	 = SMI_SwitchMode;
481	    pScrn->AdjustFrame	 = SMI_AdjustFrame;
482	    pScrn->EnterVT	 = SMI_EnterVT;
483	    pScrn->LeaveVT	 = SMI_LeaveVT;
484	    pScrn->FreeScreen	 = SMI_FreeScreen;
485	    pScrn->ValidMode	 = SMI_ValidMode;
486	    foundScreen		 = TRUE;
487
488	    xf86ConfigActivePciEntity(pScrn, usedChips[i], SMIPciChipsets, NULL,
489				      NULL, NULL, NULL, NULL);
490	}
491    }
492    xfree(usedChips);
493
494    LEAVE_PROC("SMI_Probe");
495    return foundScreen;
496}
497
498static Bool
499SMI_PreInit(ScrnInfoPtr pScrn, int flags)
500{
501    EntityInfoPtr pEnt;
502    SMIPtr pSmi;
503    MessageType from;
504    int i;
505    double real;
506    ClockRangePtr clockRanges;
507    char *s;
508    unsigned char config, m, n, shift;
509    int mclk;
510    vgaHWPtr hwp;
511    int vgaCRIndex, vgaIOBase;
512    vbeInfoPtr pVbe = NULL;
513
514    ENTER_PROC("SMI_PreInit");
515
516    if (flags & PROBE_DETECT) {
517	SMI_ProbeDDC(pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index);
518	LEAVE_PROC("SMI_PreInit");
519	return TRUE;
520    }
521
522    /* Ignoring the Type list for now.  It might be needed when multiple cards
523     * are supported.
524     */
525    if (pScrn->numEntities > 1) {
526	LEAVE_PROC("SMI_PreInit");
527	return FALSE;
528    }
529
530    /* The vgahw module should be loaded here when needed */
531    if (!xf86LoadSubModule(pScrn, "vgahw")) {
532	LEAVE_PROC("SMI_PreInit");
533	return FALSE;
534    }
535
536    xf86LoaderReqSymLists(vgahwSymbols, NULL);
537
538    /*
539     * Allocate a vgaHWRec
540     */
541    if (!vgaHWGetHWRec(pScrn)) {
542	LEAVE_PROC("SMI_PreInit");
543	return FALSE;
544    }
545
546    /* Allocate the SMIRec driverPrivate */
547    if (!SMI_GetRec(pScrn)) {
548	LEAVE_PROC("SMI_PreInit");
549	return FALSE;
550    }
551    pSmi = SMIPTR(pScrn);
552
553    /* Set pScrn->monitor */
554    pScrn->monitor = pScrn->confScreen->monitor;
555
556    /*
557     * The first thing we should figure out is the depth, bpp, etc.
558     */
559    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) {
560	LEAVE_PROC("SMI_PreInit");
561	return FALSE;
562    }
563
564    /* Check that the returned depth is one we support */
565    switch (pScrn->depth) {
566    case 8:
567    case 16:
568    case 24:
569	/* OK */
570	break;
571
572    default:
573	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
574		   "Given depth (%d) is not supported by this driver\n",
575		   pScrn->depth);
576	LEAVE_PROC("SMI_PreInit");
577	return FALSE;
578    }
579
580    xf86PrintDepthBpp(pScrn);
581
582    /*
583     * This must happen after pScrn->display has been set because
584     * xf86SetWeight references it.
585     */
586    if (pScrn->depth > 8) {
587	/* The defaults are OK for us */
588	rgb zeros = {0, 0, 0};
589
590	if (!xf86SetWeight(pScrn, zeros, zeros)) {
591	    LEAVE_PROC("SMI_PreInit");
592	    return FALSE;
593	}
594    }
595
596    if (!xf86SetDefaultVisual(pScrn, -1)) {
597	LEAVE_PROC("SMI_PreInit");
598	return FALSE;
599    }
600
601    /* We don't currently support DirectColor at > 8bpp */
602    if ((pScrn->depth > 8) && (pScrn->defaultVisual != TrueColor)) {
603	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual (%s) "
604		   "is not supported at depth %d\n",
605		   xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
606	LEAVE_PROC("SMI_PreInit");
607	return FALSE;
608    }
609
610    /* We use a programmable clock */
611    pScrn->progClock = TRUE;
612
613    /* Collect all of the relevant option flags (fill in pScrn->options) */
614    xf86CollectOptions(pScrn, NULL);
615
616    /* Set the bits per RGB for 8bpp mode */
617    if (pScrn->depth == 8) {
618	pScrn->rgbBits = 6;
619    }
620
621    /* Process the options */
622    if (!(pSmi->Options = xalloc(sizeof(SMIOptions))))
623	return FALSE;
624    memcpy(pSmi->Options, SMIOptions, sizeof(SMIOptions));
625    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pSmi->Options);
626
627    if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_BURST, FALSE)) {
628	pSmi->pci_burst = TRUE;
629	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_burst - PCI burst "
630		   "read enabled\n");
631    } else {
632	pSmi->pci_burst = FALSE;
633    }
634
635    pSmi->NoPCIRetry = TRUE;
636    if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_RETRY, FALSE)) {
637	if (xf86ReturnOptValBool(pSmi->Options, OPTION_PCI_BURST, FALSE)) {
638	    pSmi->NoPCIRetry = FALSE;
639	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
640	} else {
641	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option "
642		       "requires \"pci_burst\".\n");
643	}
644    }
645
646    if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_CONSERV)) {
647	pSmi->fifo_conservative = TRUE;
648	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_conservative "
649		   "set\n");
650    } else {
651	pSmi->fifo_conservative = FALSE;
652    }
653
654    if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_MODERATE)) {
655	pSmi->fifo_moderate = TRUE;
656	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_moderate set\n");
657    } else {
658	pSmi->fifo_moderate = FALSE;
659    }
660
661    if (xf86IsOptionSet(pSmi->Options, OPTION_FIFO_AGGRESSIVE)) {
662	pSmi->fifo_aggressive = TRUE;
663	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: fifo_aggressive set\n");
664    } else {
665	pSmi->fifo_aggressive = FALSE;
666    }
667
668    if (xf86ReturnOptValBool(pSmi->Options, OPTION_NOACCEL, FALSE)) {
669	pSmi->NoAccel = TRUE;
670	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: NoAccel - Acceleration "
671		   "disabled\n");
672    } else {
673	pSmi->NoAccel = FALSE;
674    }
675
676    if (xf86ReturnOptValBool(pSmi->Options, OPTION_SHOWCACHE, FALSE)) {
677	pSmi->ShowCache = TRUE;
678	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: show_cache set\n");
679    } else {
680	pSmi->ShowCache = FALSE;
681    }
682
683    if (xf86GetOptValFreq(pSmi->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) {
684	pSmi->MCLK = (int)(real * 1000.0);
685	if (pSmi->MCLK <= 120000) {
686	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: set_mclk set to "
687		       "%1.3f MHz\n", pSmi->MCLK / 1000.0);
688	} else {
689	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Memory Clock value of "
690		       "%1.3f MHz is larger than limit of 120 MHz\n",
691		       pSmi->MCLK / 1000.0);
692	    pSmi->MCLK = 0;
693	}
694    } else {
695	pSmi->MCLK = 0;
696    }
697
698    from = X_DEFAULT;
699    pSmi->hwcursor = TRUE;
700    if (xf86GetOptValBool(pSmi->Options, OPTION_HWCURSOR, &pSmi->hwcursor)) {
701	from = X_CONFIG;
702    }
703    if (xf86ReturnOptValBool(pSmi->Options, OPTION_SWCURSOR, FALSE)) {
704	pSmi->hwcursor = FALSE;
705	from = X_CONFIG;
706    }
707    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s Cursor\n",
708	       pSmi->hwcursor ? "Hardware" : "Software");
709
710    if (xf86GetOptValBool(pSmi->Options, OPTION_SHADOW_FB, &pSmi->shadowFB)) {
711	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowFB %s.\n",
712		   pSmi->shadowFB ? "enabled" : "disabled");
713    }
714
715#if 1 /* PDR#932 */
716    if ((pScrn->depth == 8) || (pScrn->depth == 16))
717#endif /* PDR#932 */
718	if ((s = xf86GetOptValString(pSmi->Options, OPTION_ROTATE))) {
719	    if (!xf86NameCmp(s, "CW")) {
720		pSmi->shadowFB = TRUE;
721		pSmi->rotate = SMI_ROTATE_CCW;
722		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen "
723			   "clockwise\n");
724	    } else if (!xf86NameCmp(s, "CCW")) {
725		pSmi->shadowFB = TRUE;
726		pSmi->rotate = SMI_ROTATE_CW;
727		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen counter "
728			   "clockwise\n");
729	    } else {
730		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid "
731			   "value for Option \"Rotate\"\n", s);
732		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are \"CW\" or "
733			   "\"CCW\"\n");
734	    }
735	}
736
737    if (pSmi->rotate) {
738	/* Disable the RandR extension, it messes up the internal rotation stuff */
739	xf86DisableRandR();
740    }
741
742    if (xf86GetOptValInteger(pSmi->Options, OPTION_VIDEOKEY, &pSmi->videoKey)) {
743	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Video key set to "
744		   "0x%08X\n", pSmi->videoKey);
745    } else {
746	pSmi->videoKey = (1 << pScrn->offset.red) |
747			 (1 << pScrn->offset.green) |
748			 (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
749			 << pScrn->offset.blue);
750    }
751
752    if (xf86ReturnOptValBool(pSmi->Options, OPTION_BYTESWAP, FALSE)) {
753	pSmi->ByteSwap = TRUE;
754	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ByteSwap enabled.\n");
755    } else {
756	pSmi->ByteSwap = FALSE;
757    }
758
759    /* CZ 26.10.2001: interlaced video */
760    if (xf86ReturnOptValBool(pSmi->Options, OPTION_INTERLACED, FALSE)) {
761	pSmi->interlaced = TRUE;
762	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Interlaced enabled.\n");
763    } else {
764	pSmi->interlaced = FALSE;
765    }
766    /* end CZ */
767
768    if (xf86GetOptValBool(pSmi->Options, OPTION_USEBIOS, &pSmi->useBIOS)) {
769	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: UseBIOS %s.\n",
770		   pSmi->useBIOS ? "enabled" : "disabled");
771    } else {
772	/* Default to UseBIOS enabled. */
773	pSmi->useBIOS = TRUE;
774    }
775
776    if (xf86GetOptValBool(pSmi->Options, OPTION_ZOOMONLCD, &pSmi->zoomOnLCD)) {
777	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ZoomOnLCD %s.\n",
778		   pSmi->zoomOnLCD ? "enabled" : "disabled");
779    } else {
780	/* Default to ZoomOnLCD enabled. */
781	pSmi->zoomOnLCD = TRUE;
782    }
783
784    /* Find the PCI slot for this screen */
785    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
786    if ((pEnt->location.type != BUS_PCI) || (pEnt->resources)) {
787	xfree(pEnt);
788	SMI_FreeRec(pScrn);
789	LEAVE_PROC("SMI_PreInit");
790	return FALSE;
791    }
792
793    if (xf86LoadSubModule(pScrn,"int10")) {
794	xf86LoaderReqSymLists(int10Symbols,NULL);
795	pSmi->pInt10 = xf86InitInt10(pEnt->index);
796    }
797
798    if (pSmi->pInt10 && xf86LoadSubModule(pScrn, "vbe")) {
799	xf86LoaderReqSymLists(vbeSymbols, NULL);
800	pVbe = VBEInit(pSmi->pInt10, pEnt->index);
801    }
802
803    pSmi->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
804    xf86RegisterResources(pEnt->index, NULL, ResExclusive);
805/*  xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr); */
806/*  xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr); */
807
808    /*
809     * Set the Chipset and ChipRev, allowing config file entries to
810     * override.
811     */
812    if (pEnt->device->chipset && *pEnt->device->chipset) {
813	pScrn->chipset = pEnt->device->chipset;
814	pSmi->Chipset = xf86StringToToken(SMIChipsets, pScrn->chipset);
815	from = X_CONFIG;
816    } else if (pEnt->device->chipID >= 0) {
817	pSmi->Chipset = pEnt->device->chipID;
818	pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset);
819	from = X_CONFIG;
820	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
821		   pSmi->Chipset);
822    } else {
823	from = X_PROBED;
824	pSmi->Chipset = pSmi->PciInfo->chipType;
825	pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset);
826    }
827
828    if (pEnt->device->chipRev >= 0) {
829	pSmi->ChipRev = pEnt->device->chipRev;
830	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
831		   pSmi->ChipRev);
832    } else {
833	pSmi->ChipRev = pSmi->PciInfo->chipRev;
834    }
835    xfree(pEnt);
836
837    /*
838     * This shouldn't happen because such problems should be caught in
839     * SMI_Probe(), but check it just in case.
840     */
841    if (pScrn->chipset == NULL) {
842	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04X is not "
843				"recognised\n", pSmi->Chipset);
844	LEAVE_PROC("SMI_PreInit");
845	return FALSE;
846    }
847
848    if (pSmi->Chipset < 0) {
849	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not "
850		   "recognised\n", pScrn->chipset);
851	LEAVE_PROC("SMI_PreInit");
852	return FALSE;
853    }
854
855    xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
856
857    pSmi->PciTag = pciTag(pSmi->PciInfo->bus, pSmi->PciInfo->device,
858		   	  pSmi->PciInfo->func);
859
860    pSmi->Dualhead = FALSE;
861    if (xf86ReturnOptValBool(pSmi->Options, OPTION_DUALHEAD, FALSE) &&
862	SMI_LYNXM_SERIES(pSmi->Chipset)) {
863	pSmi->Dualhead = TRUE;
864    }
865
866    /* tweak options for dualhead */
867    if (pSmi->Dualhead) {
868	pSmi->useBIOS = FALSE;
869	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UseBIOS disabled in dualhead mode\n");
870	pSmi->hwcursor = FALSE;
871	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No hardware cursor in dualhead mode\n");
872	if (pScrn->bitsPerPixel != 16) {
873	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Dualhead only supported at "
874		       "depth 16\n");
875	    return FALSE;
876	}
877    }
878
879    SMI_MapMem(pScrn);
880    SMI_DisableVideo(pScrn);
881
882    hwp = VGAHWPTR(pScrn);
883    vgaIOBase  = hwp->IOBase;
884    vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
885    pSmi->PIOBase = hwp->PIOOffset;
886
887    xf86ErrorFVerb(VERBLEV, "\tSMI_PreInit vgaCRIndex=%x, vgaIOBase=%x, "
888		   "MMIOBase=%p\n", vgaCRIndex, vgaIOBase, hwp->MMIOBase);
889
890    /* detect the panel size */
891    SMI_DetectPanelSize(pScrn);
892
893    if (xf86LoadSubModule(pScrn, "i2c")) {
894	xf86LoaderReqSymLists(i2cSymbols, NULL);
895	SMI_I2CInit(pScrn);
896    }
897
898    if (xf86LoadSubModule(pScrn, "ddc")) {
899	xf86MonPtr pMon = NULL;
900
901	xf86LoaderReqSymLists(ddcSymbols, NULL);
902#if 1 /* PDR#579 */
903	if (pVbe) {
904	    pMon = vbeDoEDID(pVbe, NULL);
905	    if (pMon != NULL) {
906		if ((pMon->rawData[0] == 0x00) &&
907		    (pMon->rawData[1] == 0xFF) &&
908		    (pMon->rawData[2] == 0xFF) &&
909		    (pMon->rawData[3] == 0xFF) &&
910		    (pMon->rawData[4] == 0xFF) &&
911		    (pMon->rawData[5] == 0xFF) &&
912		    (pMon->rawData[6] == 0xFF) &&
913		    (pMon->rawData[7] == 0x00)) {
914		    pMon = xf86PrintEDID(pMon);
915		    if (pMon != NULL) {
916			xf86SetDDCproperties(pScrn, pMon);
917		    }
918		}
919	    }
920#else
921	if ((pVbe) &&
922	    ((pMon = xf86PrintEDID(vbeDoEDID(pVbe, NULL))) != NULL)) {
923	    xf86SetDDCproperties(pScrn, pMon);
924#endif
925    	} else if (!SMI_ddc1(pScrn->scrnIndex)) {
926	    if (pSmi->I2C) {
927	    	xf86SetDDCproperties(pScrn,
928			xf86PrintEDID(xf86DoEDID_DDC2(pScrn->scrnIndex,
929			pSmi->I2C)));
930	    }
931    	}
932    }
933
934    vbeFree(pVbe);
935    xf86FreeInt10(pSmi->pInt10);
936    pSmi->pInt10 = NULL;
937
938    /*
939     * If the driver can do gamma correction, it should call xf86SetGamma()
940     * here. (from MGA, no ViRGE gamma support yet, but needed for
941     * xf86HandleColormaps support.)
942     */
943    {
944	Gamma zeros = { 0.0, 0.0, 0.0 };
945
946	if (!xf86SetGamma(pScrn, zeros)) {
947	    LEAVE_PROC("SMI_PreInit");
948	    SMI_EnableVideo(pScrn);
949	    SMI_UnmapMem(pScrn);
950	    return FALSE;
951	}
952    }
953
954
955    /* Next go on to detect amount of installed ram */
956    config = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71);
957
958    /* And compute the amount of video memory and offscreen memory */
959    pSmi->videoRAMKBytes = 0;
960
961    if (!pScrn->videoRam) {
962	switch (pSmi->Chipset) {
963	default:
964	{
965	    int mem_table[4] = { 1, 2, 4, 0 };
966	    pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024;
967	    break;
968	}
969	case SMI_LYNX3D:
970	{
971	    int mem_table[4] = { 0, 2, 4, 6 };
972	    pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024 + 512;
973	    break;
974	}
975	case SMI_LYNX3DM:
976	{
977	    int mem_table[4] = { 16, 2, 4, 8 };
978	    pSmi->videoRAMKBytes = mem_table[(config >> 6)] * 1024;
979	    break;
980	}
981	case SMI_COUGAR3DR:
982	{
983	    /* DANGER - Cougar3DR BIOS is broken - hardcode video ram size */
984	    /* per instructions from Silicon Motion engineers */
985	    pSmi->videoRAMKBytes = 16 * 1024;
986	    break;
987        }
988	}
989	pSmi->videoRAMBytes = pSmi->videoRAMKBytes * 1024;
990	pScrn->videoRam     = pSmi->videoRAMKBytes;
991
992	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "videoram: %dkB\n",
993		   pSmi->videoRAMKBytes);
994    } else {
995	pSmi->videoRAMKBytes = pScrn->videoRam;
996	pSmi->videoRAMBytes  = pScrn->videoRam * 1024;
997
998	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "videoram: %dk\n",
999		   pSmi->videoRAMKBytes);
1000    }
1001
1002    /* Detect current MCLK and print it for user */
1003    m = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A);
1004    n = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B);
1005    switch (n >> 6) {
1006    default:
1007	shift = 1;
1008	break;
1009    case 1:
1010	shift = 4;
1011	break;
1012    case 2:
1013	shift = 2;
1014	break;
1015    }
1016    n &= 0x3F;
1017    mclk = ((1431818 * m) / n / shift + 50) / 100;
1018    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of "
1019	       "%1.3f MHz\n", mclk / 1000.0);
1020
1021    SMI_EnableVideo(pScrn);
1022    SMI_UnmapMem(pScrn);
1023
1024    pSmi->IsSwitching = FALSE;
1025
1026    if (pSmi->Dualhead) {
1027	pScrn->display->virtualX = 2 * pSmi->lcdWidth;
1028	pScrn->display->virtualY = pSmi->lcdHeight;
1029    }
1030
1031    pScrn->virtualX = pScrn->display->virtualX;
1032
1033    /*
1034     * Setup the ClockRanges, which describe what clock ranges are available,
1035     * and what sort of modes they can be used for.
1036     */
1037    clockRanges = xnfcalloc(sizeof(ClockRange),1);
1038    clockRanges->next = NULL;
1039    clockRanges->minClock = 20000;
1040
1041    if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR))
1042	clockRanges->maxClock = 200000;
1043    else
1044        clockRanges->maxClock = 135000;
1045
1046    clockRanges->clockIndex = -1;
1047    clockRanges->interlaceAllowed = FALSE;
1048    clockRanges->doubleScanAllowed = FALSE;
1049
1050    i = xf86ValidateModes(
1051		pScrn,				/* Screen pointer			  */
1052		pScrn->monitor->Modes,		/* Available monitor modes		  */
1053		pScrn->display->modes,		/* req mode names for screen		  */
1054		clockRanges,			/* list of clock ranges allowed		  */
1055		NULL,				/* use min/max below			  */
1056		128,				/* min line pitch (width)		  */
1057		4096,				/* maximum line pitch (width)		  */
1058		128,				/* bits of granularity for line pitch     */
1059						/* (width) above			  */
1060		128,				/* min virtual height			  */
1061		4096,				/* max virtual height			  */
1062		pScrn->display->virtualX,	/* force virtual x			  */
1063		pScrn->display->virtualY,	/* force virtual Y			  */
1064		pSmi->videoRAMBytes,		/* size of aperture used to access	  */
1065						/* video memory				  */
1066		LOOKUP_BEST_REFRESH);		/* how to pick modes			  */
1067
1068    if (i == -1) {
1069	SMI_FreeRec(pScrn);
1070	LEAVE_PROC("SMI_PreInit");
1071	return FALSE;
1072    }
1073
1074    /* Prune the modes marked as invalid */
1075    xf86PruneDriverModes(pScrn);
1076
1077    if ((i == 0) || (pScrn->modes == NULL)) {
1078	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1079	SMI_FreeRec(pScrn);
1080	LEAVE_PROC("SMI_PreInit");
1081	return FALSE;
1082    }
1083    xf86SetCrtcForModes(pScrn, 0);
1084
1085    /* Set the current mode to the first in the list */
1086    pScrn->currentMode = pScrn->modes;
1087
1088    /* Print the list of modes being used */
1089    xf86PrintModes(pScrn);
1090
1091    /* Set display resolution */
1092    xf86SetDpi(pScrn, 0, 0);
1093
1094    if ((xf86LoadSubModule(pScrn, "fb") == NULL)) {
1095	SMI_FreeRec(pScrn);
1096	LEAVE_PROC("SMI_PreInit");
1097	return FALSE;
1098    }
1099
1100    if (!pSmi->NoAccel) {
1101	from = X_DEFAULT;
1102	char *strptr;
1103
1104	if ((strptr = (char *)xf86GetOptValString(pSmi->Options, OPTION_ACCELMETHOD))) {
1105	    if (!xf86NameCmp(strptr,"XAA")) {
1106		from = X_CONFIG;
1107		pSmi->useEXA = FALSE;
1108	    } else if(!xf86NameCmp(strptr,"EXA")) {
1109		from = X_CONFIG;
1110		pSmi->useEXA = TRUE;
1111	    }
1112	}
1113
1114	xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration architecture\n",
1115        	pSmi->useEXA ? "EXA" : "XAA");
1116    }
1117
1118    xf86LoaderReqSymLists(fbSymbols, NULL);
1119
1120    /* Load XAA or EXA if needed */
1121    if (!pSmi->NoAccel) {
1122	if (!pSmi->useEXA) {
1123	    if (!xf86LoadSubModule(pScrn, "xaa")) {
1124		SMI_FreeRec(pScrn);
1125		LEAVE_PROC("SMI_PreInit");
1126		return FALSE;
1127	    }
1128	    xf86LoaderReqSymLists(xaaSymbols, NULL);
1129	} else {
1130	    XF86ModReqInfo req;
1131	    int errmaj, errmin;
1132
1133	    memset(&req, 0, sizeof(XF86ModReqInfo));
1134	    req.majorversion = 2;
1135	    req.minorversion = 0;
1136
1137	    if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL,
1138				&req, &errmaj, &errmin)) {
1139		LoaderErrorMsg(NULL, "exa", errmaj, errmin);
1140		SMI_FreeRec(pScrn);
1141		LEAVE_PROC("SMI_PreInit");
1142		return FALSE;
1143	    }
1144	    xf86LoaderReqSymLists(exaSymbols, NULL);
1145	}
1146    }
1147
1148    /* Load ramdac if needed */
1149    if (pSmi->hwcursor) {
1150	if (!xf86LoadSubModule(pScrn, "ramdac")) {
1151	    SMI_FreeRec(pScrn);
1152	    LEAVE_PROC("SMI_PreInit");
1153	    return FALSE;
1154	}
1155	xf86LoaderReqSymLists(ramdacSymbols, NULL);
1156    }
1157
1158    if (pSmi->shadowFB) {
1159	if (!xf86LoadSubModule(pScrn, "shadowfb")) {
1160	    SMI_FreeRec(pScrn);
1161	    LEAVE_PROC("SMI_PreInit");
1162	    return FALSE;
1163	}
1164	xf86LoaderReqSymLists(shadowSymbols, NULL);
1165    }
1166
1167    LEAVE_PROC("SMI_PreInit");
1168    return TRUE;
1169}
1170
1171/*
1172 * This is called when VT switching back to the X server.  Its job is to
1173 * reinitialise the video mode. We may wish to unmap video/MMIO memory too.
1174 */
1175
1176static Bool
1177SMI_EnterVT(int scrnIndex, int flags)
1178{
1179    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1180    SMIPtr pSmi = SMIPTR(pScrn);
1181    Bool ret;
1182
1183    ENTER_PROC("SMI_EnterVT");
1184
1185    /* Enable MMIO and map memory */
1186    SMI_MapMem(pScrn);
1187    SMI_Save(pScrn);
1188
1189    /* #670 */
1190    if (pSmi->shadowFB) {
1191	pSmi->FBOffset = pSmi->savedFBOffset;
1192	pSmi->FBReserved = pSmi->savedFBReserved;
1193    }
1194
1195    ret = SMI_ModeInit(pScrn, pScrn->currentMode);
1196
1197    /* #670 */
1198    if (ret && pSmi->shadowFB) {
1199	BoxRec box;
1200
1201	/* #920 */
1202	if (pSmi->paletteBuffer) {
1203	    int i;
1204
1205	    VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0);
1206	    for (i = 0; i < 256 * 3; i++) {
1207		VGAOUT8(pSmi, VGA_DAC_DATA, pSmi->paletteBuffer[i]);
1208	    }
1209	    xfree(pSmi->paletteBuffer);
1210	    pSmi->paletteBuffer = NULL;
1211	}
1212
1213	if (pSmi->pSaveBuffer) {
1214	    memcpy(pSmi->FBBase, pSmi->pSaveBuffer, pSmi->saveBufferSize);
1215	    xfree(pSmi->pSaveBuffer);
1216	    pSmi->pSaveBuffer = NULL;
1217	}
1218
1219	box.x1 = 0;
1220	box.y1 = 0;
1221	box.x2 = pScrn->virtualY;
1222	box.y2 = pScrn->virtualX;
1223	if (pSmi->Chipset == SMI_COUGAR3DR) {
1224	    SMI_RefreshArea730(pScrn, 1, &box);
1225	} else {
1226	    SMI_RefreshArea(pScrn, 1, &box);
1227	}
1228    }
1229
1230    /* Reset the grapics engine */
1231    if (!pSmi->NoAccel)
1232	SMI_EngineReset(pScrn);
1233
1234    LEAVE_PROC("SMI_EnterVT");
1235    return ret;
1236}
1237
1238/*
1239 * This is called when VT switching away from the X server.  Its job is to
1240 * restore the previous (text) mode. We may wish to remap video/MMIO memory
1241 * too.
1242 */
1243
1244static void
1245SMI_LeaveVT(int scrnIndex, int flags)
1246{
1247    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1248    vgaHWPtr hwp = VGAHWPTR(pScrn);
1249    SMIPtr pSmi = SMIPTR(pScrn);
1250    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
1251    SMIRegPtr SMISavePtr = &pSmi->SavedReg;
1252
1253    ENTER_PROC("SMI_LeaveVT");
1254
1255    /* #670 */
1256    if (pSmi->shadowFB) {
1257	pSmi->pSaveBuffer = xnfalloc(pSmi->saveBufferSize);
1258	if (pSmi->pSaveBuffer) {
1259	    memcpy(pSmi->pSaveBuffer, pSmi->FBBase, pSmi->saveBufferSize);
1260	}
1261
1262	pSmi->savedFBOffset = pSmi->FBOffset;
1263	pSmi->savedFBReserved = pSmi->FBReserved;
1264
1265	/* #920 */
1266	if (pSmi->Bpp == 1) {
1267	    pSmi->paletteBuffer = xnfalloc(256 * 3);
1268	    if (pSmi->paletteBuffer) {
1269		int i;
1270
1271		VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0);
1272		for (i = 0; i < 256 * 3; i++) {
1273		    pSmi->paletteBuffer[i] = VGAIN8(pSmi, VGA_DAC_DATA);
1274		}
1275	    }
1276	}
1277    }
1278
1279    memset(pSmi->FBBase, 0, 256 * 1024);	/* #689 */
1280    SMI_WriteMode(pScrn, vgaSavePtr, SMISavePtr);
1281    SMI_UnmapMem(pScrn);
1282
1283    LEAVE_PROC("SMI_LeaveVT");
1284}
1285
1286/*
1287 * This function performs the inverse of the restore function: It saves all the
1288 * standard and extended registers that we are going to modify to set up a video
1289 * mode.
1290 */
1291
1292static void
1293SMI_Save(ScrnInfoPtr pScrn)
1294{
1295    int i;
1296    CARD32 offset;
1297
1298    vgaHWPtr hwp         = VGAHWPTR(pScrn);
1299    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
1300    SMIPtr pSmi          = SMIPTR(pScrn);
1301    SMIRegPtr save       = &pSmi->SavedReg;
1302
1303    int vgaIOBase  = hwp->IOBase;
1304    int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
1305    int vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
1306
1307    ENTER_PROC("SMI_Save");
1308
1309    /* Save the standard VGA registers */
1310    vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
1311    save->smiDACMask = VGAIN8(pSmi, VGA_DAC_MASK);
1312    VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0);
1313    for (i = 0; i < 256; i++) {
1314	save->smiDacRegs[i][0] = VGAIN8(pSmi, VGA_DAC_DATA);
1315	save->smiDacRegs[i][1] = VGAIN8(pSmi, VGA_DAC_DATA);
1316	save->smiDacRegs[i][2] = VGAIN8(pSmi, VGA_DAC_DATA);
1317    }
1318    for (i = 0, offset = 2; i < 8192; i++, offset += 8) {
1319	save->smiFont[i] = *(pSmi->FBBase + offset);
1320    }
1321
1322    /* Now we save all the extended registers we need. */
1323    save->SR17 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17);
1324    save->SR18 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18);
1325    save->SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
1326    save->SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
1327    save->SR32 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32);
1328    save->SR6A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A);
1329    save->SR6B = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B);
1330    save->SR81 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81);
1331    save->SRA0 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0);
1332
1333    /* vclk1 */
1334    save->SR6C = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C);
1335    save->SR6D = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D);
1336    /* vclk1 control */
1337    save->SR68 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x68);
1338
1339    if (pSmi->Dualhead) {
1340	/* dualhead stuff */
1341	save->SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22);
1342	save->SR40 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40);
1343	save->SR41 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41);
1344	save->SR42 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42);
1345	save->SR43 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43);
1346	save->SR44 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44);
1347	save->SR45 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45);
1348	save->SR48 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48);
1349	save->SR49 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49);
1350	save->SR4A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A);
1351	save->SR4B = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B);
1352	save->SR4C = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C);
1353	/* PLL2 stuff */
1354	save->SR69 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x69);
1355	save->SR6E = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E);
1356	save->SR6F = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F);
1357    }
1358
1359    if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
1360	/* Save primary registers */
1361	save->CR90[14] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E);
1362	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14] & ~0x20);
1363
1364	for (i = 0; i < 16; i++) {
1365	    save->CR90[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i);
1366	}
1367	save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
1368	save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A);
1369	for (i = 0; i < 14; i++) {
1370	    save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
1371	}
1372
1373	/* Save secondary registers */
1374	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14] | 0x20);
1375	save->CR33_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
1376	for (i = 0; i < 14; i++) {
1377	    save->CR40_2[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
1378	}
1379	save->CR9F_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F);
1380
1381	/* Save common registers */
1382	for (i = 0; i < 14; i++) {
1383	    save->CRA0[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i);
1384	}
1385
1386	/* PDR#1069 */
1387	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14]);
1388    } else {
1389	save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
1390	save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A);
1391	for (i = 0; i < 14; i++) {
1392	    save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
1393	}
1394    }
1395
1396    /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
1397    if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR)) {
1398	save->CCR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
1399    }
1400    /* end CZ */
1401
1402    save->DPR10 = READ_DPR(pSmi, 0x10);
1403    save->DPR1C = READ_DPR(pSmi, 0x1C);
1404    save->DPR20 = READ_DPR(pSmi, 0x20);
1405    save->DPR24 = READ_DPR(pSmi, 0x24);
1406    save->DPR28 = READ_DPR(pSmi, 0x28);
1407    save->DPR2C = READ_DPR(pSmi, 0x2C);
1408    save->DPR30 = READ_DPR(pSmi, 0x30);
1409    save->DPR3C = READ_DPR(pSmi, 0x3C);
1410    save->DPR40 = READ_DPR(pSmi, 0x40);
1411    save->DPR44 = READ_DPR(pSmi, 0x44);
1412
1413    save->VPR00 = READ_VPR(pSmi, 0x00);
1414    save->VPR0C = READ_VPR(pSmi, 0x0C);
1415    save->VPR10 = READ_VPR(pSmi, 0x10);
1416
1417    if (pSmi->Chipset == SMI_COUGAR3DR) {
1418	save->FPR00_ = READ_FPR(pSmi, FPR00);
1419	save->FPR0C_ = READ_FPR(pSmi, FPR0C);
1420	save->FPR10_ = READ_FPR(pSmi, FPR10);
1421    }
1422
1423    save->CPR00 = READ_CPR(pSmi, 0x00);
1424
1425    if (!pSmi->ModeStructInit) {
1426	/* XXX Should check the return value of vgaHWCopyReg() */
1427	vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
1428	memcpy(&pSmi->ModeReg, save, sizeof(SMIRegRec));
1429	pSmi->ModeStructInit = TRUE;
1430    }
1431
1432    if (pSmi->useBIOS && (pSmi->pInt10 != NULL)) {
1433	pSmi->pInt10->num = 0x10;
1434	pSmi->pInt10->ax = 0x0F00;
1435	xf86ExecX86int10(pSmi->pInt10);
1436	save->mode = pSmi->pInt10->ax & 0x007F;
1437	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Current mode 0x%02X.\n",
1438		   save->mode);
1439    }
1440
1441    if (xf86GetVerbosity() > 1) {
1442	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1443		       "Saved current video mode.  Register dump:\n");
1444	SMI_PrintRegs(pScrn);
1445    }
1446
1447    LEAVE_PROC("SMI_Save");
1448}
1449
1450/*
1451 * This function is used to restore a video mode. It writes out all of the
1452 * standard VGA and extended registers needed to setup a video mode.
1453 */
1454
1455static void
1456SMI_WriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, SMIRegPtr restore)
1457{
1458    int i;
1459    CARD8 tmp;
1460    CARD32 offset;
1461
1462    vgaHWPtr hwp   = VGAHWPTR(pScrn);
1463    SMIPtr pSmi    = SMIPTR(pScrn);
1464    int vgaIOBase  = hwp->IOBase;
1465    int vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
1466    int vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
1467
1468    ENTER_PROC("SMI_WriteMode");
1469
1470    vgaHWProtect(pScrn, TRUE);
1471
1472    /* Wait for engine to become idle */
1473    if (pSmi->IsSwitching)
1474	WaitIdle();
1475
1476    if (pSmi->useBIOS && (pSmi->pInt10 != NULL) && (restore->mode != 0)) {
1477	pSmi->pInt10->num = 0x10;
1478	pSmi->pInt10->ax = restore->mode | 0x80;
1479	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%02X\n",
1480		   restore->mode);
1481	xf86ExecX86int10(pSmi->pInt10);
1482
1483	/* Enable linear mode. */
1484	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
1485	tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
1486	outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x01);
1487
1488	/* Enable DPR/VPR registers. */
1489	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
1490	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03);
1491    } else {
1492	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17, restore->SR17);
1493	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18) & ~0x1F;
1494	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18, tmp |
1495		      (restore->SR18 & 0x1F));
1496	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
1497	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03);
1498	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & ~0xC0;
1499	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, tmp |
1500		      (restore->SR31 & 0xC0));
1501	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32) & ~0x07;
1502	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, tmp |
1503		      (restore->SR32 & 0x07));
1504	if (restore->SR6B != 0xFF) {
1505	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A, restore->SR6A);
1506	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B, restore->SR6B);
1507	}
1508	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, restore->SR81);
1509	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0, restore->SRA0);
1510
1511	/* Restore the standard VGA registers */
1512	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
1513	if (restore->smiDACMask) {
1514	    VGAOUT8(pSmi, VGA_DAC_MASK, restore->smiDACMask);
1515	} else {
1516	    VGAOUT8(pSmi, VGA_DAC_MASK, 0xFF);
1517	}
1518	VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0);
1519	for (i = 0; i < 256; i++) {
1520	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][0]);
1521	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][1]);
1522	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][2]);
1523	}
1524	for (i = 0, offset = 2; i < 8192; i++, offset += 8) {
1525	    *(pSmi->FBBase + offset) = restore->smiFont[i];
1526	}
1527
1528	if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
1529	    /* Restore secondary registers */
1530	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E,
1531			  restore->CR90[14] | 0x20);
1532
1533	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33_2);
1534	    for (i = 0; i < 14; i++) {
1535		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
1536			      restore->CR40_2[i]);
1537	    }
1538	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F, restore->CR9F_2);
1539
1540	    /* Restore primary registers */
1541	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E,
1542			  restore->CR90[14] & ~0x20);
1543
1544	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
1545	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A);
1546	    for (i = 0; i < 14; i++) {
1547		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
1548			      restore->CR40[i]);
1549	    }
1550	    for (i = 0; i < 16; i++) {
1551		if (i != 14) {
1552		    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i,
1553				  restore->CR90[i]);
1554		}
1555	    }
1556	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, restore->CR90[14]);
1557
1558	    /* Restore common registers */
1559	    for (i = 0; i < 14; i++) {
1560		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i,
1561			      restore->CRA0[i]);
1562	    }
1563	}
1564
1565	/* Restore the standard VGA registers */
1566	if (xf86IsPrimaryPci(pSmi->PciInfo)) {
1567	    vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP | VGA_SR_FONTS);
1568	}
1569
1570	if (restore->modeInit)
1571	    vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
1572
1573	if (!SMI_LYNXM_SERIES(pSmi->Chipset)) {
1574	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
1575	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A);
1576	    for (i = 0; i < 14; i++) {
1577		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
1578			      restore->CR40[i]);
1579	    }
1580	}
1581
1582	/* vclk1 */
1583	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x68, restore->SR68);
1584	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, restore->SR6C);
1585	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, restore->SR6D);
1586
1587	if (pSmi->Dualhead) {
1588
1589	/* TFT panel uses FIFO1, DSTN panel uses FIFO1 for upper panel and
1590	 * FIFO2 for lower panel.  I don't have a DSTN panel, so it's untested.
1591	 * -- AGD
1592	 */
1593
1594	    /* PLL2 regs */
1595
1596	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x69, restore->SR69);
1597
1598	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E, restore->SR6E);
1599	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F, restore->SR6F);
1600
1601	    /* setting SR21 bit 2 disables ZV circuitry,
1602	     * if ZV is needed, SR21 = 0x20
1603	     */
1604	    /* enable DAC, PLL, etc. */
1605	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, restore->SR21);
1606
1607	    /* clear DPMS state */
1608	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, restore->SR22);
1609
1610	    /* enable virtual refresh and LCD and CRT outputs */
1611	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, restore->SR31);
1612
1613	    /* FIFO1 Read Offset */
1614	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44, restore->SR44);
1615	    /* FIFO2 Read Offset */
1616	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B, restore->SR4B);
1617	    /* FIFO1/2 Read Offset overflow */
1618	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C, restore->SR4C);
1619
1620	    /* FIFO Write Offset */
1621	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48, restore->SR48);
1622	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49, restore->SR49);
1623
1624	    /* set FIFO levels */
1625	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A, restore->SR4A);
1626
1627	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
1628
1629	}
1630    }
1631
1632    /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
1633    if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR)) {
1634	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, restore->CCR66);
1635    }
1636    /* end CZ */
1637
1638    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, 0x00);
1639
1640    /* Reset the graphics engine */
1641    WRITE_DPR(pSmi, 0x10, restore->DPR10);
1642    WRITE_DPR(pSmi, 0x1C, restore->DPR1C);
1643    WRITE_DPR(pSmi, 0x20, restore->DPR20);
1644    WRITE_DPR(pSmi, 0x24, restore->DPR24);
1645    WRITE_DPR(pSmi, 0x28, restore->DPR28);
1646    WRITE_DPR(pSmi, 0x2C, restore->DPR2C);
1647    WRITE_DPR(pSmi, 0x30, restore->DPR30);
1648    WRITE_DPR(pSmi, 0x3C, restore->DPR3C);
1649    WRITE_DPR(pSmi, 0x40, restore->DPR40);
1650    WRITE_DPR(pSmi, 0x44, restore->DPR44);
1651
1652    /* write video controller regs */
1653    WRITE_VPR(pSmi, 0x00, restore->VPR00);
1654    WRITE_VPR(pSmi, 0x0C, restore->VPR0C);
1655    WRITE_VPR(pSmi, 0x10, restore->VPR10);
1656
1657    if(pSmi->Chipset == SMI_COUGAR3DR) {
1658	WRITE_FPR(pSmi, FPR00, restore->FPR00_);
1659	WRITE_FPR(pSmi, FPR0C, restore->FPR0C_);
1660	WRITE_FPR(pSmi, FPR10, restore->FPR10_);
1661    }
1662
1663    WRITE_CPR(pSmi, 0x00, restore->CPR00);
1664
1665    if (xf86GetVerbosity() > 1) {
1666	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1667		       "Done restoring mode.  Register dump:\n");
1668	SMI_PrintRegs(pScrn);
1669    }
1670
1671    vgaHWProtect(pScrn, FALSE);
1672
1673    LEAVE_PROC("SMI_WriteMode");
1674}
1675
1676static void
1677SMI_DetectPanelSize(ScrnInfoPtr pScrn)
1678{
1679    SMIPtr pSmi = SMIPTR(pScrn);
1680
1681    /* panel size detection ... requires BIOS call on 730 hardware */
1682    if (pSmi->Chipset == SMI_COUGAR3DR) {
1683	if (pSmi->pInt10 != NULL) {
1684	    pSmi->pInt10->num = 0x10;
1685	    pSmi->pInt10->ax  = 0x5F00;
1686	    pSmi->pInt10->bx  = 0;
1687	    pSmi->pInt10->cx  = 0;
1688	    pSmi->pInt10->dx  = 0;
1689	    xf86ExecX86int10(pSmi->pInt10);
1690	    if (pSmi->pInt10->ax == 0x005F) {
1691		switch (pSmi->pInt10->cx & 0x0F) {
1692		case PANEL_640x480:
1693		    pSmi->lcdWidth  = 640;
1694		    pSmi->lcdHeight = 480;
1695		    break;
1696		case PANEL_800x600:
1697		    pSmi->lcdWidth  = 800;
1698		    pSmi->lcdHeight = 600;
1699		    break;
1700		case PANEL_1024x768:
1701		    pSmi->lcdWidth  = 1024;
1702		    pSmi->lcdHeight = 768;
1703		    break;
1704		case PANEL_1280x1024:
1705		    pSmi->lcdWidth  = 1280;
1706		    pSmi->lcdHeight = 1024;
1707		    break;
1708		case PANEL_1600x1200:
1709		    pSmi->lcdWidth  = 1600;
1710		    pSmi->lcdHeight = 1200;
1711		    break;
1712		case PANEL_1400x1050:
1713		    pSmi->lcdWidth  = 1400;
1714		    pSmi->lcdHeight = 1050;
1715		    break;
1716		}
1717
1718		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Detected panel size via BIOS: %d x %d\n",
1719			   pSmi->lcdWidth, pSmi->lcdHeight);
1720	    } else {
1721		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS error during 730 panel detection!\n");
1722			   pSmi->lcdWidth  = pScrn->virtualX;
1723		pSmi->lcdHeight = pScrn->virtualY;
1724	    }
1725	} else  {
1726	    /* int10 support isn't setup on the second call to this function,
1727	       so if this is the second call, don't do detection again */
1728	    if (pSmi->lcd == 0) {
1729		/* If we get here, int10 support is not loaded or not working */
1730		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No BIOS support for 730 panel detection!\n");
1731		pSmi->lcdWidth  = pScrn->virtualX;
1732		pSmi->lcdHeight = pScrn->virtualY;
1733	    }
1734	}
1735
1736	/* Set this to indicate that we've done the detection */
1737	pSmi->lcd = 1;
1738    } else {
1739	/* panel size detection for hardware other than 730 */
1740	pSmi->lcd = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31) & 0x01;
1741
1742	if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01) {
1743	    pSmi->lcd <<= 1;
1744	}
1745	switch (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x0C) {
1746	case 0x00:
1747	    pSmi->lcdWidth  = 640;
1748	    pSmi->lcdHeight = 480;
1749	    break;
1750	case 0x04:
1751	    pSmi->lcdWidth  = 800;
1752	    pSmi->lcdHeight = 600;
1753	    break;
1754	case 0x08:
1755	    if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x74) & 0x02) {
1756		pSmi->lcdWidth  = 1024;
1757		pSmi->lcdHeight = 600;
1758	    } else {
1759		pSmi->lcdWidth  = 1024;
1760		pSmi->lcdHeight = 768;
1761	    }
1762	    break;
1763	case 0x0C:
1764	    pSmi->lcdWidth  = 1280;
1765	    pSmi->lcdHeight = 1024;
1766	    break;
1767	}
1768    }
1769
1770    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Panel Size = %dx%d\n",
1771	       (pSmi->lcd == 0) ? "OFF" : (pSmi->lcd == 1) ? "TFT" : "DSTN",
1772	       pSmi->lcdWidth, pSmi->lcdHeight);
1773
1774}
1775
1776static Bool
1777SMI_MapMem(ScrnInfoPtr pScrn)
1778{
1779    SMIPtr pSmi = SMIPTR(pScrn);
1780    vgaHWPtr hwp;
1781    CARD32 memBase;
1782
1783    ENTER_PROC("SMI_MapMem");
1784
1785    /* Map the Lynx register space */
1786    switch (pSmi->Chipset) {
1787    default:
1788	memBase = pSmi->PciInfo->memBase[0] + 0x400000;
1789	pSmi->MapSize = 0x10000;
1790	break;
1791    case SMI_COUGAR3DR:
1792	memBase = pSmi->PciInfo->memBase[1];
1793	pSmi->MapSize = 0x200000;
1794	break;
1795    case SMI_LYNX3D:
1796	memBase = pSmi->PciInfo->memBase[0] + 0x680000;
1797	pSmi->MapSize = 0x180000;
1798	break;
1799    case SMI_LYNXEM:
1800    case SMI_LYNXEMplus:
1801	memBase = pSmi->PciInfo->memBase[0] + 0x400000;
1802	pSmi->MapSize = 0x400000;
1803	break;
1804    case SMI_LYNX3DM:
1805	memBase = pSmi->PciInfo->memBase[0];
1806	pSmi->MapSize = 0x200000;
1807	break;
1808    }
1809    pSmi->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pSmi->PciTag,
1810				  memBase, pSmi->MapSize);
1811
1812    if (pSmi->MapBase == NULL) {
1813	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not map "
1814		   "MMIO registers.\n");
1815	LEAVE_PROC("SMI_MapMem");
1816	return FALSE;
1817    }
1818
1819    switch (pSmi->Chipset) {
1820    default:
1821	pSmi->DPRBase = pSmi->MapBase + 0x8000;
1822	pSmi->VPRBase = pSmi->MapBase + 0xC000;
1823	pSmi->CPRBase = pSmi->MapBase + 0xE000;
1824	pSmi->IOBase  = NULL;
1825	pSmi->DataPortBase = pSmi->MapBase;
1826	pSmi->DataPortSize = 0x8000;
1827	break;
1828    case SMI_COUGAR3DR:
1829	pSmi->DPRBase = pSmi->MapBase + 0x000000;
1830	pSmi->VPRBase = pSmi->MapBase + 0x000800;
1831	pSmi->CPRBase = pSmi->MapBase + 0x001000;
1832	pSmi->FPRBase = pSmi->MapBase + 0x005800;
1833	pSmi->IOBase  = pSmi->MapBase + 0x0C0000;
1834	pSmi->DataPortBase = pSmi->MapBase + 0x100000;
1835	pSmi->DataPortSize = 0x100000;
1836	break;
1837    case SMI_LYNX3D:
1838	pSmi->DPRBase = pSmi->MapBase + 0x000000;
1839	pSmi->VPRBase = pSmi->MapBase + 0x000800;
1840	pSmi->CPRBase = pSmi->MapBase + 0x001000;
1841	pSmi->IOBase  = pSmi->MapBase + 0x040000;
1842	pSmi->DataPortBase = pSmi->MapBase + 0x080000;
1843	pSmi->DataPortSize = 0x100000;
1844	break;
1845    case SMI_LYNXEM:
1846    case SMI_LYNXEMplus:
1847	pSmi->DPRBase = pSmi->MapBase + 0x008000;
1848	pSmi->VPRBase = pSmi->MapBase + 0x00C000;
1849	pSmi->CPRBase = pSmi->MapBase + 0x00E000;
1850	pSmi->IOBase  = pSmi->MapBase + 0x300000;
1851	pSmi->DataPortBase = pSmi->MapBase /*+ 0x100000*/;
1852	pSmi->DataPortSize = 0x8000 /*0x200000*/;
1853	break;
1854    case SMI_LYNX3DM:
1855	pSmi->DPRBase = pSmi->MapBase + 0x000000;
1856	pSmi->VPRBase = pSmi->MapBase + 0x000800;
1857	pSmi->CPRBase = pSmi->MapBase + 0x001000;
1858	pSmi->IOBase  = pSmi->MapBase + 0x0C0000;
1859	pSmi->DataPortBase = pSmi->MapBase + 0x100000;
1860	pSmi->DataPortSize = 0x100000;
1861	break;
1862    }
1863    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1864		   "Physical MMIO at 0x%08lX\n", (unsigned long)memBase);
1865    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1866		   "Logical MMIO at %p - %p\n", pSmi->MapBase,
1867		   pSmi->MapBase + pSmi->MapSize - 1);
1868    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1869		   "DPR=%p, VPR=%p, IOBase=%p\n",
1870		   pSmi->DPRBase, pSmi->VPRBase, pSmi->IOBase);
1871    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1872		   "DataPort=%p - %p\n", pSmi->DataPortBase,
1873		   pSmi->DataPortBase + pSmi->DataPortSize - 1);
1874
1875    pScrn->memPhysBase = pSmi->PciInfo->memBase[0];
1876
1877    SMI_EnableMmio(pScrn);
1878
1879    if (pSmi->videoRAMBytes) {
1880	/* Map the frame buffer */
1881	if (pSmi->Chipset == SMI_LYNX3DM)
1882	    pSmi->fbMapOffset = 0x200000;
1883	else
1884	    pSmi->fbMapOffset = 0x0;
1885
1886	pSmi->FBOffset = 0;
1887
1888	pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
1889
1890	pSmi->FBBase = xf86MapPciMem(pScrn->scrnIndex,
1891				     VIDMEM_FRAMEBUFFER,
1892				     pSmi->PciTag,
1893				     pScrn->memPhysBase + pSmi->fbMapOffset,
1894				     pSmi->videoRAMBytes);
1895
1896	if (pSmi->FBBase == NULL) {
1897	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not "
1898		       "map framebuffer.\n");
1899	    LEAVE_PROC("SMI_MapMem");
1900	    return FALSE;
1901	}
1902
1903	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1904		       "Physical frame buffer at 0x%08lX offset: 0x%08lX\n",
1905		       pScrn->memPhysBase, pScrn->fbOffset);
1906	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1907		       "Logical frame buffer at %p - %p\n", pSmi->FBBase,
1908		       pSmi->FBBase + pSmi->videoRAMBytes - 1);
1909
1910	/* Set up offset to hwcursor memory area.  It's a 1K chunk at the end of
1911	 * the frame buffer.
1912	 */
1913	pSmi->FBCursorOffset = pSmi->videoRAMBytes - 1024;
1914
1915	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1916		   "Cursor Offset: %08lX\n",
1917		   (unsigned long)pSmi->FBCursorOffset);
1918
1919	/* set up the fifo reserved space */
1920	if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01)/* #1074 */ {
1921	    CARD32 fifoOffset = 0;
1922	    fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x46) << 3;
1923	    fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x47) << 11;
1924	    fifoOffset |= (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49)
1925			& 0x1C) << 17;
1926	    pSmi->FBReserved = fifoOffset;	/* PDR#1074 */
1927	} else {
1928	    pSmi->FBReserved = pSmi->videoRAMBytes - 2048;
1929	}
1930
1931	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reserved: %08lX\n",
1932		   (unsigned long)pSmi->FBReserved);
1933
1934    }
1935
1936    /* Assign hwp->MemBase & IOBase here */
1937    hwp = VGAHWPTR(pScrn);
1938    if (pSmi->IOBase != NULL) {
1939	vgaHWSetMmioFuncs(hwp, pSmi->MapBase, pSmi->IOBase - pSmi->MapBase);
1940    }
1941    vgaHWGetIOBase(hwp);
1942
1943    /* Map the VGA memory when the primary video */
1944    if (xf86IsPrimaryPci(pSmi->PciInfo)) {
1945	hwp->MapSize = 0x10000;
1946	if (!vgaHWMapMem(pScrn)) {
1947	    LEAVE_PROC("SMI_MapMem");
1948	    return FALSE;
1949	}
1950	pSmi->PrimaryVidMapped = TRUE;
1951    }
1952
1953    LEAVE_PROC("SMI_MapMem");
1954    return TRUE;
1955}
1956
1957/* UnMapMem - contains half of pre-4.0 EnterLeave function.  The EnterLeave
1958 * function which en/disable access to IO ports and ext. regs
1959 */
1960
1961static void
1962SMI_UnmapMem(ScrnInfoPtr pScrn)
1963{
1964    SMIPtr pSmi = SMIPTR(pScrn);
1965
1966    ENTER_PROC("SMI_UnmapMem");
1967
1968    /* Unmap VGA mem if mapped. */
1969    if (pSmi->PrimaryVidMapped) {
1970	vgaHWUnmapMem(pScrn);
1971	pSmi->PrimaryVidMapped = FALSE;
1972    }
1973
1974    SMI_DisableMmio(pScrn);
1975
1976    xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->MapBase, pSmi->MapSize);
1977    if (pSmi->FBBase != NULL) {
1978	xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->FBBase,
1979			pSmi->videoRAMBytes);
1980    }
1981
1982    LEAVE_PROC("SMI_UnmapMem");
1983}
1984
1985/* This gets called at the start of each server generation. */
1986
1987static Bool
1988SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
1989{
1990    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1991    SMIPtr pSmi = SMIPTR(pScrn);
1992    EntityInfoPtr pEnt;
1993
1994    ENTER_PROC("SMI_ScreenInit");
1995
1996    /* Map MMIO regs and framebuffer */
1997    if (!SMI_MapMem(pScrn)) {
1998	LEAVE_PROC("SMI_ScreenInit");
1999	return FALSE;
2000    }
2001
2002    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
2003
2004    if (!pSmi->pInt10) {
2005	pSmi->pInt10 = xf86InitInt10(pEnt->index);
2006    }
2007
2008    /* Save the chip/graphics state */
2009    SMI_Save(pScrn);
2010
2011    /* Zero the frame buffer, #258 */
2012    memset(pSmi->FBBase, 0, pSmi->videoRAMBytes);
2013
2014    /* Initialize the first mode */
2015    if (!SMI_ModeInit(pScrn, pScrn->currentMode)) {
2016	LEAVE_PROC("SMI_ScreenInit");
2017	return FALSE;
2018    }
2019
2020    /*
2021     * The next step is to setup the screen's visuals, and initialise the
2022     * framebuffer code.  In cases where the framebuffer's default choises for
2023     * things like visual layouts and bits per RGB are OK, this may be as simple
2024     * as calling the framebuffer's ScreenInit() function.  If not, the visuals
2025     * will need to be setup before calling a fb ScreenInit() function and fixed
2026     * up after.
2027     */
2028
2029    /*
2030     * Reset the visual list.
2031     */
2032    miClearVisualTypes();
2033
2034    /* Setup the visuals we support. */
2035
2036    if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
2037			  pScrn->rgbBits, pScrn->defaultVisual)) {
2038	LEAVE_PROC("SMI_ScreenInit");
2039	return FALSE;
2040    }
2041    if (!miSetPixmapDepths ()) return FALSE;
2042
2043    if (!SMI_InternalScreenInit(scrnIndex, pScreen)) {
2044	LEAVE_PROC("SMI_ScreenInit");
2045	return FALSE;
2046    }
2047
2048    xf86SetBlackWhitePixels(pScreen);
2049
2050    if (pScrn->bitsPerPixel > 8) {
2051	VisualPtr visual;
2052	/* Fixup RGB ordering */
2053	visual = pScreen->visuals + pScreen->numVisuals;
2054	while (--visual >= pScreen->visuals) {
2055	    if ((visual->class | DynamicClass) == DirectColor) {
2056		visual->offsetRed   = pScrn->offset.red;
2057		visual->offsetGreen = pScrn->offset.green;
2058		visual->offsetBlue  = pScrn->offset.blue;
2059		visual->redMask     = pScrn->mask.red;
2060		visual->greenMask   = pScrn->mask.green;
2061		visual->blueMask    = pScrn->mask.blue;
2062	    }
2063	}
2064    }
2065
2066    /* must be after RGB ordering fixed */
2067    fbPictureInit(pScreen, 0, 0);
2068
2069    /* CZ 18.06.2001: moved here from smi_accel.c to have offscreen
2070       framebuffer in NoAccel mode */
2071    if (!pSmi->useEXA) {
2072	int numLines, maxLines;
2073	BoxRec AvailFBArea;
2074
2075	maxLines = pSmi->FBReserved / (pSmi->width * pSmi->Bpp);
2076	if (pSmi->rotate) {
2077	    numLines = maxLines;
2078	} else {
2079	    /* CZ 3.11.2001: What does the following code? see also smi_video.c aaa line 1226 */
2080/*#if SMI_USE_VIDEO */
2081#if 0
2082	    numLines = ((pSmi->FBReserved - pSmi->width * pSmi->Bpp
2083			* pSmi->height) * 25 / 100 + pSmi->width
2084			* pSmi->Bpp - 1) / (pSmi->width * pSmi->Bpp);
2085	    numLines += pSmi->height;
2086#else
2087	    numLines = maxLines;
2088#endif
2089	}
2090
2091	AvailFBArea.x1 = 0;
2092	AvailFBArea.y1 = 0;
2093	AvailFBArea.x2 = pSmi->width;
2094	AvailFBArea.y2 = numLines;
2095	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2096		   "FrameBuffer Box: %d,%d - %d,%d\n",
2097		   AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2,
2098		   AvailFBArea.y2);
2099	xf86InitFBManager(pScreen, &AvailFBArea);
2100    }
2101    /* end CZ */
2102
2103
2104    /* Initialize acceleration layer */
2105    if (!pSmi->NoAccel) {
2106	if (!pSmi->useEXA) {
2107	    if (!SMI_XAAInit(pScreen)) {
2108		LEAVE_PROC("SMI_ScreenInit");
2109		return FALSE;
2110	    }
2111	} else {
2112	    if (!SMI_EXAInit(pScreen)) {
2113		LEAVE_PROC("SMI_ScreenInit");
2114		return FALSE;
2115	    }
2116	}
2117    }
2118
2119    miInitializeBackingStore(pScreen);
2120
2121    /* hardware cursor needs to wrap this layer */
2122    if(!pSmi->NoAccel && !pSmi->useEXA)
2123	SMI_DGAInit(pScreen);
2124
2125    /* Initialise cursor functions */
2126    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
2127
2128    /* Initialize HW cursor layer.  Must follow software cursor
2129     * initialization.
2130     */
2131    if (pSmi->hwcursor) {
2132	if (!SMI_HWCursorInit(pScreen)) {
2133	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Hardware cursor "
2134		       "initialization failed\n");
2135	}
2136    }
2137
2138    if (pSmi->shadowFB) {
2139	RefreshAreaFuncPtr refreshArea;
2140
2141	if (pSmi->Chipset == SMI_COUGAR3DR) {
2142	    refreshArea = SMI_RefreshArea730;
2143	} else {
2144	    refreshArea = SMI_RefreshArea;
2145	}
2146
2147	if (pSmi->rotate) {
2148	    if (pSmi->PointerMoved == NULL) {
2149		pSmi->PointerMoved  = pScrn->PointerMoved;
2150		pScrn->PointerMoved = SMI_PointerMoved;
2151	    }
2152	}
2153
2154	ShadowFBInit(pScreen, refreshArea);
2155    }
2156
2157    /* Initialise default colormap */
2158    if (!miCreateDefColormap(pScreen)) {
2159	LEAVE_PROC("SMI_ScreenInit");
2160	return FALSE;
2161    }
2162
2163    /* Initialize colormap layer.  Must follow initialization of the default
2164     * colormap.  And SetGamma call, else it will load palette with solid white.
2165     */
2166    /* CZ 2.11.2001: CMAP_PALETTED_TRUECOLOR for gamma correction */
2167    if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SMI_LoadPalette, NULL,
2168            CMAP_RELOAD_ON_MODE_SWITCH | CMAP_PALETTED_TRUECOLOR)) {
2169	LEAVE_PROC("SMI_ScreenInit");
2170	return FALSE;
2171    }
2172
2173    pScreen->SaveScreen = SMI_SaveScreen;
2174    pSmi->CloseScreen = pScreen->CloseScreen;
2175    pScreen->CloseScreen = SMI_CloseScreen;
2176
2177    if (!xf86DPMSInit(pScreen, SMI_DisplayPowerManagementSet, 0)) {
2178	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n");
2179    }
2180
2181    if (!pSmi->Dualhead)
2182  	SMI_InitVideo(pScreen);
2183    else
2184	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No overlay in dualhead mode\n");
2185
2186    /* Report any unused options (only for the first generation) */
2187    if (serverGeneration == 1) {
2188	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
2189    }
2190
2191    LEAVE_PROC("SMI_ScreenInit");
2192    return TRUE;
2193}
2194
2195/* Common init routines needed in EnterVT and ScreenInit */
2196
2197static int
2198SMI_InternalScreenInit(int scrnIndex, ScreenPtr pScreen)
2199{
2200    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2201    SMIPtr pSmi = SMIPTR(pScrn);
2202    int width, height, displayWidth;
2203    int bytesPerPixel = pScrn->bitsPerPixel / 8;
2204    int xDpi, yDpi;
2205    int ret;
2206
2207    ENTER_PROC("SMI_InternalScreenInit");
2208
2209    if (pSmi->rotate) {
2210	width        = pScrn->virtualY;
2211	height       = pScrn->virtualX;
2212	xDpi         = pScrn->yDpi;
2213	yDpi         = pScrn->xDpi;
2214	displayWidth = ((width * bytesPerPixel + 15) & ~15) / bytesPerPixel;
2215    } else {
2216	width        = pScrn->virtualX;
2217	height       = pScrn->virtualY;
2218	xDpi		 = pScrn->xDpi;
2219	yDpi		 = pScrn->yDpi;
2220	displayWidth = pScrn->displayWidth;
2221    }
2222
2223    if (pSmi->shadowFB) {
2224	pSmi->ShadowWidth      = width;
2225	pSmi->ShadowHeight     = height;
2226	pSmi->ShadowWidthBytes = (width * bytesPerPixel + 15) & ~15;
2227	if (bytesPerPixel == 3) {
2228	    pSmi->ShadowPitch = ((height * 3) << 16)
2229			      | pSmi->ShadowWidthBytes;
2230	} else {
2231	    pSmi->ShadowPitch = (height << 16)
2232			      | (pSmi->ShadowWidthBytes / bytesPerPixel);
2233	}
2234
2235	pSmi->saveBufferSize = pSmi->ShadowWidthBytes * pSmi->ShadowHeight;
2236	pSmi->FBReserved -= pSmi->saveBufferSize;
2237	pSmi->FBReserved &= ~0x15;
2238	WRITE_VPR(pSmi, 0x0C, (pSmi->FBOffset = pSmi->FBReserved) >> 3);
2239	if (pSmi->Chipset == SMI_COUGAR3DR) {
2240	    WRITE_FPR(pSmi, FPR0C, (pSmi->FBOffset = pSmi->FBReserved) >> 3);
2241	}
2242	pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
2243	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2244		   "Shadow: width=%d height=%d "
2245		   "offset=0x%08lX pitch=0x%08X\n",
2246		   pSmi->ShadowWidth, pSmi->ShadowHeight,
2247		   (unsigned long)pSmi->FBOffset,
2248		   pSmi->ShadowPitch);
2249    } else {
2250	pSmi->FBOffset = 0;
2251	pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
2252    }
2253
2254    /*
2255     * Call the framebuffer layer's ScreenInit function, and fill in other
2256     * pScreen fields.
2257     */
2258
2259    DEBUG((VERBLEV, "\tInitializing FB @ 0x%08X for %dx%d (%d)\n",
2260	   pSmi->FBBase, width, height, displayWidth));
2261    switch (pScrn->bitsPerPixel) {
2262    case 8:
2263    case 16:
2264    case 24:
2265    case 32:
2266	ret = fbScreenInit(pScreen, pSmi->FBBase, width, height, xDpi,
2267			   yDpi, displayWidth, pScrn->bitsPerPixel);
2268	break;
2269    default:
2270	xf86DrvMsg(scrnIndex, X_ERROR, "Internal error: invalid bpp (%d) "
2271		   "in SMI_InternalScreenInit\n", pScrn->bitsPerPixel);
2272	LEAVE_PROC("SMI_InternalScreenInit");
2273	return FALSE;
2274    }
2275
2276    LEAVE_PROC("SMI_InternalScreenInit");
2277    return ret;
2278}
2279
2280/* Checks if a mode is suitable for the selected configuration. */
2281static ModeStatus
2282SMI_ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
2283{
2284    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2285    SMIPtr pSmi = SMIPTR(pScrn);
2286    float refresh;
2287
2288    ENTER_PROC("SMI_ValidMode");
2289    refresh = (mode->VRefresh > 0) ? mode->VRefresh
2290	    : mode->Clock * 1000.0 / mode->VTotal / mode->HTotal;
2291    xf86DrvMsg(scrnIndex, X_INFO, "Mode: %dx%d %d-bpp, %fHz\n", mode->HDisplay,
2292	       mode->VDisplay, pScrn->bitsPerPixel, refresh);
2293
2294    if (pSmi->shadowFB) {
2295	int mem;
2296
2297	if (pScrn->bitsPerPixel == 24) {
2298	    LEAVE_PROC("SMI_ValidMode");
2299	    return MODE_BAD;
2300	}
2301
2302	mem  = (pScrn->virtualX * pScrn->bitsPerPixel / 8 + 15) & ~15;
2303	mem *= pScrn->virtualY * 2;
2304
2305	if (mem > pSmi->FBReserved) /* PDR#1074 */ {
2306	    LEAVE_PROC("SMI_ValidMode");
2307	    return MODE_MEM;
2308	}
2309    }
2310
2311    if (!pSmi->useBIOS || pSmi->lcd) {
2312#if 1 /* PDR#983 */
2313	if (pSmi->zoomOnLCD) {
2314	    if ((mode->HDisplay > pSmi->lcdWidth) ||
2315		(mode->VDisplay > pSmi->lcdHeight)) {
2316		LEAVE_PROC("SMI_ValidMode");
2317		return MODE_PANEL;
2318	    }
2319	} else
2320#endif
2321	{
2322	    if ((mode->HDisplay != pSmi->lcdWidth) ||
2323		(mode->VDisplay != pSmi->lcdHeight)) {
2324		LEAVE_PROC("SMI_ValidMode");
2325		return MODE_PANEL;
2326	    }
2327	}
2328    }
2329
2330#if 1 /* PDR#944 */
2331    if (pSmi->rotate) {
2332	if ((mode->HDisplay != pSmi->lcdWidth) ||
2333	    (mode->VDisplay != pSmi->lcdHeight)) {
2334	    LEAVE_PROC("SMI_ValidMode");
2335	    return MODE_PANEL;
2336	}
2337    }
2338#endif
2339
2340    LEAVE_PROC("SMI_ValidMode");
2341    return MODE_OK;
2342}
2343
2344static void
2345SMI_DPRInit(ScrnInfoPtr pScrn)
2346{
2347    SMIPtr pSmi = SMIPTR(pScrn);
2348    int i;
2349    int xyAddress[] = { 320, 400, 512, 640, 800, 1024, 1280, 1600, 2048 };
2350    CARD32 DEDataFormat = 0;
2351
2352    /* Store values to current mode register structs */
2353    SMIRegPtr new = &pSmi->ModeReg;
2354
2355    /* Set DPR registers */
2356    pSmi->Stride = (pSmi->width * pSmi->Bpp + 15) & ~15;
2357    switch (pScrn->bitsPerPixel) {
2358    case 8:
2359	DEDataFormat = 0x00000000;
2360	break;
2361    case 16:
2362	pSmi->Stride >>= 1;
2363	DEDataFormat = 0x00100000;
2364	break;
2365    case 24:
2366	DEDataFormat = 0x00300000;
2367	break;
2368    case 32:
2369	pSmi->Stride >>= 2;
2370	DEDataFormat = 0x00200000;
2371	break;
2372    }
2373
2374    for (i = 0; i < sizeof(xyAddress) / sizeof(xyAddress[0]); i++) {
2375	if (pSmi->rotate) {
2376	    if (xyAddress[i] == pSmi->height) {
2377		DEDataFormat |= i << 16;
2378		break;
2379	    }
2380	} else {
2381	    if (xyAddress[i] == pSmi->width) {
2382		DEDataFormat |= i << 16;
2383		break;
2384	    }
2385	}
2386    }
2387
2388    new->DPR10 = (pSmi->Stride << 16) | pSmi->Stride;
2389    new->DPR1C = DEDataFormat;
2390    new->DPR20 = 0;
2391    new->DPR24 = 0xFFFFFFFF;
2392    new->DPR28 = 0xFFFFFFFF;
2393    new->DPR2C = 0;
2394    new->DPR30 = 0;
2395    new->DPR3C = (pSmi->Stride << 16) | pSmi->Stride;
2396    new->DPR40 = pSmi->FBOffset >> 3;
2397    new->DPR44 = pSmi->FBOffset >> 3;
2398
2399}
2400
2401static Bool
2402SMI_ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
2403{
2404    vgaHWPtr hwp = VGAHWPTR(pScrn);
2405    SMIPtr pSmi = SMIPTR(pScrn);
2406    unsigned char tmp;
2407    int panelIndex, modeIndex, i, vclk;
2408
2409    /* Store values to current mode register structs */
2410    SMIRegPtr new = &pSmi->ModeReg;
2411    vgaRegPtr vganew = &hwp->ModeReg;
2412
2413    ENTER_PROC("SMI_ModeInit");
2414
2415    if (!vgaHWInit(pScrn, mode)) {
2416	LEAVE_PROC("SMI_ModeInit");
2417	return FALSE;
2418    }
2419
2420    new->modeInit = TRUE;
2421
2422    if (pSmi->rotate) {
2423	pSmi->width  = pScrn->virtualY;
2424	pSmi->height = pScrn->virtualX;
2425    } else {
2426	pSmi->width  = pScrn->virtualX;
2427	pSmi->height = pScrn->virtualY;
2428    }
2429    pSmi->Bpp    = pScrn->bitsPerPixel / 8;
2430
2431    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x17);
2432    tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
2433    if (pSmi->pci_burst) {
2434	new->SR17 = tmp | 0x20;
2435    } else {
2436	new->SR17 = tmp & ~0x20;
2437    }
2438
2439    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
2440    new->SR18 = inb(pSmi->PIOBase + VGA_SEQ_DATA) | 0x11;
2441
2442    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
2443    new->SR21 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0x03;
2444
2445    if (pSmi->Chipset != SMI_COUGAR3DR) {
2446	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x31);
2447	new->SR31 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0xC0;
2448
2449	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x32);
2450	new->SR32 = inb(pSmi->PIOBase + VGA_SEQ_DATA) & ~0x07;
2451
2452	if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
2453	    new->SR32 |= 0x04;
2454	}
2455    }
2456
2457    new->SRA0 = new->CR33 = new->CR3A = 0x00;
2458
2459    if (pSmi->lcdWidth == 640) {
2460	panelIndex = 0;
2461    } else if (pSmi->lcdWidth == 800) {
2462	panelIndex = 1;
2463    } else {
2464	panelIndex = 2;
2465    }
2466
2467    if (mode->HDisplay == 640) {
2468	modeIndex = 0;
2469    } else if (mode->HDisplay == 800) {
2470	modeIndex = 1;
2471    } else {
2472	modeIndex = 2;
2473    }
2474
2475    if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
2476	static unsigned char PanelTable[3][14] =
2477	    {
2478		{ 0x5F, 0x4F, 0x00, 0x52, 0x1E, 0x0B, 0xDF, 0x00, 0xE9, 0x0B, 0x2E,
2479		  0x00, 0x4F, 0xDF },
2480		{ 0x7F, 0x63, 0x00, 0x69, 0x19, 0x72, 0x57, 0x00, 0x58, 0x0C, 0xA2,
2481		  0x20, 0x4F, 0xDF },
2482		{ 0xA3, 0x7F, 0x00, 0x83, 0x14, 0x24, 0xFF, 0x00, 0x02, 0x08, 0xA7,
2483		  0xE0, 0x4F, 0xDF },
2484	    };
2485
2486	for (i = 0; i < 14; i++) {
2487	    new->CR40[i] = PanelTable[panelIndex][i];
2488	}
2489	new->CR90[14] = 0x03;
2490	new->CR90[15] = 0x00;
2491	if (mode->VDisplay < pSmi->lcdHeight) {
2492	    new->CRA0[6] = (pSmi->lcdHeight - mode->VDisplay) / 8;
2493	} else {
2494	    new->CRA0[6] = 0;
2495	}
2496
2497	if (mode->HDisplay < pSmi->lcdWidth) {
2498	    new->CRA0[7] = (pSmi->lcdWidth - mode->HDisplay) / 16;
2499	} else {
2500	    new->CRA0[7] = 0;
2501	}
2502    } else {
2503	static unsigned char PanelTable[3][3][14] =
2504	    {
2505		{ /* 640x480 panel */
2506		    { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C,
2507		      0x2E, 0x00, 0x4F, 0xDF },
2508		    { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C,
2509		      0x2E, 0x00, 0x4F, 0xDF },
2510		    { 0x5F, 0x4F, 0x00, 0x53, 0x00, 0x0B, 0xDF, 0x00, 0xEA, 0x0C,
2511		      0x2E, 0x00, 0x4F, 0xDF },
2512		},
2513		{ /* 800x600 panel */
2514		    { 0x7F, 0x59, 0x19, 0x5E, 0x8E, 0x72, 0x1C, 0x37, 0x1D, 0x00,
2515		      0xA2, 0x20, 0x4F, 0xDF },
2516		    { 0x7F, 0x63, 0x00, 0x68, 0x18, 0x72, 0x58, 0x00, 0x59, 0x0C,
2517		      0xE0, 0x20, 0x63, 0x57 },
2518		    { 0x7F, 0x63, 0x00, 0x68, 0x18, 0x72, 0x58, 0x00, 0x59, 0x0C,
2519		      0xE0, 0x20, 0x63, 0x57 },
2520		},
2521		{ /* 1024x768 panel */
2522		    { 0xA3, 0x67, 0x0F, 0x6D, 0x1D, 0x24, 0x70, 0x95, 0x72, 0x07,
2523		      0xA3, 0x20, 0x4F, 0xDF },
2524		    { 0xA3, 0x71, 0x19, 0x77, 0x07, 0x24, 0xAC, 0xD1, 0xAE, 0x03,
2525		      0xE1, 0x20, 0x63, 0x57 },
2526		    { 0xA3, 0x7F, 0x00, 0x85, 0x15, 0x24, 0xFF, 0x00, 0x01, 0x07,
2527		      0xE5, 0x20, 0x7F, 0xFF },
2528		},
2529	    };
2530
2531	for (i = 0; i < 14; i++) {
2532	    new->CR40[i] = PanelTable[panelIndex][modeIndex][i];
2533	}
2534    }
2535
2536    /* CZ 2.11.2001: for gamma correction (TODO: other chipsets?) */
2537    new->CCR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
2538    if ((pSmi->Chipset == SMI_LYNX3DM) || (pSmi->Chipset == SMI_COUGAR3DR)) {
2539	switch (pScrn->bitsPerPixel) {
2540	case 8:
2541	    new->CCR66 = (new->CCR66 & 0xF3) | 0x00; /* 6 bits-RAM */
2542	    break;
2543	case 16:
2544	    new->CCR66 = (new->CCR66 & 0xF3) | 0x00; /* 6 bits-RAM */
2545	    /* no Gamma correction in 16 Bit mode (s. Release.txt 1.3.1) */
2546	    break;
2547	case 24:
2548	case 32:
2549	    new->CCR66 = (new->CCR66 & 0xF3) | 0x04; /* Gamma correct ON */
2550	    break;
2551	default:
2552	    LEAVE_PROC("SMI_ModeInit");
2553	    return FALSE;
2554	}
2555    }
2556
2557    if (pSmi->Chipset != SMI_COUGAR3DR) {
2558	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x30);
2559	if (inb(pSmi->PIOBase + VGA_SEQ_DATA) & 0x01) {
2560	    new->SR21 = 0x00;
2561	}
2562    }
2563
2564    if (pSmi->MCLK > 0) {
2565	SMI_CommonCalcClock(pScrn->scrnIndex, pSmi->MCLK,
2566			    1, 1, 63, 0, 2,
2567                            pScrn->clockRanges->minClock,
2568                            pScrn->clockRanges->maxClock,
2569                            &new->SR6A, &new->SR6B);
2570    } else {
2571	new->SR6B = 0xFF;
2572    }
2573
2574    if ((mode->HDisplay == 640) && SMI_LYNXM_SERIES(pSmi->Chipset)) {
2575	vganew->MiscOutReg &= ~0x0C;
2576    } else {
2577	vganew->MiscOutReg |= 0x0C;
2578    }
2579    vganew->MiscOutReg |= 0xE0;
2580    if (mode->HDisplay == 800) {
2581	vganew->MiscOutReg &= ~0xC0;
2582    }
2583    if ((mode->HDisplay == 1024) && SMI_LYNXM_SERIES(pSmi->Chipset)) {
2584	vganew->MiscOutReg &= ~0xC0;
2585    }
2586
2587    /* calculate vclk1 */
2588    vclk = mode->Clock;
2589    if (SMI_LYNX_SERIES(pSmi->Chipset)) {
2590        SMI_CommonCalcClock(pScrn->scrnIndex, vclk,
2591			1, 1, 63, 0, 2,
2592                        pScrn->clockRanges->minClock,
2593                        pScrn->clockRanges->maxClock,
2594                        &new->SR6C, &new->SR6D);
2595    } else {
2596        SMI_CommonCalcClock(pScrn->scrnIndex, vclk,
2597			1, 1, 63, 0, 1,
2598                        pScrn->clockRanges->minClock,
2599                        pScrn->clockRanges->maxClock,
2600                        &new->SR6C, &new->SR6D);
2601    }
2602
2603    /* use vclk1 */
2604    new->SR68 = 0x54;
2605
2606    /* dualhead */
2607    if (pSmi->Dualhead) {
2608	/* PLL controls */
2609	/* set LCD to vclk2 */
2610	new->SR69 = 0x04;
2611
2612	if (pSmi->lcdWidth == 640) {
2613	    /* vclk */
2614	    new->SR6C = 0x07;
2615	    new->SR6D = 0x04;
2616
2617	    /* vclk2 */
2618	    new->SR6E = 0x07;
2619	    new->SR6F = 0x04;
2620	} else if (pSmi->lcdWidth == 800) {
2621	    /* vclk */
2622	    new->SR6C = 0x0B;
2623	    new->SR6D = 0x82;
2624
2625	    /* vclk2 */
2626	    new->SR6E = 0x0B;
2627	    new->SR6F = 0x82;
2628	} else {
2629	    /* vclk */
2630	    new->SR6C = 0x52;
2631	    new->SR6D = 0x89;
2632
2633	    /* vclk2 */
2634	    new->SR6E = 0x52;
2635	    new->SR6F = 0x89;
2636	}
2637
2638	/* TFT panel uses FIFO1, DSTN panel uses FIFO1 for upper panel and
2639	 * FIFO2 for lower panel.  I don't have a DSTN panel, so it's untested.
2640	 * -- AGD
2641	 */
2642	CARD32 fifo1_readoffset, fifo2_readoffset, fifo_writeoffset;
2643
2644	/* setting SR21 bit 2 disables ZV circuitry,
2645	 * if ZV is needed, SR21 = 0x20
2646	 */
2647	/* enable DAC, PLL, etc. */
2648	new->SR21 = 0x24;
2649
2650	/* clear DPMS state */
2651	new->SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22) & ~0x30;
2652
2653	/* enable virtual refresh and LCD and CRT outputs */
2654	if (pScrn->bitsPerPixel > 8)
2655	    new->SR31 = /*0xCB*/ 0xC3; /* 16 bpp */
2656	else
2657	    new->SR31 = /*0x8B*/ 0x83; /* 8 bpp */
2658
2659	/* FIFO1 Read Offset */
2660	fifo1_readoffset = pSmi->lcdWidth / 2;
2661	fifo2_readoffset = pSmi->lcdWidth / 2;
2662	new->SR44 = fifo1_readoffset & 0x000000FF;
2663	/* FIFO2 Read Offset */
2664	new->SR4B = fifo2_readoffset & 0x000000FF;
2665	/* FIFO1/2 Read Offset overflow */
2666	new->SR4C = (((fifo1_readoffset & 0x00000300) >> 8) << 2) |
2667		    (((fifo2_readoffset & 0x00000300) >> 8) << 6);
2668
2669	/* FIFO Write Offset */
2670	fifo_writeoffset = pSmi->lcdWidth / 4;
2671	new->SR48 = fifo_writeoffset & 0x000000FF;
2672	new->SR49 = (fifo_writeoffset & 0x00000300) >> 8;
2673
2674	/* set FIFO levels */
2675	new->SR4A = 0x41;
2676
2677	/* something related to tv... */
2678	new->CR33 |= 0x07;
2679
2680    }
2681
2682    /* init graphics engine regs */
2683    SMI_DPRInit(pScrn);
2684
2685    /* Set VPR registers (and FPR registers for SM731) */
2686    switch (pScrn->bitsPerPixel) {
2687    case 8:
2688	new->VPR00 = 0x00000000;
2689	new->FPR00_= 0x00080000;
2690	break;
2691    case 16:
2692	new->VPR00 = 0x00020000;
2693	new->FPR00_= 0x000A0000;
2694	break;
2695    case 24:
2696	new->VPR00 = 0x00040000;
2697	new->FPR00_= 0x000C0000;
2698	break;
2699    case 32:
2700	new->VPR00 = 0x00030000;
2701	new->FPR00_= 0x000B0000;
2702	break;
2703    }
2704    new->VPR0C = pSmi->FBOffset >> 3;
2705    if (pSmi->rotate) {
2706	new->VPR10 = (((( pSmi->height * pSmi->Bpp) >> 3) + 2) << 16) |
2707		     ((pSmi->height * pSmi->Bpp) >> 3);
2708    } else {
2709	new->VPR10 = ((((pSmi->width * pSmi->Bpp) >> 3) + 2) << 16) |
2710		     ((pSmi->width * pSmi->Bpp) >> 3);
2711    }
2712
2713    new->FPR0C_ = new->VPR0C;
2714    new->FPR10_ = new->VPR10;
2715
2716    /* Set CPR registers */
2717    new->CPR00 = 0x00000000;
2718
2719    pScrn->vtSema = TRUE;
2720
2721    /* Find the INT 10 mode number */
2722    {
2723	static struct {
2724	    int x, y, bpp;
2725	    CARD16 mode;
2726	} modeTable[] =
2727	    {
2728		{  640,  480,  8, 0x50 },
2729		{  640,  480, 16, 0x52 },
2730		{  640,  480, 24, 0x53 },
2731		{  640,  480, 32, 0x54 },
2732		{  800,  480,  8, 0x4A },
2733		{  800,  480, 16, 0x4C },
2734		{  800,  480, 24, 0x4D },
2735		{  800,  600,  8, 0x55 },
2736		{  800,  600, 16, 0x57 },
2737		{  800,  600, 24, 0x58 },
2738		{  800,  600, 32, 0x59 },
2739		{ 1024,  768,  8, 0x60 },
2740		{ 1024,  768, 16, 0x62 },
2741		{ 1024,  768, 24, 0x63 },
2742		{ 1024,  768, 32, 0x64 },
2743		{ 1280, 1024,  8, 0x65 },
2744		{ 1280, 1024, 16, 0x67 },
2745		{ 1280, 1024, 24, 0x68 },
2746		{ 1280, 1024, 32, 0x69 },
2747	    };
2748
2749	new->mode = 0;
2750	for (i = 0; i < sizeof(modeTable) / sizeof(modeTable[0]); i++) {
2751	    if ((modeTable[i].x == mode->HDisplay) &&
2752		(modeTable[i].y == mode->VDisplay) &&
2753		(modeTable[i].bpp == pScrn->bitsPerPixel)) {
2754		new->mode = modeTable[i].mode;
2755		break;
2756	    }
2757	}
2758    }
2759
2760    /* Zero the font memory */
2761    memset(new->smiFont, 0, sizeof(new->smiFont));
2762
2763    /* Write the mode registers to hardware */
2764    SMI_WriteMode(pScrn, vganew, new);
2765
2766    /* Adjust the viewport */
2767    SMI_AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
2768
2769    LEAVE_PROC("SMI_ModeInit");
2770    return TRUE;
2771}
2772
2773/*
2774 * This is called at the end of each server generation.  It restores the
2775 * original (text) mode.  It should also unmap the video memory, and free any
2776 * per-generation data allocated by the driver.  It should finish by unwrapping
2777 * and calling the saved CloseScreen function.
2778 */
2779
2780static Bool
2781SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen)
2782{
2783    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2784    vgaHWPtr hwp = VGAHWPTR(pScrn);
2785    SMIPtr pSmi = SMIPTR(pScrn);
2786    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
2787    SMIRegPtr SMISavePtr = &pSmi->SavedReg;
2788    Bool ret;
2789
2790    ENTER_PROC("SMI_CloseScreen");
2791
2792    if (pScrn->vtSema) {
2793	SMI_WriteMode(pScrn, vgaSavePtr, SMISavePtr);
2794	vgaHWLock(hwp);
2795	SMI_UnmapMem(pScrn);
2796    }
2797
2798    if (pSmi->XAAInfoRec != NULL) {
2799	XAADestroyInfoRec(pSmi->XAAInfoRec);
2800    }
2801    if (pSmi->EXADriverPtr) {
2802	exaDriverFini(pScreen);
2803	pSmi->EXADriverPtr = NULL;
2804    }
2805    if (pSmi->CursorInfoRec != NULL) {
2806	xf86DestroyCursorInfoRec(pSmi->CursorInfoRec);
2807    }
2808    if (pSmi->DGAModes != NULL) {
2809	xfree(pSmi->DGAModes);
2810    }
2811    if (pSmi->pInt10 != NULL) {
2812	xf86FreeInt10(pSmi->pInt10);
2813	pSmi->pInt10 = NULL;
2814    }
2815    if (pSmi->ptrAdaptor != NULL) {
2816	xfree(pSmi->ptrAdaptor);
2817    }
2818    if (pSmi->BlockHandler != NULL) {
2819	pScreen->BlockHandler = pSmi->BlockHandler;
2820    }
2821    /* #670 */
2822    if (pSmi->pSaveBuffer) {
2823	xfree(pSmi->pSaveBuffer);
2824    }
2825/* #920 */
2826    if (pSmi->paletteBuffer) {
2827	xfree(pSmi->paletteBuffer);
2828    }
2829
2830    pScrn->vtSema = FALSE;
2831    pScreen->CloseScreen = pSmi->CloseScreen;
2832    ret = (*pScreen->CloseScreen)(scrnIndex, pScreen);
2833
2834    LEAVE_PROC("SMI_CloseScreen");
2835    return ret;
2836}
2837
2838static void
2839SMI_FreeScreen(int scrnIndex, int flags)
2840{
2841    SMI_FreeRec(xf86Screens[scrnIndex]);
2842}
2843
2844static Bool
2845SMI_SaveScreen(ScreenPtr pScreen, int mode)
2846{
2847    Bool ret;
2848
2849    ENTER_PROC("SMI_SaveScreen");
2850
2851    ret = vgaHWSaveScreen(pScreen, mode);
2852
2853    LEAVE_PROC("SMI_SaveScreen");
2854    return ret;
2855}
2856
2857void
2858SMI_AdjustFrame(int scrnIndex, int x, int y, int flags)
2859{
2860    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2861    SMIPtr pSmi = SMIPTR(pScrn);
2862    CARD32 Base, lcdBase;
2863
2864    ENTER_PROC("SMI_AdjustFrame");
2865
2866    if (pSmi->ShowCache && y) {
2867	y += pScrn->virtualY - 1;
2868    }
2869
2870    if (pSmi->Dualhead) {
2871	lcdBase = 0;
2872	x = pSmi->lcdWidth;
2873	y = 0;
2874    }
2875
2876    Base = pSmi->FBOffset + (x + y * pScrn->virtualX) * pSmi->Bpp;
2877    if (SMI_LYNX3D_SERIES(pSmi->Chipset) ||
2878	SMI_COUGAR_SERIES(pSmi->Chipset)) {
2879	Base = (Base + 15) & ~15;
2880#if 1 /* PDR#1058 */
2881	while ((Base % pSmi->Bpp) > 0) {
2882	    Base -= 16;
2883	}
2884#endif
2885    } else {
2886	Base = (Base + 7) & ~7;
2887#if 1 /* PDR#1058 */
2888	while ((Base % pSmi->Bpp) > 0) {
2889	    Base -= 8;
2890	}
2891#endif
2892    }
2893
2894    if (pSmi->Dualhead) {
2895
2896	/* FIFO1 read start address */
2897	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40,
2898			 (lcdBase & 0x000000FF));
2899	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41,
2900			 ((lcdBase & 0x0000FF00) >> 8));
2901
2902	/* FIFO2 read start address */
2903	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42,
2904			 (lcdBase & 0x000000FF));
2905	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43,
2906			 ((lcdBase & 0x0000FF00) >> 8));
2907
2908	/* FIFO1/2 read start address overflow */
2909	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45,
2910		((lcdBase & 0x000F0000) >> 12) | (((lcdBase & 0x000F0000) >> 12) << 4));
2911
2912    }
2913
2914    WRITE_VPR(pSmi, 0x0C, Base >> 3);
2915    if (pSmi->Chipset == SMI_COUGAR3DR) {
2916	WRITE_FPR(pSmi, FPR0C, Base >> 3);
2917    }
2918
2919    LEAVE_PROC("SMI_AdjustFrame");
2920}
2921
2922Bool
2923SMI_SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
2924{
2925    Bool ret;
2926    SMIPtr pSmi = SMIPTR(xf86Screens[scrnIndex]);
2927
2928    ENTER_PROC("SMI_SwitchMode");
2929
2930    pSmi->IsSwitching = TRUE;
2931    ret = SMI_ModeInit(xf86Screens[scrnIndex], mode);
2932    pSmi->IsSwitching = FALSE;
2933
2934    LEAVE_PROC("SMI_SwitchMode");
2935    return ret;
2936}
2937
2938void
2939SMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors,
2940				VisualPtr pVisual)
2941{
2942    SMIPtr pSmi = SMIPTR(pScrn);
2943    int i;
2944
2945    ENTER_PROC("SMI_LoadPalette");
2946
2947    /* Enable both the CRT and LCD DAC RAM paths, so both palettes are updated */
2948    if ((pSmi->Chipset == SMI_LYNX3DM) ||
2949	(pSmi->Chipset == SMI_COUGAR3DR)) {
2950	CARD8 ccr66;
2951
2952	ccr66  = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
2953	ccr66 &= 0x0f;
2954	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, ccr66);
2955    }
2956
2957    for(i = 0; i < numColors; i++) {
2958        DEBUG((VERBLEV, "pal[%d] = %d %d %d\n", indicies[i],
2959        colors[indicies[i]].red, colors[indicies[i]].green, colors[indicies[i]].blue));
2960	VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, indicies[i]);
2961	VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].red);
2962	VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].green);
2963	VGAOUT8(pSmi, VGA_DAC_DATA, colors[indicies[i]].blue);
2964    }
2965
2966    LEAVE_PROC("SMI_LoadPalette");
2967}
2968
2969static void
2970SMI_DisableVideo(ScrnInfoPtr pScrn)
2971{
2972    SMIPtr pSmi = SMIPTR(pScrn);
2973    CARD8 tmp;
2974
2975    if (!(tmp = VGAIN8(pSmi, VGA_DAC_MASK)))
2976	return;
2977    pSmi->DACmask = tmp;
2978    VGAOUT8(pSmi, VGA_DAC_MASK, 0);
2979}
2980
2981static void
2982SMI_EnableVideo(ScrnInfoPtr pScrn)
2983{
2984    SMIPtr pSmi = SMIPTR(pScrn);
2985
2986    VGAOUT8(pSmi, VGA_DAC_MASK, pSmi->DACmask);
2987}
2988
2989
2990void
2991SMI_EnableMmio(ScrnInfoPtr pScrn)
2992{
2993    vgaHWPtr hwp = VGAHWPTR(pScrn);
2994    SMIPtr pSmi = SMIPTR(pScrn);
2995    CARD8 tmp;
2996
2997    ENTER_PROC("SMI_EnableMmio");
2998
2999    /*
3000     * Enable chipset (seen on uninitialized secondary cards) might not be
3001     * needed once we use the VGA softbooter
3002     */
3003    vgaHWSetStdFuncs(hwp);
3004
3005    /* Enable linear mode */
3006    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
3007    tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
3008    pSmi->SR18Value = tmp;					/* PDR#521 */
3009    outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x11);
3010
3011    /* Enable 2D/3D Engine and Video Processor */
3012    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
3013    tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
3014    pSmi->SR21Value = tmp;					/* PDR#521 */
3015    outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp & ~0x03);
3016
3017    LEAVE_PROC("SMI_EnableMmio");
3018}
3019
3020void
3021SMI_DisableMmio(ScrnInfoPtr pScrn)
3022{
3023    vgaHWPtr hwp = VGAHWPTR(pScrn);
3024    SMIPtr pSmi = SMIPTR(pScrn);
3025
3026    ENTER_PROC("SMI_DisableMmio");
3027
3028    vgaHWSetStdFuncs(hwp);
3029
3030    /* Disable 2D/3D Engine and Video Processor */
3031    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
3032    outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR21Value);	/* PDR#521 */
3033
3034    /* Disable linear mode */
3035    outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
3036    outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR18Value);	/* PDR#521 */
3037
3038    LEAVE_PROC("SMI_DisableMmio");
3039}
3040
3041/* This function is used to debug, it prints out the contents of Lynx regs */
3042static void
3043SMI_PrintRegs(ScrnInfoPtr pScrn)
3044{
3045    unsigned char i;
3046    vgaHWPtr hwp = VGAHWPTR(pScrn);
3047    SMIPtr pSmi = SMIPTR(pScrn);
3048    int vgaCRIndex = hwp->IOBase + VGA_CRTC_INDEX_OFFSET;
3049    int vgaCRReg   = hwp->IOBase + VGA_CRTC_DATA_OFFSET;
3050    int vgaStatus  = hwp->IOBase + VGA_IN_STAT_1_OFFSET;
3051
3052    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
3053		"START register dump ------------------\n");
3054
3055    xf86ErrorFVerb(VERBLEV, "MISCELLANEOUS OUTPUT\n    %02X\n",
3056		VGAIN8(pSmi, VGA_MISC_OUT_R));
3057
3058    xf86ErrorFVerb(VERBLEV, "\nSEQUENCER\n"
3059		"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
3060    for (i = 0x00; i <= 0xAF; i++) {
3061	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
3062	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
3063	xf86ErrorFVerb(VERBLEV, "%02X ",
3064	    VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, i));
3065    }
3066
3067    xf86ErrorFVerb(VERBLEV, "\n\nCRT CONTROLLER\n"
3068		"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
3069    for (i = 0x00; i <= 0xAD; i++) {
3070	if (i == 0x20) i = 0x30;
3071	if (i == 0x50) i = 0x90;
3072	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
3073	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
3074	xf86ErrorFVerb(VERBLEV, "%02X ",
3075	    VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRReg, i));
3076    }
3077
3078    xf86ErrorFVerb(VERBLEV, "\n\nGRAPHICS CONTROLLER\n"
3079		"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
3080    for (i = 0x00; i <= 0x08; i++) {
3081	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
3082	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
3083	xf86ErrorFVerb(VERBLEV, "%02X ",
3084	    VGAIN8_INDEX(pSmi, VGA_GRAPH_INDEX, VGA_GRAPH_DATA, i));
3085    }
3086
3087    xf86ErrorFVerb(VERBLEV, "\n\nATTRIBUTE 0CONTROLLER\n"
3088		"    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
3089    for (i = 0x00; i <= 0x14; i++) {
3090	(void) VGAIN8(pSmi, vgaStatus);
3091	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
3092	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
3093	xf86ErrorFVerb(VERBLEV, "%02X ",
3094	    VGAIN8_INDEX(pSmi, VGA_ATTR_INDEX, VGA_ATTR_DATA_R, i));
3095    }
3096    (void) VGAIN8(pSmi, vgaStatus);
3097    VGAOUT8(pSmi, VGA_ATTR_INDEX, 0x20);
3098
3099    xf86ErrorFVerb(VERBLEV, "\n\nDPR    x0       x4       x8       xC");
3100    for (i = 0x00; i <= 0x44; i += 4) {
3101	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
3102	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_DPR(pSmi, i));
3103    }
3104
3105    xf86ErrorFVerb(VERBLEV, "\n\nVPR    x0       x4       x8       xC");
3106    for (i = 0x00; i <= 0x60; i += 4) {
3107	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
3108	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_VPR(pSmi, i));
3109    }
3110
3111    xf86ErrorFVerb(VERBLEV, "\n\nCPR    x0       x4       x8       xC");
3112    for (i = 0x00; i <= 0x18; i += 4) {
3113	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
3114	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_CPR(pSmi, i));
3115    }
3116
3117    xf86ErrorFVerb(VERBLEV, "\n\n");
3118    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
3119		"END register dump --------------------\n");
3120}
3121
3122/*
3123 * SMI_DisplayPowerManagementSet -- Sets VESA Display Power Management
3124 * Signaling (DPMS) Mode.
3125 */
3126static void
3127SMI_DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
3128							  int flags)
3129{
3130    vgaHWPtr hwp = VGAHWPTR(pScrn);
3131    SMIPtr pSmi = SMIPTR(pScrn);
3132    CARD8 SR01, SR20, SR21, SR22, SR23, SR24, SR31, SR34;
3133
3134    ENTER_PROC("SMI_DisplayPowerManagementSet");
3135
3136    /* If we already are in the requested DPMS mode, just return */
3137    if (pSmi->CurrentDPMS == PowerManagementMode) {
3138	LEAVE_PROC("SMI_DisplayPowerManagementSet");
3139	return;
3140    }
3141
3142#if 1 /* PDR#735 */
3143    if (pSmi->useBIOS && pSmi->pInt10 != NULL) {
3144	pSmi->pInt10->ax = 0x4F10;
3145	switch (PowerManagementMode) {
3146	case DPMSModeOn:
3147	    pSmi->pInt10->bx = 0x0001;
3148	    break;
3149	case DPMSModeStandby:
3150	    pSmi->pInt10->bx = 0x0101;
3151	    break;
3152	case DPMSModeSuspend:
3153	    pSmi->pInt10->bx = 0x0201;
3154	    break;
3155	case DPMSModeOff:
3156	    pSmi->pInt10->bx = 0x0401;
3157	    break;
3158	}
3159	pSmi->pInt10->cx = 0x0000;
3160	pSmi->pInt10->num = 0x10;
3161	xf86ExecX86int10(pSmi->pInt10);
3162	if (pSmi->pInt10->ax == 0x004F) {
3163	    pSmi->CurrentDPMS = PowerManagementMode;
3164#if 1 /* PDR#835 */
3165	    if (PowerManagementMode == DPMSModeOn) {
3166		SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01);
3167		VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01,
3168				SR01 & ~0x20);
3169	    }
3170#endif
3171	    LEAVE_PROC("SMI_DisplayPowerManagementSet");
3172	    return;
3173	}
3174    }
3175#endif
3176
3177    /* Save the current SR registers */
3178    if (pSmi->CurrentDPMS == DPMSModeOn) {
3179	pSmi->DPMS_SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20);
3180	pSmi->DPMS_SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
3181	pSmi->DPMS_SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
3182	pSmi->DPMS_SR34 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34);
3183    }
3184
3185    /* Read the required SR registers for the DPMS handler */
3186    SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01);
3187    SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20);
3188    SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
3189    SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22);
3190    SR23 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23);
3191    SR24 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24);
3192    SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
3193    SR34 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34);
3194
3195    switch (PowerManagementMode) {
3196    case DPMSModeOn:
3197	/* Screen On: HSync: On, VSync : On */
3198	SR01 &= ~0x20;
3199	SR20  = pSmi->DPMS_SR20;
3200	SR21  = pSmi->DPMS_SR21;
3201	SR22 &= ~0x30;
3202	SR23 &= ~0xC0;
3203	SR24 |= 0x01;
3204	SR31  = pSmi->DPMS_SR31;
3205	SR34  = pSmi->DPMS_SR34;
3206	break;
3207    case DPMSModeStandby:
3208	/* Screen: Off; HSync: Off, VSync: On */
3209	SR01 |= 0x20;
3210	SR20  = (SR20 & ~0xB0) | 0x10;
3211	SR21 |= 0x88;
3212	SR22  = (SR22 & ~0x30) | 0x10;
3213	SR23  = (SR23 & ~0x07) | 0xD8;
3214	SR24 &= ~0x01;
3215	SR31  = (SR31 & ~0x07) | 0x00;
3216	SR34 |= 0x80;
3217	break;
3218    case DPMSModeSuspend:
3219	/* Screen: Off; HSync: On, VSync: Off */
3220	SR01 |= 0x20;
3221	SR20  = (SR20 & ~0xB0) | 0x10;
3222	SR21 |= 0x88;
3223	SR22  = (SR22 & ~0x30) | 0x20;
3224	SR23  = (SR23 & ~0x07) | 0xD8;
3225	SR24 &= ~0x01;
3226	SR31  = (SR31 & ~0x07) | 0x00;
3227	SR34 |= 0x80;
3228	break;
3229    case DPMSModeOff:
3230	/* Screen: Off; HSync: Off, VSync: Off */
3231	SR01 |= 0x20;
3232	SR20  = (SR20 & ~0xB0) | 0x10;
3233	SR21 |= 0x88;
3234	SR22  = (SR22 & ~0x30) | 0x30;
3235	SR23  = (SR23 & ~0x07) | 0xD8;
3236	SR24 &= ~0x01;
3237	SR31  = (SR31 & ~0x07) | 0x00;
3238	SR34 |= 0x80;
3239	break;
3240    default:
3241	xf86ErrorFVerb(VERBLEV, "Invalid PowerManagementMode %d passed to "
3242		"SMI_DisplayPowerManagementSet\n", PowerManagementMode);
3243	LEAVE_PROC("SMI_DisplayPowerManagementSet");
3244	return;
3245    }
3246
3247    /* Wait for vertical retrace */
3248    while (hwp->readST01(hwp) & 0x8) ;
3249    while (!(hwp->readST01(hwp) & 0x8)) ;
3250
3251    /* Write the registers */
3252    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01, SR01);
3253    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34, SR34);
3254    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, SR31);
3255    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20, SR20);
3256    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, SR22);
3257    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23, SR23);
3258    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, SR21);
3259    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24, SR24);
3260
3261    /* Save the current power state */
3262    pSmi->CurrentDPMS = PowerManagementMode;
3263
3264    LEAVE_PROC("SMI_DisplayPowerManagementSet");
3265}
3266
3267static void
3268SMI_ProbeDDC(ScrnInfoPtr pScrn, int index)
3269{
3270    vbeInfoPtr pVbe;
3271    if (xf86LoadSubModule(pScrn, "vbe")) {
3272	pVbe = VBEInit(NULL, index);
3273	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3274	vbeFree(pVbe);
3275    }
3276}
3277
3278static unsigned int
3279SMI_ddc1Read(ScrnInfoPtr pScrn)
3280{
3281    register vgaHWPtr hwp = VGAHWPTR(pScrn);
3282    SMIPtr pSmi = SMIPTR(pScrn);
3283    unsigned int ret;
3284
3285    ENTER_PROC("SMI_ddc1Read");
3286
3287    while (hwp->readST01(hwp) & 0x8) ;
3288    while (!(hwp->readST01(hwp) & 0x8)) ;
3289
3290    ret = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72) & 0x08;
3291
3292    LEAVE_PROC("SMI_ddc1Read");
3293    return ret;
3294}
3295
3296static Bool
3297SMI_ddc1(int scrnIndex)
3298{
3299    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
3300    SMIPtr pSmi = SMIPTR(pScrn);
3301    Bool success = FALSE;
3302    xf86MonPtr pMon;
3303    unsigned char tmp;
3304
3305    ENTER_PROC("SMI_ddc1");
3306
3307    tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72);
3308    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp | 0x20);
3309
3310    pMon = xf86PrintEDID(xf86DoEDID_DDC1(scrnIndex,
3311					 vgaHWddc1SetSpeedWeak(),
3312					 SMI_ddc1Read));
3313    if (pMon != NULL) {
3314	success = TRUE;
3315    }
3316    xf86SetDDCproperties(pScrn, pMon);
3317
3318    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp);
3319
3320    LEAVE_PROC("SMI_ddc1");
3321    return success;
3322}
3323
3324