smi_driver.c revision 7104f784
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
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include "xf86Resources.h"
35#include "xf86RAC.h"
36#include "xf86DDC.h"
37#include "xf86int10.h"
38#include "vbe.h"
39
40#include "smi.h"
41#include "smi_501.h"
42#include "smilynx.h"
43#include "smi_crtc.h"
44
45#include "globals.h"
46#define DPMS_SERVER
47#include <X11/extensions/dpms.h>
48
49/*
50 * Internals
51 */
52static Bool SMI_MapMmio(ScrnInfoPtr pScrn);
53static Bool SMI_DetectMem(ScrnInfoPtr pScrn);
54static void SMI_EnableMmio(ScrnInfoPtr pScrn);
55static void SMI_DisableMmio(ScrnInfoPtr pScrn);
56static Bool SMI_HWInit(ScrnInfoPtr pScrn);
57
58/*
59 * Forward definitions for the functions that make up the driver.
60 */
61
62static const OptionInfoRec * SMI_AvailableOptions(int chipid, int busid);
63static void SMI_Identify(int flags);
64static Bool SMI_Probe(DriverPtr drv, int flags);
65static Bool SMI_PreInit(ScrnInfoPtr pScrn, int flags);
66static Bool SMI_EnterVT(int scrnIndex, int flags);
67static void SMI_LeaveVT(int scrnIndex, int flags);
68static Bool SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
69                           char **argv);
70static void SMI_DisableVideo(ScrnInfoPtr pScrn);
71static void SMI_EnableVideo(ScrnInfoPtr pScrn);
72static Bool SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen);
73static Bool SMI_SaveScreen(ScreenPtr pScreen, int mode);
74static void SMI_FreeScreen(int ScrnIndex, int flags);
75static void SMI_ProbeDDC(ScrnInfoPtr pScrn, int index);
76static void SMI_DetectPanelSize(ScrnInfoPtr pScrn);
77static void SMI_DetectMCLK(ScrnInfoPtr pScrn);
78
79/*
80 * xf86VDrvMsgVerb prints up to 14 characters prefix, where prefix has the
81 * format "%s(%d): " so, use name "SMI" instead of "Silicon Motion"
82 */
83#define SILICONMOTION_NAME          "SMI"
84#define SILICONMOTION_DRIVER_NAME   "siliconmotion"
85#define SILICONMOTION_VERSION_NAME  PACKAGE_VERSION
86#define SILICONMOTION_VERSION_MAJOR PACKAGE_VERSION_MAJOR
87#define SILICONMOTION_VERSION_MINOR PACKAGE_VERSION_MINOR
88#define SILICONMOTION_PATCHLEVEL    PACKAGE_VERSION_PATCHLEVEL
89#define SILICONMOTION_DRIVER_VERSION ((SILICONMOTION_VERSION_MAJOR << 24) | \
90                                      (SILICONMOTION_VERSION_MINOR << 16) | \
91                                      (SILICONMOTION_PATCHLEVEL))
92
93#if SMI_DEBUG
94int smi_indent = 1;
95#endif
96
97/* for dualhead */
98int gSMIEntityIndex = -1;
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    { PCI_CHIP_SMI501, "MSOC"	 },
130    { -1,             NULL      }
131};
132
133static PciChipsets SMIPciChipsets[] =
134{
135    /* numChipset,	PciID,			Resource */
136    { PCI_CHIP_SMI910,	PCI_CHIP_SMI910,	RES_SHARED_VGA },
137    { PCI_CHIP_SMI810,	PCI_CHIP_SMI810,	RES_SHARED_VGA },
138    { PCI_CHIP_SMI820,	PCI_CHIP_SMI820,	RES_SHARED_VGA },
139    { PCI_CHIP_SMI710,	PCI_CHIP_SMI710,	RES_SHARED_VGA },
140    { PCI_CHIP_SMI712,	PCI_CHIP_SMI712,	RES_SHARED_VGA },
141    { PCI_CHIP_SMI720,	PCI_CHIP_SMI720,	RES_SHARED_VGA },
142    { PCI_CHIP_SMI731,	PCI_CHIP_SMI731,	RES_SHARED_VGA },
143    { PCI_CHIP_SMI501,	PCI_CHIP_SMI501,	RES_UNDEFINED  },
144    { -1,		-1,			RES_UNDEFINED  }
145};
146
147typedef enum
148{
149    OPTION_PCI_BURST,
150    OPTION_PCI_RETRY,
151    OPTION_NOACCEL,
152    OPTION_MCLK,
153    OPTION_MXCLK,
154    OPTION_SWCURSOR,
155    OPTION_HWCURSOR,
156    OPTION_VIDEOKEY,
157    OPTION_BYTESWAP,
158    /* CZ 26.10.2001: interlaced video */
159    OPTION_INTERLACED,
160    /* end CZ */
161    OPTION_USEBIOS,
162    OPTION_DUALHEAD,
163    OPTION_ACCELMETHOD,
164    OPTION_PANEL_SIZE,
165    OPTION_USE_FBDEV,
166    OPTION_CSCVIDEO,
167    NUMBER_OF_OPTIONS
168} SMIOpts;
169
170static const OptionInfoRec SMIOptions[] =
171{
172    { OPTION_PCI_BURST,	     "pci_burst",	  OPTV_BOOLEAN, {0}, TRUE },
173    { OPTION_PCI_RETRY,	     "pci_retry",	  OPTV_BOOLEAN, {0}, TRUE },
174    { OPTION_NOACCEL,	     "NoAccel",		  OPTV_BOOLEAN, {0}, FALSE },
175    { OPTION_MCLK,	     "MCLK",		  OPTV_FREQ,	{0}, FALSE },
176    { OPTION_MXCLK,	     "MXCLK",		  OPTV_FREQ,	{0}, FALSE },
177    { OPTION_HWCURSOR,	     "HWCursor",	  OPTV_BOOLEAN, {0}, TRUE },
178    { OPTION_SWCURSOR,	     "SWCursor",	  OPTV_BOOLEAN, {0}, FALSE },
179    { OPTION_VIDEOKEY,	     "VideoKey",	  OPTV_INTEGER, {0}, FALSE },
180    { OPTION_BYTESWAP,	     "ByteSwap",	  OPTV_BOOLEAN, {0}, FALSE },
181    /* CZ 26.10.2001: interlaced video */
182    { OPTION_INTERLACED,     "Interlaced",        OPTV_BOOLEAN, {0}, FALSE },
183    /* end CZ */
184    { OPTION_USEBIOS,	     "UseBIOS",		  OPTV_BOOLEAN,	{0}, FALSE },
185    { OPTION_DUALHEAD,	     "Dualhead",	  OPTV_BOOLEAN,	{0}, TRUE },
186    { OPTION_ACCELMETHOD,    "AccelMethod",       OPTV_STRING,  {0}, FALSE },
187    { OPTION_PANEL_SIZE,     "PanelSize",	  OPTV_ANYSTR,	{0}, FALSE },
188    { OPTION_USE_FBDEV,	     "UseFBDev",	  OPTV_BOOLEAN,	{0}, FALSE },
189    { OPTION_CSCVIDEO,	     "CSCVideo",	  OPTV_BOOLEAN, {0}, TRUE },
190    { -1,		     NULL,		  OPTV_NONE,	{0}, FALSE }
191};
192
193/*
194 * Lists of symbols that may/may not be required by this driver.
195 * This allows the loader to know which ones to issue warnings for.
196 *
197 * Note that vgahwSymbols and xaaSymbols are referenced outside the
198 * XFree86LOADER define in later code, so are defined outside of that
199 * define here also.
200 */
201
202static const char *vgahwSymbols[] =
203{
204    "vgaHWCopyReg",
205    "vgaHWGetHWRec",
206    "vgaHWGetIOBase",
207    "vgaHWGetIndex",
208    "vgaHWInit",
209    "vgaHWLock",
210    "vgaHWMapMem",
211    "vgaHWProtect",
212    "vgaHWRestore",
213    "vgaHWSave",
214    "vgaHWSaveScreen",
215    "vgaHWSetMmioFuncs",
216    "vgaHWSetStdFuncs",
217    "vgaHWUnmapMem",
218    "vgaHWddc1SetSpeedWeak",
219    NULL
220};
221
222static const char *xaaSymbols[] =
223{
224    "XAAGetCopyROP",
225    "XAACreateInfoRec",
226    "XAADestroyInfoRec",
227    "XAAGetFallbackOps",
228    "XAAInit",
229    "XAAGetPatternROP",
230    NULL
231};
232
233static const char *exaSymbols[] =
234{
235    "exaDriverAlloc",
236    "exaDriverInit",
237    "exaDriverFini",
238    "exaOffscreenAlloc",
239    "exaOffscreenFree",
240    "exaGetPixmapPitch",
241    "exaGetPixmapOffset",
242    "exaGetPixmapSize",
243    NULL
244};
245
246static const char *ddcSymbols[] =
247{
248    "xf86PrintEDID",
249    "xf86DoEDID_DDC1",
250    "xf86DoEDID_DDC2",
251    "xf86SetDDCproperties",
252    NULL
253};
254
255static const char *i2cSymbols[] =
256{
257    "xf86CreateI2CBusRec",
258    "xf86CreateI2CDevRec",
259    "xf86DestroyI2CBusRec",
260    "xf86DestroyI2CDevRec",
261    "xf86I2CBusInit",
262    "xf86I2CDevInit",
263    "xf86I2CReadBytes",
264    "xf86I2CWriteByte",
265    NULL
266};
267
268static const char *int10Symbols[] =
269{
270    "xf86ExecX86int10",
271    "xf86FreeInt10",
272    "xf86InitInt10",
273    NULL
274};
275
276static const char *vbeSymbols[] =
277{
278    "VBEInit",
279    "vbeDoEDID",
280    "vbeFree",
281    NULL
282};
283
284static const char *fbSymbols[] =
285{
286    "fbPictureInit",
287    "fbScreenInit",
288    NULL
289};
290
291#ifdef XFree86LOADER
292
293static MODULESETUPPROTO(siliconmotionSetup);
294
295static XF86ModuleVersionInfo SMIVersRec =
296{
297    "siliconmotion",
298    MODULEVENDORSTRING,
299    MODINFOSTRING1,
300    MODINFOSTRING2,
301    XORG_VERSION_CURRENT,
302    SILICONMOTION_VERSION_MAJOR,
303    SILICONMOTION_VERSION_MINOR,
304    SILICONMOTION_PATCHLEVEL,
305    ABI_CLASS_VIDEODRV,
306    ABI_VIDEODRV_VERSION,
307    MOD_CLASS_VIDEODRV,
308    {0, 0, 0, 0}
309};
310
311/*
312 * This is the module init data for XFree86 modules.
313 *
314 * Its name has to be the driver name followed by ModuleData.
315 */
316_X_EXPORT XF86ModuleData siliconmotionModuleData =
317{
318    &SMIVersRec,
319    siliconmotionSetup,
320    NULL
321};
322
323static pointer
324siliconmotionSetup(pointer module, pointer opts, int *errmaj, int *errmin)
325{
326    static Bool setupDone = FALSE;
327
328    if (!setupDone) {
329	setupDone = TRUE;
330	xf86AddDriver(&SILICONMOTION, module, 0);
331
332	/*
333	 * Modules that this driver always requires can be loaded here
334	 * by calling LoadSubModule().
335	 */
336
337	/*
338	 * Tell the loader about symbols from other modules that this module
339	 * might refer to.
340	 */
341	LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, exaSymbols,
342					  ddcSymbols, i2cSymbols, int10Symbols, vbeSymbols,
343					  NULL);
344
345	/*
346	 * The return value must be non-NULL on success even though there
347	 * is no TearDownProc.
348	 */
349	return (pointer) 1;
350
351    } else {
352	if (errmaj) {
353	    *errmaj = LDR_ONCEONLY;
354	}
355	return NULL;
356    }
357}
358
359#endif /* XFree86LOADER */
360
361static Bool
362SMI_GetRec(ScrnInfoPtr pScrn)
363{
364    ENTER();
365
366    /*
367     * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate.
368     * pScrn->driverPrivate is initialised to NULL, so we can check if
369     * the allocation has already been done.
370     */
371    if (pScrn->driverPrivate == NULL) {
372	pScrn->driverPrivate = xnfcalloc(sizeof(SMIRec), 1);
373    }
374
375    LEAVE(TRUE);
376}
377
378static void
379SMI_FreeRec(ScrnInfoPtr pScrn)
380{
381    SMIPtr	pSmi = SMIPTR(pScrn);
382
383    ENTER();
384
385    if (pSmi) {
386	xfree(pSmi->save);
387	xfree(pSmi->mode);
388	xfree(pScrn->driverPrivate);
389	pScrn->driverPrivate = NULL;
390    }
391
392    LEAVE();
393}
394
395static const OptionInfoRec *
396SMI_AvailableOptions(int chipid, int busid)
397{
398    ENTER();
399
400    LEAVE(SMIOptions);
401}
402
403static void
404SMI_Identify(int flags)
405{
406    ENTER();
407
408    xf86PrintChipsets(SILICONMOTION_NAME, "driver (version "
409		SILICONMOTION_VERSION_NAME ") for Silicon Motion Lynx chipsets",
410		SMIChipsets);
411
412    LEAVE();
413}
414
415static Bool
416SMI_Probe(DriverPtr drv, int flags)
417{
418    int i;
419    GDevPtr *devSections;
420    int *usedChips;
421    int numDevSections;
422    int numUsed;
423    Bool foundScreen = FALSE;
424
425    ENTER();
426
427    numDevSections = xf86MatchDevice(SILICONMOTION_DRIVER_NAME, &devSections);
428
429    if (numDevSections <= 0)
430	/* There's no matching device section in the config file, so quit now. */
431	LEAVE(FALSE);
432
433#ifndef XSERVER_LIBPCIACCESS
434    if (xf86GetPciVideoInfo() == NULL)
435	LEAVE(FALSE);
436#endif
437
438    numUsed = xf86MatchPciInstances(SILICONMOTION_NAME, PCI_SMI_VENDOR_ID,
439				    SMIChipsets, SMIPciChipsets, devSections,
440				    numDevSections, drv, &usedChips);
441
442    /* Free it since we don't need that list after this */
443    xfree(devSections);
444    if (numUsed <= 0)
445	LEAVE(FALSE);
446
447    if (flags & PROBE_DETECT)
448	foundScreen = TRUE;
449    else {
450	ScrnInfoPtr	pScrn;
451	EntityInfoPtr	pEnt;
452
453	for (i = 0; i < numUsed; i++) {
454	    if ((pScrn = xf86ConfigPciEntity(NULL, 0, usedChips[i],
455					     SMIPciChipsets, NULL,
456					     NULL, NULL, NULL, NULL))) {
457		pScrn->driverVersion = SILICONMOTION_DRIVER_VERSION;
458		pScrn->driverName    = SILICONMOTION_DRIVER_NAME;
459		pScrn->name	     = SILICONMOTION_NAME;
460		pScrn->Probe	     = SMI_Probe;
461		pScrn->PreInit	     = SMI_PreInit;
462		pScrn->ScreenInit    = SMI_ScreenInit;
463		pScrn->SwitchMode    = SMI_SwitchMode;
464		pScrn->AdjustFrame   = SMI_AdjustFrame;
465
466		if ((pEnt = xf86GetEntityInfo(usedChips[i]))) {
467			pScrn->EnterVT   = SMI_EnterVT;
468			pScrn->LeaveVT   = SMI_LeaveVT;
469		    xfree(pEnt);
470		}
471		pScrn->FreeScreen    = SMI_FreeScreen;
472		foundScreen	     = TRUE;
473	    }
474	}
475    }
476    xfree(usedChips);
477
478    LEAVE(foundScreen);
479}
480
481static Bool
482SMI_PreInit(ScrnInfoPtr pScrn, int flags)
483{
484    EntityInfoPtr pEnt;
485    SMIPtr pSmi;
486    MessageType from;
487    vgaHWPtr hwp;
488
489    ENTER();
490
491    /* Ignoring the Type list for now.  It might be needed when multiple cards
492     * are supported.
493     */
494    if (pScrn->numEntities > 1)
495	LEAVE(FALSE);
496
497    /* Allocate the SMIRec driverPrivate */
498    if (!SMI_GetRec(pScrn))
499	LEAVE(FALSE);
500    pSmi = SMIPTR(pScrn);
501
502    /* Find the PCI slot for this screen */
503    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
504
505    pSmi->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
506    pSmi->Chipset = PCI_DEV_DEVICE_ID(pSmi->PciInfo);
507
508    if (IS_MSOC(pSmi)) {
509	pSmi->Save = SMI501_Save;
510	pSmi->save = xnfcalloc(sizeof(MSOCRegRec), 1);
511	pSmi->mode = xnfcalloc(sizeof(MSOCRegRec), 1);
512    }
513    else {
514	pSmi->Save = SMILynx_Save;
515	pSmi->save = xnfcalloc(sizeof(SMIRegRec), 1);
516	pSmi->mode = xnfcalloc(sizeof(SMIRegRec), 1);
517    }
518
519    if (flags & PROBE_DETECT) {
520	if (!IS_MSOC(pSmi))
521	    SMI_ProbeDDC(pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index);
522	LEAVE(TRUE);
523    }
524
525    if (pEnt->location.type != BUS_PCI || pEnt->resources) {
526	xfree(pEnt);
527	SMI_FreeRec(pScrn);
528	LEAVE(FALSE);
529    }
530    pSmi->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
531
532    /* Set pScrn->monitor */
533    pScrn->monitor = pScrn->confScreen->monitor;
534
535    if (!IS_MSOC(pSmi)) {
536	/* The vgahw module should be loaded here when needed */
537	if (!xf86LoadSubModule(pScrn, "vgahw"))
538	    LEAVE(FALSE);
539
540	xf86LoaderReqSymLists(vgahwSymbols, NULL);
541
542	/*
543	 * Allocate a vgaHWRec
544	 */
545	if (!vgaHWGetHWRec(pScrn))
546	    LEAVE(FALSE);
547
548	hwp = VGAHWPTR(pScrn);
549	pSmi->PIOBase = hwp->PIOOffset;
550
551	xf86ErrorFVerb(VERBLEV, "\tSMI_PreInit vgaCRIndex=%x, vgaIOBase=%x, "
552		       "MMIOBase=%p\n", hwp->IOBase + VGA_CRTC_INDEX_OFFSET,
553		       hwp->IOBase, hwp->MMIOBase);
554    }
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(FALSE);
561
562    /* Check that the returned depth is one we support */
563    if (pScrn->depth != 8 && pScrn->depth != 16 && pScrn->depth != 24) {
564	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
565		   "Given depth (%d) is not supported by this driver\n",
566		   pScrn->depth);
567	LEAVE(FALSE);
568    }
569
570
571    if(pScrn->bitsPerPixel != 8 && pScrn->bitsPerPixel != 16 &&
572       pScrn->bitsPerPixel != 24 && pScrn->bitsPerPixel != 32){
573	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
574		   "Given bpp (%d) is not supported by this driver\n",
575		   pScrn->bitsPerPixel);
576	LEAVE(FALSE);
577    }
578
579    xf86PrintDepthBpp(pScrn);
580
581    /*
582     * This must happen after pScrn->display has been set because
583     * xf86SetWeight references it.
584     */
585    if (pScrn->depth > 8) {
586	/* The defaults are OK for us */
587	rgb zeros = {0, 0, 0};
588#if __BYTE_ORDER == __BIG_ENDIAN
589	rgb masks = {0xff00,0xff0000,0xff000000};
590#else
591	rgb masks = {0, 0, 0};
592#endif
593
594	if (!xf86SetWeight(pScrn, zeros, masks))
595	    LEAVE(FALSE);
596    }
597
598    if (!xf86SetDefaultVisual(pScrn, -1))
599	LEAVE(FALSE);
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(FALSE);
607    }
608
609    /* We use a programmable clock */
610    pScrn->progClock = TRUE;
611
612    /* Collect all of the relevant option flags (fill in pScrn->options) */
613    xf86CollectOptions(pScrn, NULL);
614
615    /* Set the bits per RGB for 8bpp mode */
616    if (pScrn->depth == 8){
617	pScrn->rgbBits = IS_MSOC(pSmi) ? 8 : 6;
618    }else if(pScrn->depth == 16){
619	/* Use 8 bit LUT for gamma correction*/
620	pScrn->rgbBits = 8;
621    }
622
623    /* Process the options */
624    if (!(pSmi->Options = xalloc(sizeof(SMIOptions))))
625	LEAVE(FALSE);
626
627    memcpy(pSmi->Options, SMIOptions, sizeof(SMIOptions));
628    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pSmi->Options);
629
630    /* Enable pci burst by default */
631    from = X_DEFAULT;
632    pSmi->PCIBurst = TRUE;
633    if (xf86GetOptValBool(pSmi->Options, OPTION_PCI_BURST, &pSmi->PCIBurst))
634	from = X_CONFIG;
635    xf86DrvMsg(pScrn->scrnIndex, from, "PCI Burst %sabled\n",
636	       pSmi->PCIBurst ? "en" : "dis");
637
638    /* Pci retry enabled by default if pci burst also enabled */
639    from = X_DEFAULT;
640    pSmi->PCIRetry = pSmi->PCIBurst ? TRUE : FALSE;
641    if (xf86GetOptValBool(pSmi->Options, OPTION_PCI_RETRY, &pSmi->PCIRetry)) {
642	from = X_CONFIG;
643	if (pSmi->PCIRetry && !pSmi->PCIBurst) {
644	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
645		       "\"pci_retry\" option requires \"pci_burst\".\n");
646	    pSmi->PCIRetry = FALSE;
647	}
648    }
649    xf86DrvMsg(pScrn->scrnIndex, from, "PCI Retry %sabled\n",
650	       pSmi->PCIRetry ? "en" : "dis");
651
652    if (xf86ReturnOptValBool(pSmi->Options, OPTION_NOACCEL, FALSE)) {
653	pSmi->NoAccel = TRUE;
654	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: NoAccel - Acceleration "
655		   "disabled\n");
656    } else {
657	pSmi->NoAccel = FALSE;
658    }
659
660    if (IS_MSOC(pSmi)) {
661	from = X_DEFAULT;
662	if (xf86GetOptValBool(pSmi->Options, OPTION_USE_FBDEV, &pSmi->UseFBDev))
663	    from = X_CONFIG;
664	xf86DrvMsg(pScrn->scrnIndex, from, "UseFBDev %s.\n",
665		   pSmi->UseFBDev ? "enabled" : "disabled");
666    }
667
668    from = X_CONFIG;
669    pSmi->HwCursor = TRUE;
670    /* SWCursor overrides HWCusor if both specified */
671    if (xf86ReturnOptValBool(pSmi->Options, OPTION_SWCURSOR, FALSE))
672	pSmi->HwCursor = FALSE;
673    else if (!xf86GetOptValBool(pSmi->Options, OPTION_HWCURSOR, &pSmi->HwCursor))
674	from = X_DEFAULT;
675
676    xf86DrvMsg(pScrn->scrnIndex, from, "Using %sware Cursor\n",
677	       pSmi->HwCursor ? "Hard" : "Soft");
678
679    if (xf86GetOptValInteger(pSmi->Options, OPTION_VIDEOKEY, &pSmi->videoKey)) {
680	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Video key set to "
681		   "0x%08X\n", pSmi->videoKey);
682    } else {
683	pSmi->videoKey = (1 << pScrn->offset.red) |
684			 (1 << pScrn->offset.green) |
685			 (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
686			 << pScrn->offset.blue);
687    }
688
689    if (xf86ReturnOptValBool(pSmi->Options, OPTION_BYTESWAP, FALSE)) {
690	pSmi->ByteSwap = TRUE;
691	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: ByteSwap enabled.\n");
692    } else {
693	pSmi->ByteSwap = FALSE;
694    }
695
696    /* CZ 26.10.2001: interlaced video */
697    if (xf86ReturnOptValBool(pSmi->Options, OPTION_INTERLACED, FALSE)) {
698	pSmi->interlaced = TRUE;
699	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: Interlaced enabled.\n");
700    } else {
701	pSmi->interlaced = FALSE;
702    }
703    /* end CZ */
704
705    if (IS_MSOC(pSmi))
706	pSmi->useBIOS = FALSE;
707    else if (xf86GetOptValBool(pSmi->Options, OPTION_USEBIOS, &pSmi->useBIOS)) {
708	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: UseBIOS %s.\n",
709		   pSmi->useBIOS ? "enabled" : "disabled");
710    }
711    else if(pSmi->Chipset == SMI_LYNX3DM){
712	/* Default to UseBIOS disabled. */
713	pSmi->useBIOS = FALSE;
714    }
715    else {
716	/* Default to UseBIOS enabled. */
717	pSmi->useBIOS = TRUE;
718    }
719
720    if (pSmi->useBIOS) {
721	if (xf86LoadSubModule(pScrn,"int10")) {
722	    xf86LoaderReqSymLists(int10Symbols,NULL);
723	    pSmi->pInt10 = xf86InitInt10(pEnt->index);
724	}
725
726	if (pSmi->pInt10 && xf86LoadSubModule(pScrn, "vbe")) {
727	    xf86LoaderReqSymLists(vbeSymbols, NULL);
728	    pSmi->pVbe = VBEInit(pSmi->pInt10, pEnt->index);
729	}
730
731	if(!pSmi->pVbe){
732	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "VBE initialization failed: falling back to UseBIOS disabled.\n");
733	    pSmi->useBIOS = FALSE;
734	}
735    }
736
737    xf86RegisterResources(pEnt->index, NULL, ResExclusive);
738/*  xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr); */
739/*  xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr); */
740
741    /*
742     * Set the Chipset and ChipRev, allowing config file entries to
743     * override.
744     */
745    if (pEnt->device->chipset && *pEnt->device->chipset) {
746	pScrn->chipset = pEnt->device->chipset;
747	pSmi->Chipset = xf86StringToToken(SMIChipsets, pScrn->chipset);
748	from = X_CONFIG;
749    }
750    else if (pEnt->device->chipID >= 0) {
751	pSmi->Chipset = pEnt->device->chipID;
752	pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset);
753	from = X_CONFIG;
754	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
755		   pSmi->Chipset);
756    }
757    else {
758	from = X_PROBED;
759	pSmi->Chipset = PCI_DEV_DEVICE_ID(pSmi->PciInfo);
760	pScrn->chipset = (char *) xf86TokenToString(SMIChipsets, pSmi->Chipset);
761    }
762
763    if (pEnt->device->chipRev >= 0) {
764	pSmi->ChipRev = pEnt->device->chipRev;
765	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
766		   pSmi->ChipRev);
767    }
768    else
769        pSmi->ChipRev = PCI_DEV_REVISION(pSmi->PciInfo);
770    xfree(pEnt);
771
772    /*
773     * This shouldn't happen because such problems should be caught in
774     * SMI_Probe(), but check it just in case.
775     */
776    if (pScrn->chipset == NULL) {
777	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID 0x%04X is not "
778				"recognised\n", pSmi->Chipset);
779	LEAVE(FALSE);
780    }
781
782    if (pSmi->Chipset < 0) {
783	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Chipset \"%s\" is not "
784		   "recognised\n", pScrn->chipset);
785	LEAVE(FALSE);
786    }
787
788    xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
789
790#ifndef XSERVER_LIBPCIACCESS
791    pSmi->PciTag = pciTag(pSmi->PciInfo->bus, pSmi->PciInfo->device,
792		   	  pSmi->PciInfo->func);
793#endif
794
795    from = X_DEFAULT;
796    if(pSmi->Chipset == SMI_LYNX3DM &&
797       pScrn->bitsPerPixel == 16)
798	pSmi->Dualhead = TRUE;
799    else
800	pSmi->Dualhead = FALSE;
801
802    if (xf86GetOptValBool(pSmi->Options, OPTION_DUALHEAD, &pSmi->Dualhead))
803	from = X_CONFIG;
804
805    if (IS_MSOC(pSmi)) {
806	pSmi->lcd = TRUE;
807	if (pSmi->Dualhead && pSmi->UseFBDev) {
808	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
809		       "Dual head disabled in fbdev mode\n");
810	    pSmi->Dualhead = FALSE;
811	}
812	/* FIXME Randr cursor code only works properly when argb cursors
813	 * are also supported.
814	 * FIXME This probably is a randr cursor bug, and since access to
815	 * hw/xfree86/ramdac/xf86CursorPriv.h:xf86CursorScreenRec.SWCursor
816	 * field is not available, one cannot easily workaround the problem,
817	 * so, just disable it...
818	 * TODO Check with a X Server newer then 1.4.0.90 (that is being
819	 * used in the 502 OEM image).
820	 * */
821	if (pSmi->Dualhead && pSmi->HwCursor) {
822	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
823		       "HW Cursor disabled in dual head mode\n");
824	    pSmi->HwCursor = FALSE;
825	}
826    }
827    else if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
828	/* tweak options for dualhead */
829	if (pSmi->Dualhead) {
830	    pSmi->useBIOS = FALSE;
831	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UseBIOS disabled in dualhead mode\n");
832	    pSmi->HwCursor = FALSE;
833	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No hardware cursor in dualhead mode\n");
834	    if (pScrn->bitsPerPixel != 16) {
835		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Dualhead only supported at "
836			   "depth 16\n");
837		LEAVE(FALSE);
838	    }
839	}
840    }
841    xf86DrvMsg(pScrn->scrnIndex, from, "Dual head %sabled\n",
842	       pSmi->Dualhead ? "en" : "dis");
843
844    if (!pSmi->NoAccel) {
845	char *strptr;
846
847	from = X_DEFAULT;
848	if ((strptr = (char *)xf86GetOptValString(pSmi->Options,
849						  OPTION_ACCELMETHOD))) {
850	    if (!xf86NameCmp(strptr,"XAA")) {
851		from = X_CONFIG;
852		pSmi->useEXA = FALSE;
853	    } else if(!xf86NameCmp(strptr,"EXA")) {
854		from = X_CONFIG;
855		pSmi->useEXA = TRUE;
856	    }
857	}
858
859	xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration architecture\n",
860		pSmi->useEXA ? "EXA" : "XAA");
861    }
862
863    if (IS_MSOC(pSmi)) {
864	pSmi->CSCVideo = !pSmi->useEXA || !pSmi->Dualhead;
865	from = X_DEFAULT;
866	if (xf86GetOptValBool(pSmi->Options, OPTION_CSCVIDEO, &pSmi->CSCVideo)) {
867	    from = X_CONFIG;
868
869	    /* FIXME */
870	    if (pSmi->CSCVideo && pSmi->useEXA && pSmi->Dualhead) {
871		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
872			   "CSCVideo requires XAA or EXA in single head mode.\n");
873		pSmi->CSCVideo = FALSE;
874	    }
875	}
876
877	xf86DrvMsg(pScrn->scrnIndex, from, "CSC Video %sabled\n",
878		   pSmi->CSCVideo ? "en" : "dis");
879    }
880
881    SMI_MapMmio(pScrn);
882    SMI_DetectMem(pScrn);
883    SMI_MapMem(pScrn);
884    SMI_DisableVideo(pScrn);
885
886    /* detect the panel size */
887    SMI_DetectPanelSize(pScrn);
888
889    if(!IS_MSOC(pSmi)){
890	if (xf86LoadSubModule(pScrn, "i2c")) {
891	    xf86LoaderReqSymLists(i2cSymbols, NULL);
892	    SMI_I2CInit(pScrn);
893	}
894	if (xf86LoadSubModule(pScrn, "ddc")) {
895	    xf86LoaderReqSymLists(ddcSymbols, NULL);
896	}
897    }
898
899    /*
900     * If the driver can do gamma correction, it should call xf86SetGamma()
901     */
902    {
903	Gamma zeros = { 0.0, 0.0, 0.0 };
904
905	if (!xf86SetGamma(pScrn, zeros)) {
906	    SMI_EnableVideo(pScrn);
907	    SMI_UnmapMem(pScrn);
908	    LEAVE(FALSE);
909	}
910    }
911
912    SMI_DetectMCLK(pScrn);
913
914    /*
915     * Setup the ClockRanges, which describe what clock ranges are available,
916     * and what sort of modes they can be used for.
917     */
918    pSmi->clockRange.next = NULL;
919    pSmi->clockRange.minClock = 20000;
920
921    if (SMI_LYNXM_SERIES(pSmi->Chipset) ||
922	IS_MSOC(pSmi))
923	pSmi->clockRange.maxClock = 200000;
924    else
925        pSmi->clockRange.maxClock = 135000;
926
927    pSmi->clockRange.clockIndex = -1;
928    pSmi->clockRange.interlaceAllowed = FALSE;
929    pSmi->clockRange.doubleScanAllowed = FALSE;
930
931    if(!SMI_CrtcPreInit(pScrn))
932	LEAVE(FALSE);
933
934    if(!SMI_OutputPreInit(pScrn))
935	LEAVE(FALSE);
936
937    /* Only allow growing the screen dimensions if EXA is being used */
938    if (!xf86InitialConfiguration (pScrn, !pSmi->NoAccel && pSmi->useEXA)){
939	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
940	LEAVE(FALSE);
941    }
942
943
944    SMI_EnableVideo(pScrn);
945    SMI_UnmapMem(pScrn);
946
947    if(pSmi->pVbe){
948       vbeFree(pSmi->pVbe);
949       pSmi->pVbe = NULL;
950    }
951    if(pSmi->pInt10){
952       xf86FreeInt10(pSmi->pInt10);
953       pSmi->pInt10 = NULL;
954    }
955
956    /* Set display resolution */
957    xf86SetDpi(pScrn, 0, 0);
958
959    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
960	SMI_FreeRec(pScrn);
961	LEAVE(FALSE);
962    }
963
964    xf86LoaderReqSymLists(fbSymbols, NULL);
965
966    /* Load XAA or EXA if needed */
967    if (!pSmi->NoAccel) {
968	if (!pSmi->useEXA) {
969	    if (!xf86LoadSubModule(pScrn, "xaa")) {
970		SMI_FreeRec(pScrn);
971		LEAVE(FALSE);
972	    }
973	    xf86LoaderReqSymLists(xaaSymbols, NULL);
974	} else {
975	    XF86ModReqInfo req;
976	    int errmaj, errmin;
977
978	    memset(&req, 0, sizeof(XF86ModReqInfo));
979	    req.majorversion = 2;
980	    req.minorversion = 1;
981
982	    if (!LoadSubModule(pScrn->module, "exa", NULL, NULL, NULL,
983				&req, &errmaj, &errmin)) {
984		LoaderErrorMsg(NULL, "exa", errmaj, errmin);
985		SMI_FreeRec(pScrn);
986		LEAVE(FALSE);
987	    }
988	    xf86LoaderReqSymLists(exaSymbols, NULL);
989	}
990    }
991
992    /* Load ramdac if needed */
993    if (pSmi->HwCursor) {
994	if (!xf86LoadSubModule(pScrn, "ramdac")) {
995	    SMI_FreeRec(pScrn);
996	    LEAVE(FALSE);
997	}
998    }
999
1000    LEAVE(TRUE);
1001}
1002
1003/*
1004 * This is called when VT switching back to the X server.  Its job is to
1005 * reinitialise the video mode. We may wish to unmap video/MMIO memory too.
1006 */
1007
1008static Bool
1009SMI_EnterVT(int scrnIndex, int flags)
1010{
1011    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1012    SMIPtr pSmi = SMIPTR(pScrn);
1013
1014    ENTER();
1015
1016    /* Enable MMIO and map memory */
1017    SMI_MapMem(pScrn);
1018
1019    pSmi->Save(pScrn);
1020
1021    /* FBBase may have changed after remapping the memory */
1022    pScrn->pScreen->ModifyPixmapHeader(pScrn->pScreen->GetScreenPixmap(pScrn->pScreen),
1023				       -1,-1,-1,-1,-1, pSmi->FBBase + pSmi->FBOffset);
1024    pScrn->pixmapPrivate.ptr=pSmi->FBBase + pSmi->FBOffset;
1025
1026    if(pSmi->useEXA)
1027       pSmi->EXADriverPtr->memoryBase=pSmi->FBBase;
1028
1029    /* Do the CRTC independent initialization */
1030    if(!SMI_HWInit(pScrn))
1031	LEAVE(FALSE);
1032
1033    /* Initialize the chosen modes */
1034    if (!xf86SetDesiredModes(pScrn))
1035	LEAVE(FALSE);
1036
1037    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1038		   "Done writing mode.  Register dump:\n");
1039    SMI_PrintRegs(pScrn);
1040
1041    /* Reset the grapics engine */
1042    if (!pSmi->NoAccel)
1043	SMI_EngineReset(pScrn);
1044
1045    LEAVE(TRUE);
1046}
1047
1048/*
1049 * This is called when VT switching away from the X server.  Its job is to
1050 * restore the previous (text) mode. We may wish to remap video/MMIO memory
1051 * too.
1052 */
1053
1054static void
1055SMI_LeaveVT(int scrnIndex, int flags)
1056{
1057    ScrnInfoPtr	pScrn = xf86Screens[scrnIndex];
1058    SMIPtr	pSmi = SMIPTR(pScrn);
1059
1060    ENTER();
1061
1062    SMI_AccelSync(pScrn);
1063
1064    /* Ensure that the rotation BlockHandler is unwrapped, and the shadow
1065       pixmaps are deallocated, as the video memory is going to be
1066       unmapped.  */
1067    xf86RotateCloseScreen(pScrn->pScreen);
1068
1069    /* Pixmaps that by chance get allocated near the former aperture
1070       address shouldn't be considered offscreen. */
1071    if(pSmi->useEXA)
1072       pSmi->EXADriverPtr->memoryBase=NULL;
1073
1074    /* Clear frame buffer */
1075    memset(pSmi->FBBase, 0, pSmi->videoRAMBytes);
1076
1077    if (!IS_MSOC(pSmi)) {
1078	vgaHWPtr	hwp = VGAHWPTR(pScrn);
1079
1080	SMILynx_WriteMode(pScrn, &hwp->SavedReg, pSmi->save);
1081    }
1082    else
1083	SMI501_WriteMode(pScrn, pSmi->save);
1084
1085    SMI_UnmapMem(pScrn);
1086
1087    LEAVE();
1088}
1089
1090static void
1091SMI_DetectPanelSize(ScrnInfoPtr pScrn)
1092{
1093    char	*s;
1094    int		 width, height;
1095    SMIPtr	 pSmi = SMIPTR(pScrn);
1096
1097    pSmi->lcdWidth  = 0;
1098    pSmi->lcdHeight = 0;
1099    if ((s = xf86GetOptValString(pSmi->Options, OPTION_PANEL_SIZE)) != NULL) {
1100	if (sscanf(s, "%dx%d", &width, &height) != 2)
1101	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1102		       "Invalid PanelSize option: %s\n", s);
1103	else {
1104	    pSmi->lcdWidth  = width;
1105	    pSmi->lcdHeight = height;
1106	}
1107    }
1108
1109    if (pSmi->lcdWidth == 0 || pSmi->lcdHeight == 0) {
1110	/* panel size detection ... requires BIOS call on 730 hardware */
1111	if (pSmi->Chipset == SMI_COUGAR3DR) {
1112	    if (pSmi->pInt10 != NULL) {
1113		pSmi->pInt10->num = 0x10;
1114		pSmi->pInt10->ax  = 0x5F00;
1115		pSmi->pInt10->bx  = 0;
1116		pSmi->pInt10->cx  = 0;
1117		pSmi->pInt10->dx  = 0;
1118		xf86ExecX86int10(pSmi->pInt10);
1119		if (pSmi->pInt10->ax == 0x005F) {
1120		    switch (pSmi->pInt10->cx & 0x0F) {
1121			case PANEL_640x480:
1122			    pSmi->lcdWidth  = 640;
1123			    pSmi->lcdHeight = 480;
1124			    break;
1125			case PANEL_800x600:
1126			    pSmi->lcdWidth  = 800;
1127			    pSmi->lcdHeight = 600;
1128			    break;
1129			case PANEL_1024x768:
1130			    pSmi->lcdWidth  = 1024;
1131			    pSmi->lcdHeight = 768;
1132			    break;
1133			case PANEL_1280x1024:
1134			    pSmi->lcdWidth  = 1280;
1135			    pSmi->lcdHeight = 1024;
1136			    break;
1137			case PANEL_1600x1200:
1138			    pSmi->lcdWidth  = 1600;
1139			    pSmi->lcdHeight = 1200;
1140			    break;
1141			case PANEL_1400x1050:
1142			    pSmi->lcdWidth  = 1400;
1143			    pSmi->lcdHeight = 1050;
1144			    break;
1145		    }
1146
1147		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1148			       "Detected panel size via BIOS: %d x %d\n",
1149			       pSmi->lcdWidth, pSmi->lcdHeight);
1150		}
1151		else
1152		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1153			       "BIOS error during 730 panel detection!\n");
1154	    }
1155	    else  {
1156		/* int10 support isn't setup on the second call to this function,
1157		  o if this is the second call, don't do detection again */
1158		if (pSmi->lcd == 0)
1159		    /* If we get here, int10 support is not loaded or not working */
1160		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1161			       "No BIOS support for 730 panel detection!\n");
1162	    }
1163
1164	    /* Set this to indicate that we've done the detection */
1165	    pSmi->lcd = 1;
1166	}
1167	else if (IS_MSOC(pSmi)) {
1168	    pSmi->lcdWidth  = (READ_SCR(pSmi, PANEL_WWIDTH)  >> 16) & 2047;
1169	    pSmi->lcdHeight = (READ_SCR(pSmi, PANEL_WHEIGHT) >> 16) & 2047;
1170	}
1171	else {
1172	    /* panel size detection for hardware other than 730 */
1173	    pSmi->lcd = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1174				     0x31) & 0x01;
1175
1176	    if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1177			     0x30) & 0x01) {
1178		pSmi->lcd <<= 1;
1179	    }
1180	    switch (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1181				 0x30) & 0x0C) {
1182		case 0x00:
1183		    pSmi->lcdWidth  = 640;
1184		    pSmi->lcdHeight = 480;
1185		    break;
1186		case 0x04:
1187		    pSmi->lcdWidth  = 800;
1188		    pSmi->lcdHeight = 600;
1189		    break;
1190		case 0x08:
1191		    if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1192				     0x74) & 0x02) {
1193			pSmi->lcdWidth  = 1024;
1194			pSmi->lcdHeight = 600;
1195		    }
1196		    else {
1197			pSmi->lcdWidth  = 1024;
1198			pSmi->lcdHeight = 768;
1199		    }
1200		    break;
1201		case 0x0C:
1202		    pSmi->lcdWidth  = 1280;
1203		    pSmi->lcdHeight = 1024;
1204		    break;
1205	    }
1206	}
1207    }
1208
1209    if (!pSmi->lcdWidth && (pSmi->lcdWidth = pScrn->virtualX) == 0)
1210	pSmi->lcdWidth = 1024;
1211    if (!pSmi->lcdHeight && (pSmi->lcdHeight = pScrn->virtualY) == 0)
1212	pSmi->lcdHeight = 768;
1213
1214    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Panel Size = %dx%d\n",
1215	       (pSmi->lcd == 0) ? "OFF" : (pSmi->lcd == 1) ? "TFT" : "DSTN",
1216	       pSmi->lcdWidth, pSmi->lcdHeight);
1217
1218}
1219
1220static void
1221SMI_DetectMCLK(ScrnInfoPtr pScrn)
1222{
1223    double		real;
1224    MSOCClockRec	clock;
1225    int			mclk, mxclk;
1226    SMIPtr		pSmi = SMIPTR(pScrn);
1227
1228    /* MCLK defaults */
1229    if (pSmi->Chipset == SMI_LYNXEMplus){
1230	/* The SM712 can be safely clocked up to 157MHz, according to
1231	   Silicon Motion engineers. */
1232	pSmi->MCLK = 157000;
1233    }else
1234	pSmi->MCLK = 0;
1235
1236    pSmi->MXCLK = 0;
1237
1238    /* MCLK from user settings */
1239    if (xf86GetOptValFreq(pSmi->Options, OPTION_MCLK, OPTUNITS_MHZ, &real)) {
1240	if (IS_MSOC(pSmi) || (int)real <= 120) {
1241	    pSmi->MCLK = (int)(real * 1000.0);
1242	} else {
1243	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1244		       "Memory Clock %1.3f MHz larger than limit of 120 MHz\n",
1245		       real);
1246	}
1247    }
1248    mclk = pSmi->MCLK;
1249
1250    if (IS_MSOC(pSmi)) {
1251	clock.value = READ_SCR(pSmi, CURRENT_CLOCK);
1252	if (xf86GetOptValFreq(pSmi->Options, OPTION_MXCLK,
1253			      OPTUNITS_MHZ, &real))
1254	    pSmi->MXCLK = (int)(real * 1000.0);
1255    }
1256
1257    /* Already programmed MCLK */
1258    if (pSmi->MCLK == 0) {
1259	if (IS_MSOC(pSmi))
1260	    mclk = ((clock.f.m_select ? 336 : 288) /
1261		    ((clock.f.m_divider ? 3 : 1) <<
1262		     (unsigned)clock.f.m_shift)) * 1000;
1263	else {
1264	    unsigned char	shift, m, n;
1265
1266	    m = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A);
1267	    n = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B);
1268	    switch (n >> 6) {
1269		case 1:
1270		    shift = 4;
1271		    break;
1272		case 2:
1273		    shift = 2;
1274		    break;
1275		default:
1276		    shift = 1;
1277		    break;
1278	    }
1279	    n &= 0x3F;
1280	    mclk = ((1431818 * m) / n / shift + 50) / 100;
1281	}
1282    }
1283
1284    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MCLK = %1.3f\n", mclk / 1000.0);
1285    if (IS_MSOC(pSmi)) {
1286	if (pSmi->MXCLK == 0) {
1287	    mxclk = ((clock.f.m1_select ? 336 : 288) /
1288		     ((clock.f.m1_divider ? 3 : 1) <<
1289		      (unsigned)clock.f.m1_shift)) * 1000;
1290	}
1291	else
1292	    mxclk = pSmi->MXCLK;
1293	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MXCLK = %1.3f\n", mxclk / 1000.0);
1294    }
1295}
1296
1297static Bool
1298SMI_MapMmio(ScrnInfoPtr pScrn)
1299{
1300    SMIPtr	pSmi = SMIPTR(pScrn);
1301    CARD32	memBase;
1302
1303    SMI_EnableMmio(pScrn);
1304
1305    switch (pSmi->Chipset) {
1306	case SMI_COUGAR3DR:
1307	    memBase = PCI_REGION_BASE(pSmi->PciInfo, 1, REGION_MEM);
1308	    pSmi->MapSize = 0x200000;
1309	    break;
1310	case SMI_LYNX3D:
1311	    memBase = PCI_REGION_BASE(pSmi->PciInfo, 0, REGION_MEM) + 0x680000;
1312	    pSmi->MapSize = 0x180000;
1313	    break;
1314	case SMI_LYNXEM:
1315	case SMI_LYNXEMplus:
1316	    memBase = PCI_REGION_BASE(pSmi->PciInfo, 0, REGION_MEM) + 0x400000;
1317	    pSmi->MapSize = 0x400000;
1318	    break;
1319	case SMI_LYNX3DM:
1320	    memBase = PCI_REGION_BASE(pSmi->PciInfo, 0, REGION_MEM);
1321	    pSmi->MapSize = 0x200000;
1322	    break;
1323	case SMI_MSOC:
1324	    memBase = PCI_REGION_BASE(pSmi->PciInfo, 1, REGION_MEM);
1325	    pSmi->MapSize = 0x200000;
1326	    break;
1327	default:
1328	    memBase = PCI_REGION_BASE(pSmi->PciInfo, 0, REGION_MEM) + 0x400000;
1329	    pSmi->MapSize = 0x10000;
1330	    break;
1331    }
1332
1333#ifndef XSERVER_LIBPCIACCESS
1334    pSmi->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, pSmi->PciTag,
1335				  memBase, pSmi->MapSize);
1336#else
1337    {
1338	void	**result = (void**)&pSmi->MapBase;
1339	int	  err = pci_device_map_range(pSmi->PciInfo,
1340					     memBase,
1341					     pSmi->MapSize,
1342					     PCI_DEV_MAP_FLAG_WRITABLE,
1343					     result);
1344
1345	if (err)
1346	    return (FALSE);
1347    }
1348#endif
1349
1350    if (pSmi->MapBase == NULL) {
1351	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Internal error: could not map "
1352		   "MMIO registers.\n");
1353	return (FALSE);
1354    }
1355
1356    switch (pSmi->Chipset) {
1357	case SMI_COUGAR3DR:
1358	    pSmi->DPRBase = pSmi->MapBase + 0x000000;
1359	    pSmi->VPRBase = pSmi->MapBase + 0x000800;
1360	    pSmi->CPRBase = pSmi->MapBase + 0x001000;
1361	    pSmi->FPRBase = pSmi->MapBase + 0x005800;
1362	    pSmi->IOBase  = pSmi->MapBase + 0x0C0000;
1363	    pSmi->DataPortBase = pSmi->MapBase + 0x100000;
1364	    pSmi->DataPortSize = 0x100000;
1365	    break;
1366	case SMI_LYNX3D:
1367	    pSmi->DPRBase = pSmi->MapBase + 0x000000;
1368	    pSmi->VPRBase = pSmi->MapBase + 0x000800;
1369	    pSmi->CPRBase = pSmi->MapBase + 0x001000;
1370	    pSmi->IOBase  = pSmi->MapBase + 0x040000;
1371	    pSmi->DataPortBase = pSmi->MapBase + 0x080000;
1372	    pSmi->DataPortSize = 0x100000;
1373	    break;
1374	case SMI_LYNXEM:
1375	case SMI_LYNXEMplus:
1376	    pSmi->DPRBase = pSmi->MapBase + 0x008000;
1377	    pSmi->VPRBase = pSmi->MapBase + 0x00C000;
1378	    pSmi->CPRBase = pSmi->MapBase + 0x00E000;
1379	    pSmi->IOBase  = pSmi->MapBase + 0x300000;
1380	    pSmi->DataPortBase = pSmi->MapBase /*+ 0x100000*/;
1381	    pSmi->DataPortSize = 0x8000 /*0x200000*/;
1382	    break;
1383	case SMI_LYNX3DM:
1384	    pSmi->DPRBase = pSmi->MapBase + 0x000000;
1385	    pSmi->VPRBase = pSmi->MapBase + 0x000800;
1386	    pSmi->CPRBase = pSmi->MapBase + 0x001000;
1387	    pSmi->IOBase  = pSmi->MapBase + 0x0C0000;
1388	    pSmi->DataPortBase = pSmi->MapBase + 0x100000;
1389	    pSmi->DataPortSize = 0x100000;
1390	    break;
1391	case SMI_MSOC:
1392	    pSmi->DPRBase = pSmi->MapBase + 0x100000;
1393	    pSmi->VPRBase = pSmi->MapBase + 0x000000;
1394	    pSmi->CPRBase = pSmi->MapBase + 0x090000;
1395	    pSmi->DCRBase = pSmi->MapBase + 0x080000;
1396	    pSmi->SCRBase = pSmi->MapBase + 0x000000;
1397	    pSmi->IOBase = 0;
1398	    pSmi->DataPortBase = pSmi->MapBase + 0x110000;
1399	    pSmi->DataPortSize = 0x10000;
1400	    break;
1401	default:
1402	    pSmi->DPRBase = pSmi->MapBase + 0x8000;
1403	    pSmi->VPRBase = pSmi->MapBase + 0xC000;
1404	    pSmi->CPRBase = pSmi->MapBase + 0xE000;
1405	    pSmi->IOBase  = NULL;
1406	    pSmi->DataPortBase = pSmi->MapBase;
1407	    pSmi->DataPortSize = 0x8000;
1408	    break;
1409    }
1410
1411    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1412		   "Physical MMIO at 0x%08lX\n", (unsigned long)memBase);
1413    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1414		   "Logical MMIO at %p - %p\n", pSmi->MapBase,
1415		   pSmi->MapBase + pSmi->MapSize - 1);
1416    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1417		   "DPR=%p, VPR=%p, IOBase=%p\n",
1418		   pSmi->DPRBase, pSmi->VPRBase, pSmi->IOBase);
1419    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1420		   "DataPort=%p - %p\n", pSmi->DataPortBase,
1421		   pSmi->DataPortBase + pSmi->DataPortSize - 1);
1422
1423    return (TRUE);
1424}
1425
1426static Bool
1427SMI_DetectMem(ScrnInfoPtr pScrn)
1428{
1429    SMIPtr	pSmi = SMIPTR(pScrn);
1430    MessageType from;
1431
1432    if ((pScrn->videoRam = pScrn->confScreen->device->videoRam)){
1433	pSmi->videoRAMKBytes = pScrn->videoRam;
1434	from = X_CONFIG;
1435    }
1436    else {
1437	unsigned char	 config;
1438	static int	 lynx3d_table[4]  = {  0, 2, 4, 6 };
1439	static int	 lynx3dm_table[4] = { 16, 2, 4, 8 };
1440	static int	 msoc_table[8]    = {  4, 8, 16, 32, 64, 2, 0, 0 };
1441	static int	 default_table[4] = {  1, 2, 4, 0 };
1442
1443	if (IS_MSOC(pSmi)) {
1444	    config = (READ_SCR(pSmi, DRAM_CTL) >> 13) & 7;
1445	    pSmi->videoRAMKBytes = msoc_table[config] * 1024 -
1446		SHARED_USB_DMA_BUFFER_SIZE;
1447	}
1448	else {
1449	    config = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x71);
1450	    switch (pSmi->Chipset) {
1451		case SMI_LYNX3D:
1452		    pSmi->videoRAMKBytes = lynx3d_table[config >> 6] * 1024 +
1453			512;
1454		    break;
1455		case SMI_LYNX3DM:
1456		    pSmi->videoRAMKBytes = lynx3dm_table[config >> 6] * 1024;
1457		    break;
1458		case SMI_COUGAR3DR:
1459		    /* DANGER - Cougar3DR BIOS is broken - hardcode video ram
1460		     * size per instructions from Silicon Motion engineers */
1461		    pSmi->videoRAMKBytes = 16 * 1024;
1462		    break;
1463		default:
1464		    pSmi->videoRAMKBytes = default_table[config >> 6] * 1024;
1465		    break;
1466	    }
1467	}
1468	from = X_PROBED;
1469    }
1470
1471    pSmi->videoRAMBytes = pSmi->videoRAMKBytes * 1024;
1472    pScrn->videoRam     = pSmi->videoRAMKBytes;
1473    xf86DrvMsg(pScrn->scrnIndex, from,
1474	       "videoram: %dkB\n", pSmi->videoRAMKBytes);
1475
1476    return (TRUE);
1477}
1478
1479Bool
1480SMI_MapMem(ScrnInfoPtr pScrn)
1481{
1482    SMIPtr pSmi = SMIPTR(pScrn);
1483    vgaHWPtr hwp;
1484
1485    ENTER();
1486
1487    if (pSmi->MapBase == NULL && SMI_MapMmio(pScrn) == FALSE)
1488	LEAVE(FALSE);
1489
1490    pScrn->memPhysBase = PCI_REGION_BASE(pSmi->PciInfo, 0, REGION_MEM);
1491
1492    if (pSmi->Chipset == SMI_LYNX3DM)
1493	pSmi->fbMapOffset = 0x200000;
1494    else
1495	pSmi->fbMapOffset = 0x0;
1496
1497#ifndef XSERVER_LIBPCIACCESS
1498    pSmi->FBBase = xf86MapPciMem(pScrn->scrnIndex,
1499				 VIDMEM_FRAMEBUFFER,
1500				 pSmi->PciTag,
1501				 pScrn->memPhysBase + pSmi->fbMapOffset,
1502				 pSmi->videoRAMBytes);
1503#else
1504    {
1505	void	**result = (void**)&pSmi->FBBase;
1506	int	  err = pci_device_map_range(pSmi->PciInfo,
1507					     pScrn->memPhysBase +
1508					     pSmi->fbMapOffset,
1509					     pSmi->videoRAMBytes,
1510					     PCI_DEV_MAP_FLAG_WRITABLE |
1511					     PCI_DEV_MAP_FLAG_WRITE_COMBINE,
1512					     result);
1513
1514	if (err)
1515	    LEAVE(FALSE);
1516    }
1517#endif
1518
1519    if (pSmi->FBBase == NULL) {
1520	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1521		   "Internal error: could not map framebuffer.\n");
1522	LEAVE(FALSE);
1523    }
1524
1525    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1526		   "Physical frame buffer at 0x%08lX offset: 0x%08lX\n",
1527		   pScrn->memPhysBase, pSmi->fbMapOffset);
1528    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1529		   "Logical frame buffer at %p - %p\n", pSmi->FBBase,
1530		   pSmi->FBBase + pSmi->videoRAMBytes - 1);
1531
1532    if (IS_MSOC(pSmi)) {
1533	/* Reserve space for panel cursr, and crt if in dual head mode */
1534#if SMI_CURSOR_ALPHA_PLANE
1535	pSmi->FBReserved = pSmi->FBCursorOffset = pSmi->videoRAMBytes -
1536	    (pSmi->Dualhead ? SMI501_CURSOR_SIZE << 1 : SMI501_ARGB_CURSOR_SIZE);
1537#else
1538	pSmi->FBReserved = pSmi->FBCursorOffset = pSmi->videoRAMBytes -
1539	    (pSmi->Dualhead ? SMI501_CURSOR_SIZE << 1 : SMI501_CURSOR_SIZE);
1540
1541# if SMI501_CLI_DEBUG
1542	if (pSmi->useEXA) {
1543	    pSmi->batch_active = FALSE;
1544	    pSmi->batch_length = 4096;
1545	    pSmi->FBReserved -= pSmi->batch_length << 3;
1546	    pSmi->batch_offset = pSmi->FBReserved;
1547	    pSmi->batch_handle = (int64_t *)(pSmi->FBBase + pSmi->batch_offset);
1548	    pSmi->batch_finish = -1;
1549	    pSmi->batch_index = 0;
1550	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1551		       "Using command list interpreter debug code\n");
1552	}
1553# endif
1554
1555#endif
1556    }
1557    else {
1558	/* Set up offset to hwcursor memory area, at the end of
1559	 * the frame buffer.
1560	 */
1561	pSmi->FBCursorOffset = pSmi->videoRAMBytes - SMILYNX_CURSOR_SIZE;
1562	/* set up the fifo reserved space */
1563	if (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x30) & 0x01)/* #1074 */ {
1564	    CARD32 fifoOffset = 0;
1565	    fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1566				       0x46) << 3;
1567	    fifoOffset |= VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1568				       0x47) << 11;
1569	    fifoOffset |= (VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA,
1570					0x49) & 0x1C) << 17;
1571	    pSmi->FBReserved = fifoOffset;	/* PDR#1074 */
1572	}
1573	else
1574	    pSmi->FBReserved = pSmi->videoRAMBytes - 2048;
1575
1576	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Cursor Offset: %08lX\n",
1577		   (unsigned long)pSmi->FBCursorOffset);
1578
1579	/* Assign hwp->MemBase & IOBase here */
1580	hwp = VGAHWPTR(pScrn);
1581	if (pSmi->IOBase != NULL)
1582	    vgaHWSetMmioFuncs(hwp, pSmi->MapBase, pSmi->IOBase - pSmi->MapBase);
1583	vgaHWGetIOBase(hwp);
1584
1585	/* Map the VGA memory when the primary video */
1586	if (xf86IsPrimaryPci(pSmi->PciInfo)) {
1587	    hwp->MapSize = 0x10000;
1588	    if (!vgaHWMapMem(pScrn))
1589		LEAVE(FALSE);
1590	    pSmi->PrimaryVidMapped = TRUE;
1591	}
1592    }
1593
1594    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reserved: %08lX\n",
1595	       (unsigned long)pSmi->FBReserved);
1596
1597    LEAVE(TRUE);
1598}
1599
1600/* UnMapMem - contains half of pre-4.0 EnterLeave function.  The EnterLeave
1601 * function which en/disable access to IO ports and ext. regs
1602 */
1603
1604void
1605SMI_UnmapMem(ScrnInfoPtr pScrn)
1606{
1607    SMIPtr pSmi = SMIPTR(pScrn);
1608
1609    ENTER();
1610
1611    /* Unmap VGA mem if mapped. */
1612    if (pSmi->PrimaryVidMapped) {
1613	vgaHWUnmapMem(pScrn);
1614	pSmi->PrimaryVidMapped = FALSE;
1615    }
1616
1617    SMI_DisableMmio(pScrn);
1618
1619    if (pSmi->MapBase) {
1620#ifndef XSERVER_LIBPCIACCESS
1621	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pSmi->MapBase,
1622			pSmi->MapSize);
1623#else
1624	pci_device_unmap_range(pSmi->PciInfo, (pointer)pSmi->MapBase,
1625			       pSmi->MapSize);
1626#endif
1627	pSmi->MapBase = NULL;
1628    }
1629
1630    if (pSmi->FBBase) {
1631#ifndef XSERVER_LIBPCIACCESS
1632	xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pSmi->FBBase,
1633			pSmi->videoRAMBytes);
1634#else
1635	pci_device_unmap_range(pSmi->PciInfo, (pointer)pSmi->FBBase,
1636			       pSmi->videoRAMBytes);
1637#endif
1638	pSmi->FBBase = NULL;
1639    }
1640
1641    LEAVE();
1642}
1643
1644/* This gets called at the start of each server generation. */
1645
1646static Bool
1647SMI_ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
1648{
1649    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1650    SMIPtr		pSmi = SMIPTR(pScrn);
1651    EntityInfoPtr	pEnt;
1652
1653    ENTER();
1654
1655    /* Map MMIO regs and framebuffer */
1656    if (!SMI_MapMem(pScrn))
1657	LEAVE(FALSE);
1658
1659    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
1660
1661    if (!pSmi->pInt10 && pSmi->useBIOS) {
1662	pSmi->pInt10 = xf86InitInt10(pEnt->index);
1663    }
1664    if (!pSmi->pVbe && pSmi->pInt10 && xf86LoaderCheckSymbol("VBEInit")) {
1665	pSmi->pVbe = VBEInit(pSmi->pInt10, pEnt->index);
1666    }
1667
1668    /* Save the chip/graphics state */
1669    pSmi->Save(pScrn);
1670
1671    /* Fill in some needed pScrn fields */
1672    pScrn->vtSema = TRUE;
1673    pScrn->pScreen = pScreen;
1674
1675    pSmi->Bpp = pScrn->bitsPerPixel >> 3;
1676    pScrn->displayWidth = ((pScrn->virtualX * pSmi->Bpp + 15) & ~15) / pSmi->Bpp;
1677
1678    pSmi->fbArea = NULL;
1679    pSmi->FBOffset = 0;
1680    pScrn->fbOffset = pSmi->FBOffset + pSmi->fbMapOffset;
1681
1682    /* Clear frame buffer */
1683    memset(pSmi->FBBase, 0, pSmi->videoRAMBytes);
1684
1685    /*
1686     * The next step is to setup the screen's visuals, and initialise the
1687     * framebuffer code.  In cases where the framebuffer's default choises for
1688     * things like visual layouts and bits per RGB are OK, this may be as simple
1689     * as calling the framebuffer's ScreenInit() function.  If not, the visuals
1690     * will need to be setup before calling a fb ScreenInit() function and fixed
1691     * up after.
1692     */
1693
1694    /*
1695     * Reset the visual list.
1696     */
1697    miClearVisualTypes();
1698
1699    /* Setup the visuals we support. */
1700
1701    if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
1702			  pScrn->rgbBits, pScrn->defaultVisual))
1703	LEAVE(FALSE);
1704
1705    if (!miSetPixmapDepths ())
1706	LEAVE(FALSE);
1707
1708    /*
1709     * Call the framebuffer layer's ScreenInit function
1710     */
1711
1712    DEBUG("\tInitializing FB @ 0x%08X for %dx%d (%d)\n",
1713	  pSmi->FBBase, pScrn->virtualX, pScrn->virtualY, pScrn->displayWidth);
1714    if(!fbScreenInit(pScreen, pSmi->FBBase, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi,
1715		     pScrn->yDpi, pScrn->displayWidth, pScrn->bitsPerPixel))
1716	LEAVE(FALSE);
1717
1718    xf86SetBlackWhitePixels(pScreen);
1719
1720    if (pScrn->bitsPerPixel > 8) {
1721	VisualPtr visual;
1722	/* Fixup RGB ordering */
1723	visual = pScreen->visuals + pScreen->numVisuals;
1724	while (--visual >= pScreen->visuals) {
1725	    if ((visual->class | DynamicClass) == DirectColor) {
1726		visual->offsetRed   = pScrn->offset.red;
1727		visual->offsetGreen = pScrn->offset.green;
1728		visual->offsetBlue  = pScrn->offset.blue;
1729		visual->redMask     = pScrn->mask.red;
1730		visual->greenMask   = pScrn->mask.green;
1731		visual->blueMask    = pScrn->mask.blue;
1732	    }
1733	}
1734    }
1735
1736    /* must be after RGB ordering fixed */
1737    fbPictureInit(pScreen, 0, 0);
1738
1739    /* Do the CRTC independent initialization */
1740    if(!SMI_HWInit(pScrn))
1741	LEAVE(FALSE);
1742
1743    /* Unless using EXA, regardless or using XAA or not, needs offscreen
1744     * management at least for video. */
1745    if (pSmi->NoAccel || !pSmi->useEXA) {
1746	int		numLines;
1747	BoxRec		AvailFBArea;
1748
1749	numLines = pSmi->FBReserved / (pScrn->displayWidth * pSmi->Bpp);
1750	AvailFBArea.x1 = 0;
1751	AvailFBArea.y1 = 0;
1752	AvailFBArea.x2 = pScrn->virtualX;
1753	AvailFBArea.y2 = numLines;
1754
1755	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1756		   "FrameBuffer Box: %d,%d - %d,%d\n",
1757		   AvailFBArea.x1, AvailFBArea.y1, AvailFBArea.x2,
1758		   AvailFBArea.y2);
1759
1760	xf86InitFBManager(pScreen, &AvailFBArea);
1761    }
1762
1763    /* Initialize acceleration layer */
1764    if (!pSmi->NoAccel) {
1765	if (pSmi->useEXA && !SMI_EXAInit(pScreen))
1766	    LEAVE(FALSE);
1767	else if (!pSmi->useEXA && !SMI_XAAInit(pScreen))
1768	    LEAVE(FALSE);
1769    }
1770
1771    /* Initialize the chosen modes */
1772    if (!xf86SetDesiredModes(pScrn))
1773	    LEAVE(FALSE);
1774
1775    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
1776		   "Done writing mode.  Register dump:\n");
1777    SMI_PrintRegs(pScrn);
1778
1779    miInitializeBackingStore(pScreen);
1780
1781#ifdef HAVE_XMODES
1782    xf86DiDGAInit(pScreen, (unsigned long)(pSmi->FBBase + pScrn->fbOffset));
1783#endif
1784
1785    /* Initialise cursor functions */
1786    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1787
1788    /* Initialize HW cursor layer.  Must follow software cursor
1789     * initialization.
1790     */
1791    if (pSmi->HwCursor) {
1792	int	size, flags;
1793
1794	if (IS_MSOC(pSmi)) {
1795	    size = SMI501_MAX_CURSOR;
1796	    flags = (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
1797		     HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK);
1798#if SMI_CURSOR_ALPHA_PLANE
1799	    if (!pSmi->Dualhead)
1800		flags |= HARDWARE_CURSOR_ARGB;
1801#endif
1802	}
1803	else {
1804	    size = SMILYNX_MAX_CURSOR;
1805	    flags = (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 |
1806		     HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
1807		     HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
1808		     HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
1809		     HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
1810		     HARDWARE_CURSOR_INVERT_MASK);
1811	}
1812
1813	if (!xf86_cursors_init(pScreen, size, size, flags))
1814	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1815		       "Hardware cursor initialization failed\n");
1816    }
1817
1818    /* Initialise default colormap */
1819    if (!miCreateDefColormap(pScreen))
1820	LEAVE(FALSE);
1821
1822    /* Initialize colormap layer.  Must follow initialization of the default
1823     * colormap.  And SetGamma call, else it will load palette with solid white.
1824     */
1825    if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits,SMI_LoadPalette, NULL,
1826			     CMAP_RELOAD_ON_MODE_SWITCH | CMAP_PALETTED_TRUECOLOR))
1827	LEAVE(FALSE);
1828
1829    pScreen->SaveScreen = SMI_SaveScreen;
1830    pSmi->CloseScreen = pScreen->CloseScreen;
1831    pScreen->CloseScreen = SMI_CloseScreen;
1832
1833    if ((IS_MSOC(pSmi) &&
1834	 !xf86DPMSInit(pScreen, SMI501_DisplayPowerManagementSet, 0)) ||
1835	(!IS_MSOC(pSmi) &&
1836	 !xf86DPMSInit(pScreen, SMILynx_DisplayPowerManagementSet, 0)))
1837	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n");
1838
1839    SMI_InitVideo(pScreen);
1840
1841    if(!xf86CrtcScreenInit(pScreen))
1842	LEAVE(FALSE);
1843
1844    /* Report any unused options (only for the first generation) */
1845    if (serverGeneration == 1) {
1846	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1847    }
1848
1849    LEAVE(TRUE);
1850}
1851
1852/*
1853 * This is called at the end of each server generation.  It restores the
1854 * original (text) mode.  It should also unmap the video memory, and free any
1855 * per-generation data allocated by the driver.  It should finish by unwrapping
1856 * and calling the saved CloseScreen function.
1857 */
1858
1859static Bool
1860SMI_CloseScreen(int scrnIndex, ScreenPtr pScreen)
1861{
1862    ScrnInfoPtr	pScrn = xf86Screens[scrnIndex];
1863    SMIPtr	pSmi = SMIPTR(pScrn);
1864    Bool	ret;
1865
1866    ENTER();
1867
1868    if (pSmi->HwCursor)
1869	xf86_cursors_fini(pScreen);
1870
1871    if (pScrn->vtSema)
1872	/* Restore console mode and unmap framebuffer */
1873	SMI_LeaveVT(scrnIndex, 0);
1874
1875    if (pSmi->XAAInfoRec != NULL) {
1876	XAADestroyInfoRec(pSmi->XAAInfoRec);
1877    }
1878    if (pSmi->EXADriverPtr) {
1879	exaDriverFini(pScreen);
1880	pSmi->EXADriverPtr = NULL;
1881    }
1882    if (pSmi->pVbe != NULL) {
1883	vbeFree(pSmi->pVbe);
1884	pSmi->pVbe = NULL;
1885    }
1886    if (pSmi->pInt10 != NULL) {
1887	xf86FreeInt10(pSmi->pInt10);
1888	pSmi->pInt10 = NULL;
1889    }
1890    if (pSmi->ptrAdaptor != NULL) {
1891	xfree(pSmi->ptrAdaptor);
1892    }
1893    if (pSmi->BlockHandler != NULL) {
1894	pScreen->BlockHandler = pSmi->BlockHandler;
1895    }
1896
1897    pScrn->vtSema = FALSE;
1898    pScreen->CloseScreen = pSmi->CloseScreen;
1899    ret = (*pScreen->CloseScreen)(scrnIndex, pScreen);
1900
1901    LEAVE(ret);
1902}
1903
1904static void
1905SMI_FreeScreen(int scrnIndex, int flags)
1906{
1907    SMI_FreeRec(xf86Screens[scrnIndex]);
1908}
1909
1910static Bool
1911SMI_SaveScreen(ScreenPtr pScreen, int mode)
1912{
1913    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
1914
1915    ENTER();
1916
1917    if(xf86IsUnblank(mode)){
1918	pScrn->DPMSSet(pScrn, DPMSModeOn, 0);
1919    }else{
1920	pScrn->DPMSSet(pScrn, DPMSModeOff, 0);
1921    }
1922
1923    LEAVE(TRUE);
1924}
1925
1926void
1927SMI_AdjustFrame(int scrnIndex, int x, int y, int flags)
1928{
1929    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(xf86Screens[scrnIndex]);
1930    xf86CrtcPtr compat_crtc = crtcConf->output[crtcConf->compat_output]->crtc;
1931
1932    ENTER();
1933
1934    SMICRTC(compat_crtc)->adjust_frame(compat_crtc,x,y);
1935
1936    LEAVE();
1937}
1938
1939Bool
1940SMI_SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
1941{
1942    Bool ret;
1943    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1944    SMIPtr pSmi = SMIPTR(pScrn);
1945
1946    ENTER();
1947
1948    ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
1949
1950    if (!pSmi->NoAccel)
1951	SMI_EngineReset(pScrn);
1952
1953    LEAVE(ret);
1954}
1955
1956void
1957SMI_LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
1958		LOCO *colors, VisualPtr pVisual)
1959{
1960    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(pScrn);
1961    int crtc_idx,i,j;
1962
1963    ENTER();
1964
1965    if(pScrn->bitsPerPixel == 16){
1966	/* Expand the RGB 565 palette into the 256-elements LUT */
1967
1968	for(crtc_idx=0; crtc_idx<crtcConf->num_crtc; crtc_idx++){
1969	    SMICrtcPrivatePtr crtcPriv = SMICRTC(crtcConf->crtc[crtc_idx]);
1970
1971	    for(i=0; i<numColors; i++){
1972		int idx = indicies[i];
1973
1974		if(idx<32){
1975		    for(j=0; j<8; j++){
1976			crtcPriv->lut_r[idx*8 + j] = colors[idx].red << 8;
1977			crtcPriv->lut_b[idx*8 + j] = colors[idx].blue << 8;
1978		    }
1979		}
1980
1981		for(j=0; j<4; j++)
1982		    crtcPriv->lut_g[idx*4 + j] = colors[idx].green << 8;
1983	    }
1984
1985	    crtcPriv->load_lut(crtcConf->crtc[crtc_idx]);
1986    }
1987    }else{
1988	for(crtc_idx=0; crtc_idx<crtcConf->num_crtc; crtc_idx++){
1989	    SMICrtcPrivatePtr crtcPriv = SMICRTC(crtcConf->crtc[crtc_idx]);
1990
1991    for(i = 0; i < numColors; i++) {
1992		int idx = indicies[i];
1993
1994		crtcPriv->lut_r[idx] = colors[idx].red << 8;
1995		crtcPriv->lut_g[idx] = colors[idx].green << 8;
1996		crtcPriv->lut_b[idx] = colors[idx].blue << 8;
1997	    }
1998
1999	    crtcPriv->load_lut(crtcConf->crtc[crtc_idx]);
2000	}
2001    }
2002
2003    LEAVE();
2004}
2005
2006static void
2007SMI_DisableVideo(ScrnInfoPtr pScrn)
2008{
2009    SMIPtr pSmi = SMIPTR(pScrn);
2010    CARD8 tmp;
2011
2012    if (!IS_MSOC(pSmi)) {
2013	if (!(tmp = VGAIN8(pSmi, VGA_DAC_MASK)))
2014	    return;
2015	pSmi->DACmask = tmp;
2016	VGAOUT8(pSmi, VGA_DAC_MASK, 0);
2017    }
2018}
2019
2020static void
2021SMI_EnableVideo(ScrnInfoPtr pScrn)
2022{
2023    SMIPtr pSmi = SMIPTR(pScrn);
2024
2025    if (!IS_MSOC(pSmi)) {
2026	VGAOUT8(pSmi, VGA_DAC_MASK, pSmi->DACmask);
2027    }
2028}
2029
2030
2031void
2032SMI_EnableMmio(ScrnInfoPtr pScrn)
2033{
2034    SMIPtr pSmi = SMIPTR(pScrn);
2035
2036    ENTER();
2037
2038    if (!IS_MSOC(pSmi)) {
2039	vgaHWPtr hwp = VGAHWPTR(pScrn);
2040	CARD8 tmp;
2041
2042	/*
2043	 * Enable chipset (seen on uninitialized secondary cards) might not be
2044	 * needed once we use the VGA softbooter
2045	 */
2046	vgaHWSetStdFuncs(hwp);
2047
2048	/* Enable linear mode */
2049	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
2050	tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
2051	pSmi->SR18Value = tmp;					/* PDR#521 */
2052	outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x11);
2053
2054	/* Enable 2D/3D Engine and Video Processor */
2055	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
2056	tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
2057	pSmi->SR21Value = tmp;					/* PDR#521 */
2058	outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp & ~0x03);
2059    }
2060
2061    LEAVE();
2062}
2063
2064void
2065SMI_DisableMmio(ScrnInfoPtr pScrn)
2066{
2067    SMIPtr pSmi = SMIPTR(pScrn);
2068
2069    ENTER();
2070
2071    if (!IS_MSOC(pSmi)) {
2072	vgaHWPtr hwp = VGAHWPTR(pScrn);
2073
2074	vgaHWSetStdFuncs(hwp);
2075
2076	/* Disable 2D/3D Engine and Video Processor */
2077	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
2078	outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR21Value);	/* PDR#521 */
2079
2080	/* Disable linear mode */
2081	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
2082	outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR18Value);	/* PDR#521 */
2083    }
2084
2085    LEAVE();
2086}
2087
2088static void
2089SMI_ProbeDDC(ScrnInfoPtr pScrn, int index)
2090{
2091    vbeInfoPtr pVbe;
2092    if (xf86LoadSubModule(pScrn, "vbe")) {
2093	pVbe = VBEInit(NULL, index);
2094	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
2095	vbeFree(pVbe);
2096    }
2097}
2098
2099static Bool
2100SMI_HWInit(ScrnInfoPtr pScrn)
2101{
2102    SMIPtr pSmi = SMIPTR(pScrn);
2103
2104    ENTER();
2105
2106    if(IS_MSOC(pSmi))
2107	LEAVE(SMI501_HWInit(pScrn));
2108    else
2109	LEAVE(SMILynx_HWInit(pScrn));
2110}
2111
2112void
2113SMI_PrintRegs(ScrnInfoPtr pScrn)
2114{
2115    SMIPtr pSmi = SMIPTR(pScrn);
2116    int i;
2117
2118    ENTER();
2119
2120    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
2121		"START register dump ------------------\n");
2122
2123    if(IS_MSOC(pSmi))
2124	SMI501_PrintRegs(pScrn);
2125    else
2126	SMILynx_PrintRegs(pScrn);
2127
2128
2129    xf86ErrorFVerb(VERBLEV, "\n\nDPR    x0       x4       x8       xC");
2130    for (i = 0x00; i <= 0x44; i += 4) {
2131	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2132	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_DPR(pSmi, i));
2133    }
2134
2135    xf86ErrorFVerb(VERBLEV, "\n\nVPR    x0       x4       x8       xC");
2136    for (i = 0x00; i <= 0x60; i += 4) {
2137	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2138	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_VPR(pSmi, i));
2139    }
2140
2141    xf86ErrorFVerb(VERBLEV, "\n\nCPR    x0       x4       x8       xC");
2142    for (i = 0x00; i <= 0x18; i += 4) {
2143	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2144	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_CPR(pSmi, i));
2145    }
2146
2147    xf86ErrorFVerb(VERBLEV, "\n\n");
2148    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
2149		"END register dump --------------------\n");
2150
2151    LEAVE();
2152}
2153