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