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