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