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