smi_driver.c revision 621ff18c
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    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    SMIPtr pSmi = SMIPTR(pScrn);
2014
2015    ENTER();
2016
2017    if (!IS_MSOC(pSmi)) {
2018	vgaHWPtr hwp = VGAHWPTR(pScrn);
2019	CARD8 tmp;
2020
2021	/*
2022	 * Enable chipset (seen on uninitialized secondary cards) might not be
2023	 * needed once we use the VGA softbooter
2024	 */
2025	vgaHWSetStdFuncs(hwp);
2026
2027	/* Enable linear mode */
2028	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
2029	tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
2030	pSmi->SR18Value = tmp;					/* PDR#521 */
2031	outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x11);
2032
2033	/* Enable 2D/3D Engine and Video Processor */
2034	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
2035	tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
2036	pSmi->SR21Value = tmp;					/* PDR#521 */
2037	outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp & ~0x03);
2038    }
2039
2040    LEAVE();
2041}
2042
2043void
2044SMI_DisableMmio(ScrnInfoPtr pScrn)
2045{
2046    SMIPtr pSmi = SMIPTR(pScrn);
2047
2048    ENTER();
2049
2050    if (!IS_MSOC(pSmi)) {
2051	vgaHWPtr hwp = VGAHWPTR(pScrn);
2052
2053	vgaHWSetStdFuncs(hwp);
2054
2055	/* Disable 2D/3D Engine and Video Processor */
2056	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x21);
2057	outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR21Value);	/* PDR#521 */
2058
2059	/* Disable linear mode */
2060	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
2061	outb(pSmi->PIOBase + VGA_SEQ_DATA, pSmi->SR18Value);	/* PDR#521 */
2062    }
2063
2064    LEAVE();
2065}
2066
2067static void
2068SMI_ProbeDDC(ScrnInfoPtr pScrn, int index)
2069{
2070    vbeInfoPtr pVbe;
2071    if (xf86LoadSubModule(pScrn, "vbe")) {
2072	pVbe = VBEInit(NULL, index);
2073	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
2074	vbeFree(pVbe);
2075    }
2076}
2077
2078static Bool
2079SMI_HWInit(ScrnInfoPtr pScrn)
2080{
2081    SMIPtr pSmi = SMIPTR(pScrn);
2082
2083    ENTER();
2084
2085    if(IS_MSOC(pSmi))
2086	LEAVE(SMI501_HWInit(pScrn));
2087    else
2088	LEAVE(SMILynx_HWInit(pScrn));
2089}
2090
2091void
2092SMI_PrintRegs(ScrnInfoPtr pScrn)
2093{
2094    SMIPtr pSmi = SMIPTR(pScrn);
2095    int i;
2096
2097    ENTER();
2098
2099    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
2100		"START register dump ------------------\n");
2101
2102    if(IS_MSOC(pSmi))
2103	SMI501_PrintRegs(pScrn);
2104    else
2105	SMILynx_PrintRegs(pScrn);
2106
2107
2108    xf86ErrorFVerb(VERBLEV, "\n\nDPR    x0       x4       x8       xC");
2109    for (i = 0x00; i <= 0x44; i += 4) {
2110	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2111	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_DPR(pSmi, i));
2112    }
2113
2114    xf86ErrorFVerb(VERBLEV, "\n\nVPR    x0       x4       x8       xC");
2115    for (i = 0x00; i <= 0x60; i += 4) {
2116	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2117	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_VPR(pSmi, i));
2118    }
2119
2120    xf86ErrorFVerb(VERBLEV, "\n\nCPR    x0       x4       x8       xC");
2121    for (i = 0x00; i <= 0x18; i += 4) {
2122	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
2123	xf86ErrorFVerb(VERBLEV, " %08lX", (unsigned long)READ_CPR(pSmi, i));
2124    }
2125
2126    xf86ErrorFVerb(VERBLEV, "\n\n");
2127    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
2128		"END register dump --------------------\n");
2129
2130    LEAVE();
2131}
2132