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