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