smi_driver.c revision 5788ca14
1/* Header:   //Mercury/Projects/archives/XFree86/4.0/smi_driver.c-arc   1.42   03 Jan 2001 13:52:16   Frido  $ */
2
3/*
4Copyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
5Copyright (C) 2000 Silicon Motion, Inc.  All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of
8this software and associated documentation files (the "Software"), to deal in
9the Software without restriction, including without limitation the rights to
10use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11of the Software, and to permit persons to whom the Software is furnished to do
12so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
19NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the names of The XFree86 Project and
25Silicon Motion shall not be used in advertising or otherwise to promote the
26sale, use or other dealings in this Software without prior written
27authorization from The XFree86 Project or Silicon Motion.
28*/
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include "xf86.h"
35#include "xf86DDC.h"
36#include "xf86int10.h"
37#include "vbe.h"
38
39#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
40#include "xf86Resources.h"
41#include "xf86RAC.h"
42#endif
43
44#include "smi.h"
45#include "smi_501.h"
46#include "smilynx.h"
47#include "smi_crtc.h"
48
49#include "globals.h"
50#ifdef HAVE_XEXTPROTO_71
51#include <X11/extensions/dpmsconst.h>
52#else
53#define DPMS_SERVER
54#include <X11/extensions/dpms.h>
55#endif
56
57
58/*
59 * Internals
60 */
61static Bool SMI_MapMmio(ScrnInfoPtr pScrn);
62static Bool SMI_DetectMem(ScrnInfoPtr pScrn);
63static void SMI_EnableMmio(ScrnInfoPtr pScrn);
64static void SMI_DisableMmio(ScrnInfoPtr pScrn);
65static Bool SMI_HWInit(ScrnInfoPtr pScrn);
66
67/*
68 * Forward definitions for the functions that make up the driver.
69 */
70
71static const OptionInfoRec * SMI_AvailableOptions(int chipid, int busid);
72static void SMI_Identify(int flags);
73static Bool SMI_Probe(DriverPtr drv, int flags);
74static Bool SMI_PreInit(ScrnInfoPtr pScrn, int flags);
75static Bool SMI_EnterVT(VT_FUNC_ARGS_DECL);
76static void SMI_LeaveVT(VT_FUNC_ARGS_DECL);
77static Bool SMI_ScreenInit(SCREEN_INIT_ARGS_DECL);
78static void SMI_DisableVideo(ScrnInfoPtr pScrn);
79static void SMI_EnableVideo(ScrnInfoPtr pScrn);
80static Bool SMI_CloseScreen(CLOSE_SCREEN_ARGS_DECL);
81static Bool SMI_SaveScreen(ScreenPtr pScreen, int mode);
82static void SMI_FreeScreen(FREE_SCREEN_ARGS_DECL);
83static void SMI_ProbeDDC(ScrnInfoPtr pScrn, int index);
84static void SMI_DetectPanelSize(ScrnInfoPtr pScrn);
85static void SMI_DetectMCLK(ScrnInfoPtr pScrn);
86
87/*
88 * xf86VDrvMsgVerb prints up to 14 characters prefix, where prefix has the
89 * format "%s(%d): " so, use name "SMI" instead of "Silicon Motion"
90 */
91#define SILICONMOTION_NAME          "SMI"
92#define SILICONMOTION_DRIVER_NAME   "siliconmotion"
93#define SILICONMOTION_VERSION_NAME  PACKAGE_VERSION
94#define SILICONMOTION_VERSION_MAJOR PACKAGE_VERSION_MAJOR
95#define SILICONMOTION_VERSION_MINOR PACKAGE_VERSION_MINOR
96#define SILICONMOTION_PATCHLEVEL    PACKAGE_VERSION_PATCHLEVEL
97#define SILICONMOTION_DRIVER_VERSION ((SILICONMOTION_VERSION_MAJOR << 24) | \
98                                      (SILICONMOTION_VERSION_MINOR << 16) | \
99                                      (SILICONMOTION_PATCHLEVEL))
100
101#if SMI_DEBUG
102int smi_indent = 1;
103#endif
104
105/* for dualhead */
106int gSMIEntityIndex = -1;
107
108/*
109 * This contains the functions needed by the server after loading the
110 * driver module.  It must be supplied, and gets added the driver list by
111 * the Module Setup funtion in the dynamic case.  In the static case a
112 * reference to this is compiled in, and this requires that the name of
113 * this DriverRec be an upper-case version of the driver name.
114 */
115
116_X_EXPORT DriverRec SILICONMOTION =
117{
118    SILICONMOTION_DRIVER_VERSION,
119    SILICONMOTION_DRIVER_NAME,
120    SMI_Identify,
121    SMI_Probe,
122    SMI_AvailableOptions,
123    NULL,
124    0
125};
126
127/* Supported chipsets */
128static SymTabRec SMIChipsets[] =
129{
130    { PCI_CHIP_SMI910, "Lynx"    },
131    { PCI_CHIP_SMI810, "LynxE"   },
132    { PCI_CHIP_SMI820, "Lynx3D"  },
133    { PCI_CHIP_SMI710, "LynxEM"  },
134    { PCI_CHIP_SMI712, "LynxEM+" },
135    { PCI_CHIP_SMI720, "Lynx3DM" },
136    { PCI_CHIP_SMI731, "Cougar3DR" },
137    { PCI_CHIP_SMI501, "MSOC"	 },
138    { -1,             NULL      }
139};
140
141static PciChipsets SMIPciChipsets[] =
142{
143    /* numChipset,	PciID,			Resource */
144    { PCI_CHIP_SMI910,	PCI_CHIP_SMI910,	RES_SHARED_VGA },
145    { PCI_CHIP_SMI810,	PCI_CHIP_SMI810,	RES_SHARED_VGA },
146    { PCI_CHIP_SMI820,	PCI_CHIP_SMI820,	RES_SHARED_VGA },
147    { PCI_CHIP_SMI710,	PCI_CHIP_SMI710,	RES_SHARED_VGA },
148    { PCI_CHIP_SMI712,	PCI_CHIP_SMI712,	RES_SHARED_VGA },
149    { PCI_CHIP_SMI720,	PCI_CHIP_SMI720,	RES_SHARED_VGA },
150    { PCI_CHIP_SMI731,	PCI_CHIP_SMI731,	RES_SHARED_VGA },
151    { PCI_CHIP_SMI501,	PCI_CHIP_SMI501,	RES_UNDEFINED  },
152    { -1,		-1,			RES_UNDEFINED  }
153};
154
155typedef enum
156{
157    OPTION_PCI_BURST,
158    OPTION_PCI_RETRY,
159    OPTION_NOACCEL,
160    OPTION_MCLK,
161    OPTION_MXCLK,
162    OPTION_SWCURSOR,
163    OPTION_HWCURSOR,
164    OPTION_VIDEOKEY,
165    OPTION_BYTESWAP,
166    /* CZ 26.10.2001: interlaced video */
167    OPTION_INTERLACED,
168    /* end CZ */
169    OPTION_USEBIOS,
170    OPTION_DUALHEAD,
171    OPTION_ACCELMETHOD,
172    OPTION_PANEL_SIZE,
173    OPTION_USE_FBDEV,
174    OPTION_CSCVIDEO,
175    NUMBER_OF_OPTIONS
176} SMIOpts;
177
178static const OptionInfoRec SMIOptions[] =
179{
180    { OPTION_PCI_BURST,	     "pci_burst",	  OPTV_BOOLEAN, {0}, TRUE },
181    { OPTION_PCI_RETRY,	     "pci_retry",	  OPTV_BOOLEAN, {0}, TRUE },
182    { OPTION_NOACCEL,	     "NoAccel",		  OPTV_BOOLEAN, {0}, FALSE },
183    { OPTION_MCLK,	     "MCLK",		  OPTV_FREQ,	{0}, FALSE },
184    { OPTION_MXCLK,	     "MXCLK",		  OPTV_FREQ,	{0}, FALSE },
185    { OPTION_HWCURSOR,	     "HWCursor",	  OPTV_BOOLEAN, {0}, TRUE },
186    { OPTION_SWCURSOR,	     "SWCursor",	  OPTV_BOOLEAN, {0}, FALSE },
187    { OPTION_VIDEOKEY,	     "VideoKey",	  OPTV_INTEGER, {0}, FALSE },
188    { OPTION_BYTESWAP,	     "ByteSwap",	  OPTV_BOOLEAN, {0}, FALSE },
189    /* CZ 26.10.2001: interlaced video */
190    { OPTION_INTERLACED,     "Interlaced",        OPTV_BOOLEAN, {0}, FALSE },
191    /* end CZ */
192    { OPTION_USEBIOS,	     "UseBIOS",		  OPTV_BOOLEAN,	{0}, FALSE },
193    { OPTION_DUALHEAD,	     "Dualhead",	  OPTV_BOOLEAN,	{0}, TRUE },
194    { OPTION_ACCELMETHOD,    "AccelMethod",       OPTV_STRING,  {0}, FALSE },
195    { OPTION_PANEL_SIZE,     "PanelSize",	  OPTV_ANYSTR,	{0}, FALSE },
196    { OPTION_USE_FBDEV,	     "UseFBDev",	  OPTV_BOOLEAN,	{0}, FALSE },
197    { OPTION_CSCVIDEO,	     "CSCVideo",	  OPTV_BOOLEAN, {0}, TRUE },
198    { -1,		     NULL,		  OPTV_NONE,	{0}, FALSE }
199};
200
201#ifdef XFree86LOADER
202
203static MODULESETUPPROTO(siliconmotionSetup);
204
205static XF86ModuleVersionInfo SMIVersRec =
206{
207    "siliconmotion",
208    MODULEVENDORSTRING,
209    MODINFOSTRING1,
210    MODINFOSTRING2,
211    XORG_VERSION_CURRENT,
212    SILICONMOTION_VERSION_MAJOR,
213    SILICONMOTION_VERSION_MINOR,
214    SILICONMOTION_PATCHLEVEL,
215    ABI_CLASS_VIDEODRV,
216    ABI_VIDEODRV_VERSION,
217    MOD_CLASS_VIDEODRV,
218    {0, 0, 0, 0}
219};
220
221/*
222 * This is the module init data for XFree86 modules.
223 *
224 * Its name has to be the driver name followed by ModuleData.
225 */
226_X_EXPORT XF86ModuleData siliconmotionModuleData =
227{
228    &SMIVersRec,
229    siliconmotionSetup,
230    NULL
231};
232
233static pointer
234siliconmotionSetup(pointer module, pointer opts, int *errmaj, int *errmin)
235{
236    static Bool setupDone = FALSE;
237
238    if (!setupDone) {
239	setupDone = TRUE;
240	xf86AddDriver(&SILICONMOTION, module, 0);
241
242	/*
243	 * The return value must be non-NULL on success even though there
244	 * is no TearDownProc.
245	 */
246	return (pointer) 1;
247
248    } else {
249	if (errmaj) {
250	    *errmaj = LDR_ONCEONLY;
251	}
252	return NULL;
253    }
254}
255
256#endif /* XFree86LOADER */
257
258static Bool
259SMI_GetRec(ScrnInfoPtr pScrn)
260{
261    ENTER();
262
263    /*
264     * Allocate an 'Chip'Rec, and hook it into pScrn->driverPrivate.
265     * pScrn->driverPrivate is initialised to NULL, so we can check if
266     * the allocation has already been done.
267     */
268    if (pScrn->driverPrivate == NULL) {
269	pScrn->driverPrivate = xnfcalloc(sizeof(SMIRec), 1);
270    }
271
272    LEAVE(TRUE);
273}
274
275static void
276SMI_FreeRec(ScrnInfoPtr pScrn)
277{
278    SMIPtr	pSmi = SMIPTR(pScrn);
279
280    ENTER();
281
282    if (pSmi) {
283	free(pSmi->save);
284	free(pSmi->mode);
285	free(pScrn->driverPrivate);
286	pScrn->driverPrivate = NULL;
287    }
288
289    LEAVE();
290}
291
292static const OptionInfoRec *
293SMI_AvailableOptions(int chipid, int busid)
294{
295    ENTER();
296
297    LEAVE(SMIOptions);
298}
299
300static void
301SMI_Identify(int flags)
302{
303    ENTER();
304
305    xf86PrintChipsets(SILICONMOTION_NAME, "driver (version "
306		SILICONMOTION_VERSION_NAME ") for Silicon Motion Lynx chipsets",
307		SMIChipsets);
308
309    LEAVE();
310}
311
312static Bool
313SMI_Probe(DriverPtr drv, int flags)
314{
315    int i;
316    GDevPtr *devSections;
317    int *usedChips;
318    int numDevSections;
319    int numUsed;
320    Bool foundScreen = FALSE;
321
322    ENTER();
323
324    numDevSections = xf86MatchDevice(SILICONMOTION_DRIVER_NAME, &devSections);
325
326    if (numDevSections <= 0)
327	/* There's no matching device section in the config file, so quit now. */
328	LEAVE(FALSE);
329
330#ifndef XSERVER_LIBPCIACCESS
331    if (xf86GetPciVideoInfo() == NULL)
332	LEAVE(FALSE);
333#endif
334
335    numUsed = xf86MatchPciInstances(SILICONMOTION_NAME, PCI_SMI_VENDOR_ID,
336				    SMIChipsets, SMIPciChipsets, devSections,
337				    numDevSections, drv, &usedChips);
338
339    /* Free it since we don't need that list after this */
340    free(devSections);
341    if (numUsed <= 0)
342	LEAVE(FALSE);
343
344    if (flags & PROBE_DETECT)
345	foundScreen = TRUE;
346    else {
347	ScrnInfoPtr	pScrn;
348	EntityInfoPtr	pEnt;
349
350	for (i = 0; i < numUsed; i++) {
351	    if ((pScrn = xf86ConfigPciEntity(NULL, 0, usedChips[i],
352					     SMIPciChipsets, NULL,
353					     NULL, NULL, NULL, NULL))) {
354		pScrn->driverVersion = SILICONMOTION_DRIVER_VERSION;
355		pScrn->driverName    = SILICONMOTION_DRIVER_NAME;
356		pScrn->name	     = SILICONMOTION_NAME;
357		pScrn->Probe	     = SMI_Probe;
358		pScrn->PreInit	     = SMI_PreInit;
359		pScrn->ScreenInit    = SMI_ScreenInit;
360		pScrn->SwitchMode    = SMI_SwitchMode;
361		pScrn->AdjustFrame   = SMI_AdjustFrame;
362
363		if ((pEnt = xf86GetEntityInfo(usedChips[i]))) {
364			pScrn->EnterVT   = SMI_EnterVT;
365			pScrn->LeaveVT   = SMI_LeaveVT;
366		    free(pEnt);
367		}
368		pScrn->FreeScreen    = SMI_FreeScreen;
369		foundScreen	     = TRUE;
370	    }
371	}
372    }
373    free(usedChips);
374
375    LEAVE(foundScreen);
376}
377
378static Bool
379SMI_PreInit(ScrnInfoPtr pScrn, int flags)
380{
381    EntityInfoPtr pEnt;
382    SMIPtr pSmi;
383    MessageType from;
384    vgaHWPtr hwp;
385
386    ENTER();
387
388    /* Ignoring the Type list for now.  It might be needed when multiple cards
389     * are supported.
390     */
391    if (pScrn->numEntities > 1)
392	LEAVE(FALSE);
393
394    /* Allocate the SMIRec driverPrivate */
395    if (!SMI_GetRec(pScrn))
396	LEAVE(FALSE);
397    pSmi = SMIPTR(pScrn);
398
399    /* Find the PCI slot for this screen */
400    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
401
402    pSmi->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
403    pSmi->Chipset = PCI_DEV_DEVICE_ID(pSmi->PciInfo);
404
405    if (IS_MSOC(pSmi)) {
406	pSmi->Save = SMI501_Save;
407	pSmi->save = xnfcalloc(sizeof(MSOCRegRec), 1);
408	pSmi->mode = xnfcalloc(sizeof(MSOCRegRec), 1);
409    }
410    else {
411	pSmi->Save = SMILynx_Save;
412	pSmi->save = xnfcalloc(sizeof(SMIRegRec), 1);
413	pSmi->mode = xnfcalloc(sizeof(SMIRegRec), 1);
414    }
415
416    if (flags & PROBE_DETECT) {
417	if (!IS_MSOC(pSmi))
418	    SMI_ProbeDDC(pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index);
419	LEAVE(TRUE);
420    }
421
422    if (pEnt->location.type != BUS_PCI) {
423	free(pEnt);
424	SMI_FreeRec(pScrn);
425	LEAVE(FALSE);
426    }
427    pSmi->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
428
429    /* Set pScrn->monitor */
430    pScrn->monitor = pScrn->confScreen->monitor;
431
432    if (!IS_MSOC(pSmi)) {
433	/* The vgahw module should be loaded here when needed */
434	if (!xf86LoadSubModule(pScrn, "vgahw"))
435	    LEAVE(FALSE);
436
437	/*
438	 * Allocate a vgaHWRec
439	 */
440	if (!vgaHWGetHWRec(pScrn))
441	    LEAVE(FALSE);
442
443	hwp = VGAHWPTR(pScrn);
444	vgaHWSetStdFuncs(hwp);
445#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
446	pSmi->PIOBase = hwp->PIOOffset;
447#else
448	pSmi->PIOBase = 0;
449#endif
450
451	xf86ErrorFVerb(VERBLEV, "\tSMI_PreInit vgaCRIndex=%x, vgaIOBase=%x, "
452		       "MMIOBase=%p\n", hwp->IOBase + VGA_CRTC_INDEX_OFFSET,
453		       hwp->IOBase, hwp->MMIOBase);
454    }
455
456    /*
457     * The first thing we should figure out is the depth, bpp, etc.
458     */
459    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
460	LEAVE(FALSE);
461
462    /* Check that the returned depth is one we support */
463    if (pScrn->depth != 8 && pScrn->depth != 16 && pScrn->depth != 24) {
464	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
465		   "Given depth (%d) is not supported by this driver\n",
466		   pScrn->depth);
467	LEAVE(FALSE);
468    }
469
470
471    if(pScrn->bitsPerPixel != 8 && pScrn->bitsPerPixel != 16 &&
472       pScrn->bitsPerPixel != 24 && pScrn->bitsPerPixel != 32){
473	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
474		   "Given bpp (%d) is not supported by this driver\n",
475		   pScrn->bitsPerPixel);
476	LEAVE(FALSE);
477    }
478
479    xf86PrintDepthBpp(pScrn);
480
481    pSmi->Bpp = pScrn->bitsPerPixel >> 3;
482
483    /*
484     * This must happen after pScrn->display has been set because
485     * xf86SetWeight references it.
486     */
487    if (pScrn->depth > 8) {
488	/* The defaults are OK for us */
489	rgb zeros = {0, 0, 0};
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	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    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    miInitializeBackingStore(pScreen);
1757
1758#ifdef HAVE_XMODES
1759    xf86DiDGAInit(pScreen, (unsigned long)(pSmi->FBBase + pScrn->fbOffset));
1760#endif
1761
1762    /* Initialise cursor functions */
1763    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1764
1765    /* Initialize HW cursor layer.  Must follow software cursor
1766     * initialization.
1767     */
1768    if (pSmi->HwCursor) {
1769	int	size, flags;
1770
1771	if (IS_MSOC(pSmi)) {
1772	    size = SMI501_MAX_CURSOR;
1773	    flags = (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
1774		     HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK);
1775#if SMI_CURSOR_ALPHA_PLANE
1776	    if (!pSmi->Dualhead)
1777		flags |= HARDWARE_CURSOR_ARGB;
1778#endif
1779	}
1780	else {
1781	    size = SMILYNX_MAX_CURSOR;
1782	    flags = (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 |
1783		     HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK |
1784		     HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
1785		     HARDWARE_CURSOR_BIT_ORDER_MSBFIRST |
1786		     HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
1787		     HARDWARE_CURSOR_INVERT_MASK);
1788	}
1789
1790	if (!xf86_cursors_init(pScreen, size, size, flags))
1791	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1792		       "Hardware cursor initialization failed\n");
1793    }
1794
1795    /* Initialise default colormap */
1796    if (!miCreateDefColormap(pScreen))
1797	LEAVE(FALSE);
1798
1799    /* Initialize colormap layer.  Must follow initialization of the default
1800     * colormap.  And SetGamma call, else it will load palette with solid white.
1801     */
1802    if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits,SMI_LoadPalette, NULL,
1803			     CMAP_RELOAD_ON_MODE_SWITCH | CMAP_PALETTED_TRUECOLOR))
1804	LEAVE(FALSE);
1805
1806    pScreen->SaveScreen = SMI_SaveScreen;
1807    pSmi->CloseScreen = pScreen->CloseScreen;
1808    pScreen->CloseScreen = SMI_CloseScreen;
1809
1810    if ((IS_MSOC(pSmi) &&
1811	 !xf86DPMSInit(pScreen, SMI501_DisplayPowerManagementSet, 0)) ||
1812	(!IS_MSOC(pSmi) &&
1813	 !xf86DPMSInit(pScreen, SMILynx_DisplayPowerManagementSet, 0)))
1814	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed!\n");
1815
1816    SMI_InitVideo(pScreen);
1817
1818    if(!xf86CrtcScreenInit(pScreen))
1819	LEAVE(FALSE);
1820
1821    /* Report any unused options (only for the first generation) */
1822    if (serverGeneration == 1) {
1823	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1824    }
1825
1826    LEAVE(TRUE);
1827}
1828
1829/*
1830 * This is called at the end of each server generation.  It restores the
1831 * original (text) mode.  It should also unmap the video memory, and free any
1832 * per-generation data allocated by the driver.  It should finish by unwrapping
1833 * and calling the saved CloseScreen function.
1834 */
1835
1836static Bool
1837SMI_CloseScreen(CLOSE_SCREEN_ARGS_DECL)
1838{
1839    ScrnInfoPtr	pScrn = xf86ScreenToScrn(pScreen);
1840    SMIPtr	pSmi = SMIPTR(pScrn);
1841    Bool	ret;
1842
1843    ENTER();
1844
1845    if (pSmi->HwCursor)
1846	xf86_cursors_fini(pScreen);
1847
1848    if (pScrn->vtSema)
1849	/* Restore console mode and unmap framebuffer */
1850        SMI_LeaveVT(VT_FUNC_ARGS);
1851
1852#ifdef HAVE_XAA_H
1853    if (pSmi->XAAInfoRec != NULL) {
1854	XAADestroyInfoRec(pSmi->XAAInfoRec);
1855    }
1856#endif
1857    if (pSmi->EXADriverPtr) {
1858	exaDriverFini(pScreen);
1859	pSmi->EXADriverPtr = NULL;
1860    }
1861    if (pSmi->pVbe != NULL) {
1862	vbeFree(pSmi->pVbe);
1863	pSmi->pVbe = NULL;
1864    }
1865    if (pSmi->pInt10 != NULL) {
1866	xf86FreeInt10(pSmi->pInt10);
1867	pSmi->pInt10 = NULL;
1868    }
1869    if (pSmi->ptrAdaptor != NULL) {
1870	free(pSmi->ptrAdaptor);
1871    }
1872    if (pSmi->BlockHandler != NULL) {
1873	pScreen->BlockHandler = pSmi->BlockHandler;
1874    }
1875
1876    pScrn->vtSema = FALSE;
1877    pScreen->CloseScreen = pSmi->CloseScreen;
1878    ret = (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
1879
1880    LEAVE(ret);
1881}
1882
1883static void
1884SMI_FreeScreen(FREE_SCREEN_ARGS_DECL)
1885{
1886    SCRN_INFO_PTR(arg);
1887    SMI_FreeRec(pScrn);
1888}
1889
1890static Bool
1891SMI_SaveScreen(ScreenPtr pScreen, int mode)
1892{
1893    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1894
1895    ENTER();
1896
1897    if(xf86IsUnblank(mode)){
1898	pScrn->DPMSSet(pScrn, DPMSModeOn, 0);
1899    }else{
1900	pScrn->DPMSSet(pScrn, DPMSModeOff, 0);
1901    }
1902
1903    LEAVE(TRUE);
1904}
1905
1906void
1907SMI_AdjustFrame(int scrnIndex, int x, int y, int flags)
1908{
1909    xf86CrtcConfigPtr crtcConf = XF86_CRTC_CONFIG_PTR(xf86Screens[scrnIndex]);
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(int scrnIndex, DisplayModePtr mode, int flags)
1921{
1922    Bool ret;
1923    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
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    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}
2043
2044void
2045SMI_DisableMmio(ScrnInfoPtr pScrn)
2046{
2047    SMIPtr pSmi = SMIPTR(pScrn);
2048
2049    ENTER();
2050
2051    if (!IS_MSOC(pSmi)) {
2052	vgaHWPtr hwp = VGAHWPTR(pScrn);
2053
2054	vgaHWSetStdFuncs(hwp);
2055
2056	/* Disable 2D/3D Engine and Video Processor */
2057	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
2058	outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR21Value);	/* PDR#521 */
2059
2060	/* Disable linear mode */
2061	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
2062	outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR18Value);	/* PDR#521 */
2063    }
2064
2065    LEAVE();
2066}
2067
2068static void
2069SMI_ProbeDDC(ScrnInfoPtr pScrn, int index)
2070{
2071    vbeInfoPtr pVbe;
2072    if (xf86LoadSubModule(pScrn, "vbe")) {
2073	pVbe = VBEInit(NULL, index);
2074	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
2075	vbeFree(pVbe);
2076    }
2077}
2078
2079static Bool
2080SMI_HWInit(ScrnInfoPtr pScrn)
2081{
2082    SMIPtr pSmi = SMIPTR(pScrn);
2083
2084    ENTER();
2085
2086    if(IS_MSOC(pSmi))
2087	LEAVE(SMI501_HWInit(pScrn));
2088    else
2089	LEAVE(SMILynx_HWInit(pScrn));
2090}
2091
2092void
2093SMI_PrintRegs(ScrnInfoPtr pScrn)
2094{
2095    SMIPtr pSmi = SMIPTR(pScrn);
2096    int i;
2097
2098    ENTER();
2099
2100    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
2101		"START register dump ------------------\n");
2102
2103    if(IS_MSOC(pSmi))
2104	SMI501_PrintRegs(pScrn);
2105    else
2106	SMILynx_PrintRegs(pScrn);
2107
2108
2109    xf86ErrorFVerb(VERBLEV, "\n\nDPR    x0       x4       x8       xC");
2110    for (i = 0x00; i <= 0x44; i += 4) {
2111	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2112	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_DPR(pSmi, i));
2113    }
2114
2115    xf86ErrorFVerb(VERBLEV, "\n\nVPR    x0       x4       x8       xC");
2116    for (i = 0x00; i <= 0x60; i += 4) {
2117	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2118	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_VPR(pSmi, i));
2119    }
2120
2121    xf86ErrorFVerb(VERBLEV, "\n\nCPR    x0       x4       x8       xC");
2122    for (i = 0x00; i <= 0x18; i += 4) {
2123	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2124	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_CPR(pSmi, i));
2125    }
2126
2127    xf86ErrorFVerb(VERBLEV, "\n\n");
2128    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
2129		"END register dump --------------------\n");
2130
2131    LEAVE();
2132}
2133