neo_driver.c revision c3c9db83
1/**********************************************************************
2Copyright 1998, 1999 by Precision Insight, Inc., Cedar Park, Texas.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, distribute, and sell this software and
7its documentation for any purpose is hereby granted without fee,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Precision Insight not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.  Precision Insight
13and its suppliers make no representations about the suitability of this
14software for any purpose.  It is provided "as is" without express or
15implied warranty.
16
17PRECISION INSIGHT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24**********************************************************************/
25
26/*
27 * Copyright 1998, 1999 Egbert Eich
28 * Copyright 2000, 2001 SuSE GmbH, Author: Egbert Eich
29 * Copyright 2002 SuSE Linux AG, Author: Egbert Eich
30 * Copyright 2002 Shigehiro Nomura
31 */
32
33
34/*
35 * The original Precision Insight driver for
36 * XFree86 v.3.3 has been sponsored by Red Hat.
37 *
38 * Authors:
39 *   Jens Owen (jens@tungstengraphics.com)
40 *   Kevin E. Martin (kevin@precisioninsight.com)
41 *
42 * Port to Xfree86 v.4.0
43 *   1998, 1999 by Egbert Eich (Egbert.Eich@Physik.TU-Darmstadt.DE)
44 */
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50/* All drivers should typically include these */
51#include "xf86.h"
52#include "xf86_OSproc.h"
53
54/* Everything using inb/outb, etc needs "compiler.h" */
55#include "compiler.h"
56
57#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
58#include "xf86Resources.h"
59/* Needed by Resources Access Control (RAC) */
60#include "xf86RAC.h"
61#endif
62
63/* Drivers for PCI hardware need this */
64#include "xf86PciInfo.h"
65
66/* Drivers that need to access the PCI config space directly need this */
67#include "xf86Pci.h"
68
69/* All drivers using the vgahw module need this */
70#include "vgaHW.h"
71
72/* All drivers initialising the SW cursor need this */
73#include "mipointer.h"
74
75/* All drivers implementing backing store need this */
76#include "mibstore.h"
77
78/* All drivers using the mi colormap manipulation need this */
79#include "micmap.h"
80
81#include "xf86cmap.h"
82
83#include "fb.h"
84
85/* int10 */
86#include "xf86int10.h"
87#include "vbe.h"
88
89/* Needed for Device Data Channel (DDC) support */
90#include "xf86DDC.h"
91
92#include "picturestr.h"
93
94#include "xf86xv.h"
95#include <X11/extensions/Xv.h>
96
97/*
98 * Driver data structures.
99 */
100#include "neo.h"
101#include "neo_reg.h"
102#include "neo_macros.h"
103
104/* These need to be checked */
105#include <X11/X.h>
106#include <X11/Xproto.h>
107#include "scrnintstr.h"
108#include "servermd.h"
109
110#include <unistd.h>
111
112/* Mandatory functions */
113static const OptionInfoRec *	NEOAvailableOptions(int chipid, int busid);
114static void     NEOIdentify(int flags);
115static Bool     NEOProbe(DriverPtr drv, int flags);
116static Bool     NEOPreInit(ScrnInfoPtr pScrn, int flags);
117static Bool     NEOScreenInit(int Index, ScreenPtr pScreen, int argc,
118                                  char **argv);
119static Bool     NEOEnterVT(int scrnIndex, int flags);
120static void     NEOLeaveVT(int scrnIndex, int flags);
121static Bool     NEOCloseScreen(int scrnIndex, ScreenPtr pScreen);
122static void     NEOFreeScreen(int scrnIndex, int flags);
123static ModeStatus NEOValidMode(int scrnIndex, DisplayModePtr mode,
124                               Bool verbose, int flags);
125
126/* Internally used functions */
127static int      neoFindIsaDevice(GDevPtr dev);
128static Bool     neoModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
129static void     neoSave(ScrnInfoPtr pScrn);
130static void     neoRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
131				 NeoRegPtr NeoReg, Bool restoreText);
132static void     neoLock(ScrnInfoPtr pScrn);
133static void     neoUnlock(ScrnInfoPtr pScrn);
134static Bool	neoMapMem(ScrnInfoPtr pScrn);
135static Bool	neoUnmapMem(ScrnInfoPtr pScrn);
136static void     neoProgramShadowRegs(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
137				     NeoRegPtr restore);
138static void     neoCalcVCLK(ScrnInfoPtr pScrn, long freq);
139static xf86MonPtr  neo_ddc1(int scrnIndex);
140static Bool     neoDoDDC1(ScrnInfoPtr pScrn);
141static Bool     neoDoDDC2(ScrnInfoPtr pScrn);
142static Bool     neoDoDDCVBE(ScrnInfoPtr pScrn);
143static void     neoProbeDDC(ScrnInfoPtr pScrn, int index);
144static void     NeoDisplayPowerManagementSet(ScrnInfoPtr pScrn,
145				int PowerManagementMode, int flags);
146static int      neoFindMode(int xres, int yres, int depth);
147
148#define NEO_VERSION 4000
149#define NEO_NAME "NEOMAGIC"
150#define NEO_DRIVER_NAME "neomagic"
151
152#define NEO_MAJOR_VERSION PACKAGE_VERSION_MAJOR
153#define NEO_MINOR_VERSION PACKAGE_VERSION_MINOR
154#define NEO_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL
155
156/*
157 * This is intentionally screen-independent.  It indicates the binding
158 * choice made in the first PreInit.
159 */
160static int pix24bpp = 0;
161
162
163static biosMode bios8[] = {
164    { 320, 240, 0x40 },
165    { 300, 400, 0x42 },
166    { 640, 400, 0x20 },
167    { 640, 480, 0x21 },
168    { 800, 600, 0x23 },
169    { 1024, 768, 0x25 }
170};
171
172static biosMode bios15[] = {
173    { 320, 200, 0x2D },
174    { 640, 480, 0x30 },
175    { 800, 600, 0x33 },
176    { 1024, 768, 0x36 }
177};
178
179static biosMode bios16[] = {
180    { 320, 200, 0x2e },
181    { 320, 240, 0x41 },
182    { 300, 400, 0x43 },
183    { 640, 480, 0x31 },
184    { 800, 600, 0x34 },
185    { 1024, 768, 0x37 }
186};
187
188static biosMode bios24[] = {
189    { 640, 480, 0x32 },
190    { 800, 600, 0x35 },
191    { 1024, 768, 0x38 }
192};
193
194static DisplayModeRec neo800x480Mode = {
195	NULL,           /* prev */
196	NULL,           /* next */
197	"800x480",      /* identifier of this mode */
198	MODE_OK,        /* mode status */
199	M_T_BUILTIN,    /* mode type */
200	35260,		/* Clock frequency */
201	800,		/* HDisplay */
202	856,		/* HSyncStart */
203	1040,		/* HSyncEnd */
204	1056,		/* HTotal */
205	0,		/* HSkew */
206	480,		/* VDisplay */
207	480,		/* VSyncStart */
208	486,		/* VSyncEnd */
209	488,		/* VTotal */
210	0,		/* VScan */
211	V_PHSYNC | V_PVSYNC,	/* Flags */
212	-1,		/* ClockIndex */
213	35260,		/* SynthClock */
214	800,		/* CRTC HDisplay */
215	800,            /* CRTC HBlankStart */
216	856,            /* CRTC HSyncStart */
217	1040,           /* CRTC HSyncEnd */
218	872,            /* CRTC HBlankEnd */
219	1048,           /* CRTC HTotal */
220	0,              /* CRTC HSkew */
221	480,		/* CRTC VDisplay */
222	480,		/* CRTC VBlankStart */
223	480,		/* CRTC VSyncStart */
224	486,		/* CRTC VSyncEnd */
225	487,		/* CRTC VBlankEnd */
226	488,		/* CRTC VTotal */
227	FALSE,		/* CrtcHAdjusted */
228	FALSE,		/* CrtcVAdjusted */
229	0,		/* PrivSize */
230	NULL,		/* Private */
231	0.0,		/* HSync */
232	0.0		/* VRefresh */
233};
234
235static DisplayModeRec neo1024x480Mode = {
236	NULL,           /* prev */
237	NULL,           /* next */
238	"1024x480",      /* identifier of this mode */
239	MODE_OK,        /* mode status */
240	M_T_BUILTIN,    /* mode type */
241	45900,		/* Clock frequency */
242	1024,		/* HDisplay */
243	1048,		/* HSyncStart */
244	1184,		/* HSyncEnd */
245	1344,		/* HTotal */
246	0,		/* HSkew */
247	480,		/* VDisplay */
248	480,		/* VSyncStart */
249	486,		/* VSyncEnd */
250	488,		/* VTotal */
251	0,		/* VScan */
252	V_PHSYNC | V_PVSYNC,	/* Flags */
253	-1,		/* ClockIndex */
254	45900,		/* SynthClock */
255	1024,		/* CRTC HDisplay */
256	1024,            /* CRTC HBlankStart */
257	1048,            /* CRTC HSyncStart */
258	1184,           /* CRTC HSyncEnd */
259	1072,            /* CRTC HBlankEnd */
260	1344,           /* CRTC HTotal */
261	0,              /* CRTC HSkew */
262	480,		/* CRTC VDisplay */
263	480,		/* CRTC VBlankStart */
264	480,		/* CRTC VSyncStart */
265	486,		/* CRTC VSyncEnd */
266	487,		/* CRTC VBlankEnd */
267	488,		/* CRTC VTotal */
268	FALSE,		/* CrtcHAdjusted */
269	FALSE,		/* CrtcVAdjusted */
270	0,		/* PrivSize */
271	NULL,		/* Private */
272	0.0,		/* HSync */
273	0.0		/* VRefresh */
274};
275
276/*
277 * This contains the functions needed by the server after loading the driver
278 * module.  It must be supplied, and gets passed back by the SetupProc
279 * function in the dynamic case.  In the static case, a reference to this
280 * is compiled in, and this requires that the name of this DriverRec be
281 * an upper-case version of the driver name.
282 */
283
284_X_EXPORT DriverRec NEOMAGIC = {
285    NEO_VERSION,
286    NEO_DRIVER_NAME,
287    NEOIdentify,
288    NEOProbe,
289    NEOAvailableOptions,
290    NULL,
291    0
292};
293
294static SymTabRec NEOChipsets[] = {
295    { NM2070,   "neo2070" },
296    { NM2090,   "neo2090" },
297    { NM2093,   "neo2093" },
298    { NM2097,   "neo2097" },
299    { NM2160,   "neo2160" },
300    { NM2200,   "neo2200" },
301    { NM2230,   "neo2230" },
302    { NM2360,   "neo2360" },
303    { NM2380,   "neo2380" },
304    { -1,		 NULL }
305};
306
307/* Conversion PCI ID to chipset name */
308static PciChipsets NEOPCIchipsets[] = {
309    { NM2070,  PCI_CHIP_NM2070,  RES_SHARED_VGA },
310    { NM2090,  PCI_CHIP_NM2090,  RES_SHARED_VGA },
311    { NM2093,  PCI_CHIP_NM2093,  RES_SHARED_VGA },
312    { NM2097,  PCI_CHIP_NM2097,  RES_SHARED_VGA },
313    { NM2160,  PCI_CHIP_NM2160,  RES_SHARED_VGA },
314    { NM2200,  PCI_CHIP_NM2200,  RES_SHARED_VGA },
315    { NM2230,  PCI_CHIP_NM2230,  RES_SHARED_VGA },
316    { NM2360,  PCI_CHIP_NM2360,  RES_SHARED_VGA },
317    { NM2380,  PCI_CHIP_NM2380,  RES_SHARED_VGA },
318    { -1,	     -1,	     RES_UNDEFINED}
319};
320
321#ifdef HAVE_ISA
322static IsaChipsets NEOISAchipsets[] = {
323    { NM2070,               RES_EXCLUSIVE_VGA },
324    { NM2090,               RES_EXCLUSIVE_VGA },
325    { NM2093,               RES_EXCLUSIVE_VGA },
326    { NM2097,               RES_EXCLUSIVE_VGA },
327    { NM2160,               RES_EXCLUSIVE_VGA },
328    { NM2200,               RES_EXCLUSIVE_VGA },
329    { -1,			RES_UNDEFINED }
330};
331#endif
332
333/* The options supported by the Neomagic Driver */
334typedef enum {
335    OPTION_NOACCEL,
336    OPTION_SW_CURSOR,
337    OPTION_NO_MMIO,
338    OPTION_INTERN_DISP,
339    OPTION_EXTERN_DISP,
340    OPTION_LCD_CENTER,
341    OPTION_LCD_STRETCH,
342    OPTION_SHADOW_FB,
343    OPTION_PCI_BURST,
344    OPTION_PROG_LCD_MODE_REGS,
345    OPTION_PROG_LCD_MODE_STRETCH,
346    OPTION_OVERRIDE_VALIDATE_MODE,
347    OPTION_SHOWCACHE,
348    OPTION_ROTATE,
349    OPTION_VIDEO_KEY,
350    OPTION_OVERLAYMEM,
351    OPTION_VIDEO_INTERLACE,
352    OPTION_DISPLAY_HEIGHT_480,
353    OPTION_STRANGE_LOCKUPS
354} NEOOpts;
355
356static const OptionInfoRec NEO_2070_Options[] = {
357    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
358    { OPTION_SW_CURSOR,	"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
359    { OPTION_NO_MMIO,	"noMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
360    { OPTION_INTERN_DISP,"internDisp",	OPTV_BOOLEAN,	{0}, FALSE },
361    { OPTION_EXTERN_DISP,"externDisp",  OPTV_BOOLEAN,	{0}, FALSE },
362    { OPTION_LCD_CENTER, "LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
363    { OPTION_LCD_STRETCH, "NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
364    { OPTION_SHADOW_FB,   "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
365    { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,   {0}, FALSE },
366    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
367    { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
368    { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
369      OPTV_BOOLEAN, {0}, FALSE },
370    { OPTION_PROG_LCD_MODE_STRETCH, "progLcdModeStretch",
371      OPTV_BOOLEAN, {0}, FALSE },
372    { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
373      OPTV_BOOLEAN, {0}, FALSE },
374    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
375    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
376    { OPTION_VIDEO_INTERLACE, "Interlace",
377      OPTV_INTEGER,   {0}, FALSE },
378    { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
379};
380
381static const OptionInfoRec NEOOptions[] = {
382    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
383    { OPTION_SW_CURSOR,	"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
384    { OPTION_NO_MMIO,	"noMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
385    { OPTION_INTERN_DISP,"internDisp",	OPTV_BOOLEAN,	{0}, FALSE },
386    { OPTION_EXTERN_DISP,"externDisp",	OPTV_BOOLEAN,	{0}, FALSE },
387    { OPTION_LCD_CENTER, "LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
388    { OPTION_SHADOW_FB,  "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
389    { OPTION_LCD_STRETCH,"NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
390    { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,	{0}, FALSE },
391    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
392    { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
393    { OPTION_STRANGE_LOCKUPS, "StrangeLockups", OPTV_BOOLEAN, {0}, FALSE },
394    { OPTION_DISPLAY_HEIGHT_480, "DisplayHeight480",
395      OPTV_BOOLEAN, {0}, FALSE },
396    { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
397      OPTV_BOOLEAN, {0}, FALSE },
398    { OPTION_PROG_LCD_MODE_STRETCH, "progLcdModeStretch",
399      OPTV_BOOLEAN, {0}, FALSE },
400    { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
401      OPTV_BOOLEAN, {0}, FALSE },
402    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
403    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
404    { OPTION_VIDEO_INTERLACE, "Interlace",
405      OPTV_INTEGER,   {0}, FALSE },
406    { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
407};
408
409#ifdef XFree86LOADER
410
411static MODULESETUPPROTO(neoSetup);
412
413static XF86ModuleVersionInfo neoVersRec =
414{
415	"neomagic",
416	MODULEVENDORSTRING,
417	MODINFOSTRING1,
418	MODINFOSTRING2,
419	XORG_VERSION_CURRENT,
420	NEO_MAJOR_VERSION, NEO_MINOR_VERSION, NEO_PATCHLEVEL,
421	ABI_CLASS_VIDEODRV,
422	ABI_VIDEODRV_VERSION,
423	MOD_CLASS_VIDEODRV,
424	{0,0,0,0}
425};
426
427/*
428 * This is the module init data.
429 * Its name has to be the driver name followed by ModuleData
430 */
431_X_EXPORT XF86ModuleData neomagicModuleData = { &neoVersRec, neoSetup, NULL };
432
433static pointer
434neoSetup(pointer module, pointer opts, int *errmaj, int *errmin)
435{
436    static Bool setupDone = FALSE;
437
438    if (!setupDone) {
439	setupDone = TRUE;
440        xf86AddDriver(&NEOMAGIC, module, 0);
441
442	/*
443	 * The return value must be non-NULL on success even though there
444	 * is no TearDownProc.
445	 */
446  	return (pointer)1;
447    } else {
448	if (errmaj) *errmaj = LDR_ONCEONLY;
449	return NULL;
450    }
451}
452
453#endif /* XFree86LOADER */
454
455static Bool
456NEOGetRec(ScrnInfoPtr pScrn)
457{
458    /*
459     * Allocate a NEORec, and hook it into pScrn->driverPrivate.
460     * pScrn->driverPrivate is initialised to NULL, so we can check if
461     * the allocation has already been done.
462     */
463    if (pScrn->driverPrivate != NULL)
464	return TRUE;
465
466    pScrn->driverPrivate = xnfcalloc(sizeof(NEORec), 1);
467
468    if (pScrn->driverPrivate == NULL)
469	return FALSE;
470        return TRUE;
471}
472
473static void
474NEOFreeRec(ScrnInfoPtr pScrn)
475{
476    if (pScrn->driverPrivate == NULL)
477	return;
478    xfree(pScrn->driverPrivate);
479    pScrn->driverPrivate = NULL;
480}
481
482static const OptionInfoRec *
483NEOAvailableOptions(int chipid, int busid)
484{
485    int chip = (chipid & 0x0000ffff);
486
487    if (chip == PCI_CHIP_NM2070)
488	return NEO_2070_Options;
489    else
490    	return NEOOptions;
491}
492
493/* Mandatory */
494static void
495NEOIdentify(int flags)
496{
497    xf86PrintChipsets(NEO_NAME, "Driver for Neomagic chipsets",
498			NEOChipsets);
499}
500
501/* Mandatory */
502static Bool
503NEOProbe(DriverPtr drv, int flags)
504{
505    Bool foundScreen = FALSE;
506    int numDevSections, numUsed;
507    GDevPtr *devSections;
508    int *usedChips;
509    int i;
510
511    /*
512     * Find the config file Device sections that match this
513     * driver, and return if there are none.
514     */
515    if ((numDevSections = xf86MatchDevice(NEO_DRIVER_NAME,
516					  &devSections)) <= 0) {
517	return FALSE;
518    }
519
520    /* PCI BUS */
521#ifndef XSERVER_LIBPCIACCESS
522    if (xf86GetPciVideoInfo() )
523#endif
524    {
525	numUsed = xf86MatchPciInstances(NEO_NAME, PCI_VENDOR_NEOMAGIC,
526					NEOChipsets, NEOPCIchipsets,
527					devSections,numDevSections,
528					drv, &usedChips);
529
530	if (numUsed > 0) {
531	    if (flags & PROBE_DETECT)
532		foundScreen = TRUE;
533	    else for (i = 0; i < numUsed; i++) {
534		ScrnInfoPtr pScrn = NULL;
535		/* Allocate a ScrnInfoRec and claim the slot */
536		if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
537						       NEOPCIchipsets,NULL, NULL,
538						       NULL, NULL, NULL))) {
539		    pScrn->driverVersion = NEO_VERSION;
540		    pScrn->driverName    = NEO_DRIVER_NAME;
541		    pScrn->name          = NEO_NAME;
542		    pScrn->Probe         = NEOProbe;
543		    pScrn->PreInit       = NEOPreInit;
544		    pScrn->ScreenInit    = NEOScreenInit;
545		    pScrn->SwitchMode    = NEOSwitchMode;
546		    pScrn->AdjustFrame   = NEOAdjustFrame;
547		    pScrn->EnterVT       = NEOEnterVT;
548		    pScrn->LeaveVT       = NEOLeaveVT;
549		    pScrn->FreeScreen    = NEOFreeScreen;
550		    pScrn->ValidMode     = NEOValidMode;
551		    foundScreen = TRUE;
552		}
553	    }
554	    xfree(usedChips);
555	}
556    }
557
558#ifdef HAVE_ISA
559    /* Isa Bus */
560
561    numUsed = xf86MatchIsaInstances(NEO_NAME,NEOChipsets,NEOISAchipsets,
562				     drv,neoFindIsaDevice,devSections,
563				     numDevSections,&usedChips);
564    if (numUsed > 0) {
565      if (flags & PROBE_DETECT)
566	foundScreen = TRUE;
567      else for (i = 0; i < numUsed; i++) {
568	ScrnInfoPtr pScrn = NULL;
569	if ((pScrn = xf86ConfigIsaEntity(pScrn, 0, usedChips[i],
570					 NEOISAchipsets, NULL, NULL,
571					 NULL, NULL, NULL))) {
572	    pScrn->driverVersion = NEO_VERSION;
573	    pScrn->driverName    = NEO_DRIVER_NAME;
574	    pScrn->name          = NEO_NAME;
575	    pScrn->Probe         = NEOProbe;
576	    pScrn->PreInit       = NEOPreInit;
577	    pScrn->ScreenInit    = NEOScreenInit;
578	    pScrn->SwitchMode    = NEOSwitchMode;
579	    pScrn->AdjustFrame   = NEOAdjustFrame;
580	    pScrn->EnterVT       = NEOEnterVT;
581	    pScrn->LeaveVT       = NEOLeaveVT;
582	    pScrn->FreeScreen    = NEOFreeScreen;
583	    pScrn->ValidMode     = NEOValidMode;
584	    foundScreen = TRUE;
585	}
586      }
587      xfree(usedChips);
588    }
589#endif
590
591    xfree(devSections);
592    return foundScreen;
593}
594
595#ifdef HAVE_ISA
596static int
597neoFindIsaDevice(GDevPtr dev)
598{
599    unsigned int vgaIOBase;
600    unsigned char id;
601
602    vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
603    /* §§§ Too intrusive ? */
604    outw(GRAX, 0x2609); /* Unlock NeoMagic registers */
605
606    outb(vgaIOBase + 4, 0x1A);
607    id = inb(vgaIOBase + 5);
608
609    outw(GRAX, 0x0009); /* Lock NeoMagic registers */
610
611    switch (id) {
612    case PROBED_NM2070 :
613	return NM2070;
614    case PROBED_NM2090 :
615	return NM2090;
616    case PROBED_NM2093 :
617	return NM2093;
618    default :
619	return -1;
620    }
621}
622#endif
623
624/* Mandatory */
625Bool
626NEOPreInit(ScrnInfoPtr pScrn, int flags)
627{
628    ClockRangePtr clockRanges;
629    int i;
630    NEOPtr nPtr;
631    vgaHWPtr hwp;
632    int bppSupport = NoDepth24Support;
633    int videoRam = 896;
634    int maxClock = 65000;
635    int CursorMem = 1024;
636    int CursorOff = 0x100;
637    int linearSize = 1024;
638    int maxWidth = 1024;
639    int maxHeight = 1024;
640    unsigned char type, dpy;
641    int w;
642    int apertureSize;
643    Bool height_480 = FALSE;
644    Bool lcdCenterOptSet = FALSE;
645    char *s;
646
647    if (flags & PROBE_DETECT)  {
648	neoProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
649	return TRUE;
650    }
651
652    /* The vgahw module should be loaded here when needed */
653    if (!xf86LoadSubModule(pScrn, "vgahw"))
654	return FALSE;
655
656    /*
657     * Allocate a vgaHWRec.
658     */
659    if (!vgaHWGetHWRec(pScrn))
660	return FALSE;
661    hwp = VGAHWPTR(pScrn);
662
663    /* Allocate the NeoRec driverPrivate */
664    if (!NEOGetRec(pScrn)) {
665	return FALSE;
666    }
667# define RETURN \
668    { NEOFreeRec(pScrn);\
669			    return FALSE;\
670					     }
671
672    nPtr = NEOPTR(pScrn);
673
674    /* Since, the capabilities are determined by the chipset the very
675     * first thing to do is, figure out the chipset and its capabilities
676     */
677    /* This driver doesn't expect more than one entity per screen */
678    if (pScrn->numEntities > 1)
679	RETURN;
680
681    /* This is the general case */
682    for (i = 0; i<pScrn->numEntities; i++) {
683	nPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
684#ifndef XSERVER_LIBPCIACCESS
685	if (nPtr->pEnt->resources) return FALSE;
686#endif
687	nPtr->NeoChipset = nPtr->pEnt->chipset;
688	pScrn->chipset = (char *)xf86TokenToString(NEOChipsets,
689						   nPtr->pEnt->chipset);
690	/* This driver can handle ISA and PCI buses */
691	if (nPtr->pEnt->location.type == BUS_PCI) {
692	    nPtr->PciInfo = xf86GetPciInfoForEntity(nPtr->pEnt->index);
693#ifndef XSERVER_LIBPCIACCESS
694	    nPtr->PciTag = pciTag(nPtr->PciInfo->bus,
695				  nPtr->PciInfo->device,
696				  nPtr->PciInfo->func);
697#endif
698	}
699    }
700    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Chipset is a ");
701    switch(nPtr->NeoChipset){
702    case NM2070:
703	xf86ErrorF("MagicGraph 128 (NM2070)");
704	break;
705    case NM2090 :
706	xf86ErrorF("MagicGraph 128V (NM2090)");
707	break;
708    case NM2093 :
709	xf86ErrorF("MagicGraph 128ZV (NM2093)");
710	break;
711    case NM2097 :
712	xf86ErrorF("MagicGraph 128ZV+ (NM2097)");
713	break;
714    case NM2160 :
715	xf86ErrorF("MagicGraph 128XD (NM2160)");
716	break;
717    case NM2200 :
718        xf86ErrorF("MagicMedia 256AV (NM2200)");
719	break;
720    case NM2230 :
721        xf86ErrorF("MagicMedia 256AV+ (NM2230)");
722	break;
723    case NM2360 :
724        xf86ErrorF("MagicMedia 256ZX (NM2360)");
725	break;
726    case NM2380 :
727        xf86ErrorF("MagicMedia 256XL+ (NM2380)");
728	break;
729    }
730    xf86ErrorF("\n");
731
732    vgaHWGetIOBase(hwp);
733    nPtr->vgaIOBase = hwp->IOBase;
734    vgaHWSetStdFuncs(hwp);
735
736    /* Determine the panel type */
737    VGAwGR(0x09,0x26);
738    type = VGArGR(0x21);
739    dpy = VGArGR(0x20);
740
741    /* Determine panel width -- used in NeoValidMode. */
742    w = VGArGR(0x20);
743    VGAwGR(0x09,0x00);
744    switch ((w & 0x18) >> 3) {
745    case 0x00 :
746	nPtr->NeoPanelWidth  = 640;
747	nPtr->NeoPanelHeight = 480;
748	break;
749    case 0x01 :
750	nPtr->NeoPanelWidth  = 800;
751	nPtr->NeoPanelHeight = 600;
752	break;
753    case 0x02 :
754	nPtr->NeoPanelWidth  = 1024;
755	nPtr->NeoPanelHeight = 768;
756	break;
757    case 0x03 :
758        /* 1280x1024 panel support needs to be added */
759#ifdef NOT_DONE
760	nPtr->NeoPanelWidth  = 1280;
761	nPtr->NeoPanelHeight = 1024;
762	break;
763#else
764	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
765		     "Only 640x480,\n"
766                     "     800x600,\n"
767                     " and 1024x768 panels are currently supported\n");
768	return FALSE;
769#endif
770    default :
771	nPtr->NeoPanelWidth  = 640;
772	nPtr->NeoPanelHeight = 480;
773	break;
774    }
775
776    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel is a %dx%d %s %s display\n",
777	       nPtr->NeoPanelWidth,
778	       nPtr->NeoPanelHeight,
779	       (type & 0x02) ? "color" : "monochrome",
780	       (type & 0x10) ? "TFT" : "dual scan");
781
782
783    switch (nPtr->NeoChipset){
784    case NM2070:
785	bppSupport = NoDepth24Support;
786	videoRam   = 896;
787	maxClock   = 65000;
788	CursorMem  = 2048;
789	CursorOff  = 0x100;
790	linearSize = 1024;
791	maxWidth   = 1024;
792	maxHeight  = 1024;
793	break;
794    case NM2090:
795    case NM2093:
796	bppSupport = Support24bppFb | Support32bppFb |
797	    SupportConvert32to24 | PreferConvert32to24;
798	videoRam   = 1152;
799	maxClock   = 80000;
800	CursorMem  = 2048;
801	CursorOff  = 0x100;
802	linearSize = 2048;
803	maxWidth   = 1024;
804	maxHeight  = 1024;
805	break;
806    case NM2097:
807	bppSupport = Support24bppFb | Support32bppFb |
808	  SupportConvert32to24 | PreferConvert32to24;
809	videoRam   = 1152;
810	maxClock   = 80000;
811	CursorMem  = 1024;
812	CursorOff  = 0x100;
813	linearSize = 2048;
814	maxWidth   = 1024;
815	maxHeight  = 1024;
816	break;
817    case NM2160:
818	bppSupport = Support24bppFb | Support32bppFb |
819	    SupportConvert32to24 | PreferConvert32to24;
820	videoRam   = 2048;
821	maxClock   = 90000;
822	CursorMem  = 1024;
823	CursorOff  = 0x100;
824	linearSize = 2048;
825	maxWidth   = 1024;
826	maxHeight  = 1024;
827	break;
828    case NM2200:
829	bppSupport = Support24bppFb | Support32bppFb |
830	    SupportConvert32to24 | PreferConvert32to24;
831	videoRam   = 2560;
832	maxClock   = 110000;
833	CursorMem  = 1024;
834	CursorOff  = 0x1000;
835	linearSize = 4096;
836	maxWidth   = 1280;
837	maxHeight  = 1024;  /* ???? */
838	break;
839    case NM2230:
840	bppSupport = Support24bppFb | Support32bppFb |
841	    SupportConvert32to24 | PreferConvert32to24;
842	videoRam   = 3008;
843	maxClock   = 110000;
844	CursorMem  = 1024;
845	CursorOff  = 0x1000;
846	linearSize = 4096;
847	maxWidth   = 1280;
848	maxHeight  = 1024;  /* ???? */
849	break;
850    case NM2360:
851	bppSupport = Support24bppFb | Support32bppFb |
852	    SupportConvert32to24 | PreferConvert32to24;
853	videoRam   = 4096;
854	maxClock   = 110000;
855	CursorMem  = 1024;
856	CursorOff  = 0x1000;
857	linearSize = 4096;
858	maxWidth   = 1280;
859	maxHeight  = 1024;  /* ???? */
860	break;
861    case NM2380:
862	bppSupport = Support24bppFb | Support32bppFb |
863	    SupportConvert32to24 | PreferConvert32to24;
864	videoRam   = 6144;
865	maxClock   = 110000;
866	CursorMem  = 1024;
867	CursorOff  = 0x1000;
868	linearSize = 8192;
869	maxWidth   = 1280;
870	maxHeight  = 1024;  /* ???? */
871	break;
872    }
873
874    pScrn->monitor = pScrn->confScreen->monitor;
875
876    if (xf86LoadSubModule(pScrn, "ddc")) {
877#if 1 /* for DDC1 testing */
878	if (!neoDoDDCVBE(pScrn))
879	  if (!neoDoDDC2(pScrn))
880#endif
881	      neoDoDDC1(pScrn);
882    }
883
884    if (!xf86SetDepthBpp(pScrn, 16, 0, 0, bppSupport ))
885	return FALSE;
886    else {
887	/* Check that the returned depth is one we support */
888	switch (pScrn->depth) {
889	case 8:
890	case 15:
891	case 16:
892	    break;
893	case 24:
894	    if (nPtr->NeoChipset != NM2070)
895		break;
896	default:
897	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
898		       "Given depth (%d) is not supported by this driver\n",
899		       pScrn->depth);
900	    return FALSE;
901	}
902    }
903    xf86PrintDepthBpp(pScrn);
904    if (pScrn->depth == 8)
905	pScrn->rgbBits = 6;
906
907    /* Get the depth24 pixmap format */
908    if (pScrn->depth == 24 && pix24bpp == 0)
909	pix24bpp = xf86GetBppFromDepth(pScrn, 24);
910
911    /*
912     * This must happen after pScrn->display has been set because
913     * xf86SetWeight references it.
914     */
915    if (pScrn->depth > 8) {
916	/* The defaults are OK for us */
917	rgb zeros = {0, 0, 0};
918
919	if (!xf86SetWeight(pScrn, zeros, zeros)) {
920	    return FALSE;
921	} else {
922	    /* XXX check that weight returned is supported */
923	    ;
924	}
925    }
926
927    if (!xf86SetDefaultVisual(pScrn, -1))
928	return FALSE;
929
930    if (pScrn->depth > 1) {
931	Gamma zeros = {0.0, 0.0, 0.0};
932
933	if (!xf86SetGamma(pScrn, zeros))
934	    return FALSE;
935    }
936
937    nPtr->strangeLockups = TRUE;
938
939    /* Collect all of the relevant option flags (fill in pScrn->options) */
940    xf86CollectOptions(pScrn, NULL);
941    /* Process the options */
942    if (nPtr->NeoChipset == NM2070) {
943	if (!(nPtr->Options = xalloc(sizeof(NEO_2070_Options))))
944	    return FALSE;
945	memcpy(nPtr->Options, NEO_2070_Options, sizeof(NEO_2070_Options));
946    } else {
947	if (!(nPtr->Options = xalloc(sizeof(NEOOptions))))
948	    return FALSE;
949	memcpy(nPtr->Options, NEOOptions, sizeof(NEOOptions));
950    }
951
952    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, nPtr->Options);
953
954    xf86GetOptValBool(nPtr->Options, OPTION_SW_CURSOR,&nPtr->swCursor);
955    xf86GetOptValBool(nPtr->Options, OPTION_NO_MMIO,&nPtr->noMMIO);
956    xf86GetOptValBool(nPtr->Options, OPTION_INTERN_DISP,&nPtr->internDisp);
957    xf86GetOptValBool(nPtr->Options, OPTION_EXTERN_DISP,&nPtr->externDisp);
958    if (xf86GetOptValBool(nPtr->Options, OPTION_LCD_CENTER,&nPtr->lcdCenter))
959	lcdCenterOptSet = TRUE;
960    xf86GetOptValBool(nPtr->Options, OPTION_LCD_STRETCH,&nPtr->noLcdStretch);
961    xf86GetOptValBool(nPtr->Options, OPTION_SHADOW_FB,&nPtr->shadowFB);
962    xf86GetOptValBool(nPtr->Options, OPTION_SHOWCACHE,&nPtr->showcache);
963    nPtr->onPciBurst = TRUE;
964    xf86GetOptValBool(nPtr->Options, OPTION_PCI_BURST,&nPtr->onPciBurst);
965    xf86GetOptValBool(nPtr->Options,
966		      OPTION_PROG_LCD_MODE_REGS,&nPtr->progLcdRegs);
967    if (xf86GetOptValBool(nPtr->Options,
968		      OPTION_PROG_LCD_MODE_STRETCH,&nPtr->progLcdStretch))
969	nPtr->progLcdStretchOpt = TRUE;
970    xf86GetOptValBool(nPtr->Options,
971		      OPTION_OVERRIDE_VALIDATE_MODE, &nPtr->overrideValidate);
972    xf86GetOptValBool(nPtr->Options, OPTION_DISPLAY_HEIGHT_480,&height_480);
973    xf86GetOptValBool(nPtr->Options, OPTION_STRANGE_LOCKUPS,
974		      &nPtr->strangeLockups);
975    nPtr->noAccelSet =
976	xf86GetOptValBool(nPtr->Options, OPTION_NOACCEL,&nPtr->noAccel);
977
978    nPtr->rotate = 0;
979    if ((s = xf86GetOptValString(nPtr->Options, OPTION_ROTATE))) {
980	if(!xf86NameCmp(s, "CW")) {
981	    /* accel is disabled below for shadowFB */
982	    nPtr->shadowFB = TRUE;
983	    nPtr->swCursor = TRUE;
984	    nPtr->rotate = 1;
985	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
986		       "Rotating screen clockwise - acceleration disabled\n");
987	} else if(!xf86NameCmp(s, "CCW")) {
988	    nPtr->shadowFB = TRUE;
989	    nPtr->swCursor = TRUE;
990	    nPtr->rotate = -1;
991	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
992		       "counter clockwise - acceleration disabled\n");
993	} else {
994	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
995		       "value for Option \"Rotate\"\n", s);
996	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
997		       "Valid options are \"CW\" or \"CCW\"\n");
998      }
999    }
1000
1001    if(xf86GetOptValInteger(nPtr->Options,
1002			    OPTION_VIDEO_KEY, &(nPtr->videoKey))) {
1003        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
1004		   nPtr->videoKey);
1005    } else {
1006        nPtr->videoKey = (1 << pScrn->offset.red) |
1007	    (1 << pScrn->offset.green) |
1008	    (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
1009	     << pScrn->offset.blue);
1010    }
1011    if(xf86GetOptValInteger(nPtr->Options, OPTION_OVERLAYMEM,
1012			    &(nPtr->overlay))) {
1013        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1014		   "reserve %d bytes for overlay.\n", nPtr->overlay);
1015    } else {
1016	nPtr->overlay = 0;
1017    }
1018    nPtr->interlace = 0;
1019    if(xf86GetOptValInteger(nPtr->Options, OPTION_VIDEO_INTERLACE,
1020			    &(nPtr->interlace))) {
1021	if (nPtr->interlace >= 0  &&  nPtr->interlace <= 2){
1022	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "interlace flag = %d\n",
1023		       nPtr->interlace);
1024	} else {
1025	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1026		       "\"%s\" is not a valid value for "
1027		       "Option \"Interlaced\"\n", s);
1028	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are  0..2\n");
1029        }
1030    }
1031
1032    if (height_480
1033	&& (nPtr->NeoPanelWidth == 800 || nPtr->NeoPanelWidth == 1024)) {
1034	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1035		   "Overriding Panel height: Set to 480\n");
1036	nPtr->NeoPanelHeight = 480;
1037	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1038		   "Disabling LCD stretching for panel height 480\n");
1039	nPtr->noLcdStretch = TRUE;
1040	if (!lcdCenterOptSet)
1041	    nPtr->lcdCenter = TRUE;
1042    }
1043
1044    if (nPtr->internDisp && nPtr->externDisp)
1045	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1046		   "Simultaneous LCD/CRT display mode\n");
1047    else if (nPtr->externDisp)
1048	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1049		   "External CRT only display mode\n");
1050    else  if (nPtr->internDisp)
1051	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1052		   "Internal LCD only display mode\n");
1053    else {
1054	nPtr->internDisp = ((dpy & 0x02) == 0x02);
1055    	nPtr->externDisp = ((dpy & 0x01) == 0x01);
1056	if (nPtr->internDisp && nPtr->externDisp)
1057	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1058		       "Simultaneous LCD/CRT display mode\n");
1059	else if (nPtr->externDisp)
1060	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1061		       "External CRT only display mode\n");
1062	else if (nPtr->internDisp)
1063	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1064		       "Internal LCD only display mode\n");
1065	else {
1066	    /* this is a fallback if probed values are bogus */
1067	    nPtr->internDisp = TRUE;
1068	    xf86DrvMsg(pScrn->scrnIndex,X_DEFAULT,
1069		       "Internal LCD only display mode\n");
1070	}
1071    }
1072
1073    if (nPtr->noLcdStretch)
1074	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1075		   "Low resolution video modes are not stretched\n");
1076    if (nPtr->lcdCenter)
1077	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1078		   "Video modes are centered on the display\n");
1079    if (nPtr->swCursor)
1080	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using sofware cursor\n");
1081    if (nPtr->noMMIO)
1082	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "MMIO mode disabled\n");
1083    if (nPtr->onPciBurst)
1084	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using PCI Burst mode\n");
1085    if (nPtr->strangeLockups)
1086	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1087		   "Option StrangeLockups set: disabling some acceleration\n");
1088    if (nPtr->showcache)
1089	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1090		   "Show chache for debugging\n");
1091    if (nPtr->shadowFB) {
1092        nPtr->noAccel = TRUE;
1093        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1094                "Using \"Shadow Framebuffer\" - acceleration disabled\n");
1095    }
1096
1097    nPtr->NeoFbMapSize = linearSize * 1024;
1098    nPtr->NeoCursorOffset = CursorOff;
1099
1100    if (nPtr->pEnt->device->MemBase) {
1101	/* XXX Check this matches a PCI base address */
1102	nPtr->NeoLinearAddr = nPtr->pEnt->device->MemBase;
1103	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1104		   "FB base address is set at 0x%lX.\n",
1105		   nPtr->NeoLinearAddr);
1106    } else {
1107	nPtr->NeoLinearAddr = 0;
1108    }
1109
1110    nPtr->NeoMMIOAddr2 = 0;
1111    nPtr->NeoMMIOBase2 = NULL;
1112    if (nPtr->pEnt->device->IOBase && !nPtr->noMMIO) {
1113	/* XXX Check this matches a PCI base address */
1114	nPtr->NeoMMIOAddr = nPtr->pEnt->device->IOBase;
1115	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1116		   "MMIO base address is set at 0x%lX.\n",
1117		   nPtr->NeoMMIOAddr);
1118    } else {
1119	nPtr->NeoMMIOAddr = 0;
1120    }
1121
1122    if (nPtr->pEnt->location.type == BUS_PCI) {
1123	if (!nPtr->NeoLinearAddr) {
1124	    nPtr->NeoLinearAddr = PCI_REGION_BASE(nPtr->PciInfo, 0, REGION_MEM);
1125	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1126		       "FB base address is set at 0x%lX.\n",
1127		       nPtr->NeoLinearAddr);
1128	}
1129	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
1130	    switch (nPtr->NeoChipset) {
1131	    case NM2070 :
1132		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
1133		break;
1134	    case NM2090:
1135	    case NM2093:
1136		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x200000;
1137		break;
1138	    case NM2160:
1139	    case NM2097:
1140	    case NM2200:
1141	    case NM2230:
1142	    case NM2360:
1143	    case NM2380:
1144		nPtr->NeoMMIOAddr = PCI_REGION_BASE(nPtr->PciInfo, 1, REGION_MEM);
1145		nPtr->NeoMMIOAddr2 = PCI_REGION_BASE(nPtr->PciInfo, 2, REGION_MEM);
1146		break;
1147	    }
1148	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1149		       "MMIO base address is set at 0x%lX.\n",
1150		       nPtr->NeoMMIOAddr);
1151	    if (nPtr->NeoMMIOAddr2 != 0){
1152	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1153		           "MMIO base address2 is set at 0x%lX.\n",
1154		           nPtr->NeoMMIOAddr2);
1155	    }
1156	}
1157#ifndef XSERVER_LIBPCIACCESS
1158	/* XXX What about VGA resources in OPERATING mode? */
1159	if (xf86RegisterResources(nPtr->pEnt->index, NULL, ResExclusive))
1160	    RETURN;
1161#endif
1162
1163    }
1164#ifndef XSERVER_LIBPCIACCESS
1165    else if (nPtr->pEnt->location.type == BUS_ISA) {
1166	unsigned int addr;
1167	resRange linearRes[] = { {ResExcMemBlock|ResBios|ResBus,0,0},_END };
1168
1169	if (!nPtr->NeoLinearAddr) {
1170	    VGAwGR(0x09,0x26);
1171	    addr = VGArGR(0x13);
1172	    VGAwGR(0x09,0x00);
1173	    nPtr->NeoLinearAddr = addr << 20;
1174	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1175		       "FB base address is set at 0x%lX.\n",
1176		       nPtr->NeoLinearAddr);
1177	}
1178	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
1179	    nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
1180	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1181		       "MMIO base address is set at 0x%lX.\n",
1182		       nPtr->NeoMMIOAddr);
1183	}
1184
1185	linearRes[0].rBegin = nPtr->NeoLinearAddr;
1186	linearRes[1].rEnd = nPtr->NeoLinearAddr + nPtr->NeoFbMapSize - 1;
1187	if (xf86RegisterResources(nPtr->pEnt->index,linearRes,ResNone)) {
1188	    RETURN;
1189	}
1190    }
1191#endif
1192    else
1193	RETURN;
1194
1195    if (nPtr->pEnt->device->videoRam != 0) {
1196	pScrn->videoRam = nPtr->pEnt->device->videoRam;
1197	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VideoRAM: %d kByte\n",
1198		   pScrn->videoRam);
1199    } else {
1200	pScrn->videoRam = videoRam;
1201	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VideoRAM: %d kByte\n",
1202		   pScrn->videoRam);
1203    }
1204
1205    if (nPtr->pEnt->device->dacSpeeds[0] != 0) {
1206	maxClock = nPtr->pEnt->device->dacSpeeds[0];
1207	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Max Clock: %d kHz\n",
1208		   maxClock);
1209    } else {
1210	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Max Clock: %d kHz\n",
1211		   maxClock);
1212    }
1213
1214    pScrn->progClock = TRUE;
1215    /*
1216     * Setup the ClockRanges, which describe what clock ranges are available,
1217     * and what sort of modes they can be used for.
1218     */
1219    clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
1220    clockRanges->next = NULL;
1221    clockRanges->ClockMulFactor = 1;
1222    clockRanges->minClock = 11000;   /* guessed §§§ */
1223    clockRanges->maxClock = maxClock;
1224    clockRanges->clockIndex = -1;		/* programmable */
1225	clockRanges->interlaceAllowed = FALSE;
1226    clockRanges->doubleScanAllowed = TRUE;
1227
1228    /* Subtract memory for HW cursor */
1229    if (!nPtr->swCursor)
1230	nPtr->NeoCursorMem = CursorMem;
1231    else
1232	nPtr->NeoCursorMem = 0;
1233    apertureSize = (pScrn->videoRam * 1024) - nPtr->NeoCursorMem;
1234
1235    if ((nPtr->NeoPanelWidth == 800) && (nPtr->NeoPanelHeight == 480)) {
1236	neo800x480Mode.next = pScrn->monitor->Modes;
1237	pScrn->monitor->Modes = &neo800x480Mode;
1238    }
1239    if ((nPtr->NeoPanelWidth == 1024) && (nPtr->NeoPanelHeight == 480)) {
1240	neo1024x480Mode.next = pScrn->monitor->Modes;
1241	pScrn->monitor->Modes = &neo1024x480Mode;
1242    }
1243
1244    if (!pScrn->monitor->DDC) {
1245	/*
1246	 * If the monitor parameters are not specified explicitly, set them
1247	 * so that 60Hz modes up to the panel size are allowed.
1248	 */
1249	if (pScrn->monitor->nHsync == 0) {
1250	    pScrn->monitor->nHsync = 1;
1251	    pScrn->monitor->hsync[0].lo = 28;
1252	    pScrn->monitor->hsync[0].hi =
1253				60.0 * 1.07 * nPtr->NeoPanelHeight / 1000.0;
1254	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1255		       "Using hsync range matching panel size: %.2f-%.2f kHz\n",
1256		       pScrn->monitor->hsync[0].lo,
1257		       pScrn->monitor->hsync[0].hi);
1258	}
1259	if (pScrn->monitor->nVrefresh == 0) {
1260	    pScrn->monitor->nVrefresh = 1;
1261	    pScrn->monitor->vrefresh[0].lo = 55.0;
1262	    pScrn->monitor->vrefresh[0].hi = 65.0;
1263	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1264		       "Using vsync range for panel: %.2f-%.2f kHz\n",
1265		       pScrn->monitor->vrefresh[0].lo,
1266		       pScrn->monitor->vrefresh[0].hi);
1267	}
1268    }
1269
1270    /*
1271     * For external displays, limit the width to 1024 pixels or less.
1272     */
1273    {
1274       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
1275			  pScrn->display->modes, clockRanges,
1276			  NULL, 256, maxWidth,(8 * pScrn->bitsPerPixel),/*§§§*/
1277			  128, maxHeight, pScrn->display->virtualX,
1278			  pScrn->display->virtualY, apertureSize,
1279			  LOOKUP_BEST_REFRESH);
1280
1281       if (i == -1)
1282           RETURN;
1283    }
1284
1285    /* Prune the modes marked as invalid */
1286    xf86PruneDriverModes(pScrn);
1287
1288    if (i == 0 || pScrn->modes == NULL) {
1289	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1290	RETURN;
1291    }
1292
1293    /*
1294     * Set the CRTC parameters for all of the modes based on the type
1295     * of mode, and the chipset's interlace requirements.
1296     *
1297     * Calling this is required if the mode->Crtc* values are used by the
1298     * driver and if the driver doesn't provide code to set them.  They
1299     * are not pre-initialised at all.
1300     */
1301    xf86SetCrtcForModes(pScrn, 0);
1302
1303    /* Set the current mode to the first in the list */
1304    pScrn->currentMode = pScrn->modes;
1305
1306    /* Print the list of modes being used */
1307    xf86PrintModes(pScrn);
1308
1309    /* If monitor resolution is set on the command line, use it */
1310    xf86SetDpi(pScrn, 0, 0);
1311
1312    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
1313	RETURN;
1314    }
1315
1316    if (!xf86LoadSubModule(pScrn, "xaa"))
1317        RETURN;
1318
1319    if (nPtr->shadowFB) {
1320	if (!xf86LoadSubModule(pScrn, "shadow")) {
1321	    RETURN;
1322	}
1323    }
1324
1325    if (!nPtr->swCursor) {
1326	if (!xf86LoadSubModule(pScrn, "ramdac"))
1327	    RETURN;
1328    }
1329    return TRUE;
1330}
1331#undef RETURN
1332
1333/* Mandatory */
1334static Bool
1335NEOEnterVT(int scrnIndex, int flags)
1336{
1337    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1338    NEOPtr nPtr = NEOPTR(pScrn);
1339
1340    /* Should we re-save the text mode on each VT enter? */
1341    if(!neoModeInit(pScrn, pScrn->currentMode))
1342      return FALSE;
1343
1344    if (nPtr->video)
1345	NEOResetVideo(pScrn);
1346
1347    if (nPtr->NeoHWCursorShown)
1348	NeoShowCursor(pScrn);
1349    NEOAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1350
1351    return TRUE;
1352}
1353
1354/* Mandatory */
1355static void
1356NEOLeaveVT(int scrnIndex, int flags)
1357{
1358    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1359    NEOPtr nPtr = NEOPTR(pScrn);
1360
1361    /* Invalidate the cached acceleration registers */
1362    if (nPtr->NeoHWCursorShown)
1363	NeoHideCursor(pScrn);
1364    neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
1365    neoLock(pScrn);
1366
1367}
1368
1369static void
1370NEOLoadPalette(
1371   ScrnInfoPtr pScrn,
1372   int numColors,
1373   int *indices,
1374   LOCO *colors,
1375   VisualPtr pVisual
1376){
1377   int i, index, shift, Gshift;
1378   vgaHWPtr hwp = VGAHWPTR(pScrn);
1379
1380   switch(pScrn->depth) {
1381   case 15:
1382	shift = Gshift = 1;
1383	break;
1384   case 16:
1385	shift = 0;
1386        Gshift = 0;
1387	break;
1388   default:
1389	shift = Gshift = 0;
1390	break;
1391   }
1392
1393   for(i = 0; i < numColors; i++) {
1394        index = indices[i];
1395        hwp->writeDacWriteAddr(hwp, index);
1396	DACDelay(hwp);
1397        hwp->writeDacData(hwp, colors[index].red << shift);
1398	DACDelay(hwp);
1399        hwp->writeDacData(hwp, colors[index].green << Gshift);
1400	DACDelay(hwp);
1401        hwp->writeDacData(hwp, colors[index].blue << shift);
1402	DACDelay(hwp);
1403   }
1404}
1405
1406/* Mandatory */
1407static Bool
1408NEOScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
1409{
1410    ScrnInfoPtr pScrn;
1411    vgaHWPtr hwp;
1412    NEOPtr nPtr;
1413    NEOACLPtr nAcl;
1414    int ret;
1415    VisualPtr visual;
1416    int allocatebase, freespace, currentaddr;
1417#ifndef XSERVER_LIBPCIACCESS
1418    unsigned int racflag = RAC_FB;
1419#endif
1420    unsigned char *FBStart;
1421    int height, width, displayWidth;
1422
1423    /*
1424     * we need to get the ScrnInfoRec for this screen, so let's allocate
1425     * one first thing
1426     */
1427    pScrn = xf86Screens[pScreen->myNum];
1428    nPtr = NEOPTR(pScrn);
1429    nAcl = NEOACLPTR(pScrn);
1430
1431    hwp = VGAHWPTR(pScrn);
1432    hwp->MapSize = 0x10000;		/* Standard 64k VGA window */
1433    /* Map the VGA memory */
1434    if (!vgaHWMapMem(pScrn))
1435	return FALSE;
1436
1437    /* Map the Neo memory and possible MMIO areas */
1438    if (!neoMapMem(pScrn))
1439	return FALSE;
1440
1441    /*
1442     * next we save the current state and setup the first mode
1443     */
1444    neoSave(pScrn);
1445
1446    if (!neoModeInit(pScrn,pScrn->currentMode))
1447	return FALSE;
1448    vgaHWSaveScreen(pScreen,SCREEN_SAVER_ON);
1449    NEOAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1450
1451    /*
1452     * Reset visual list.
1453     */
1454    miClearVisualTypes();
1455
1456    /* Setup the visuals we support. */
1457    if (!miSetVisualTypes(pScrn->depth,
1458      		      miGetDefaultVisualMask(pScrn->depth),
1459		      pScrn->rgbBits, pScrn->defaultVisual))
1460         return FALSE;
1461
1462    if (!miSetPixmapDepths ()) return FALSE;
1463
1464    /*
1465     * Call the framebuffer layer's ScreenInit function, and fill in other
1466     * pScreen fields.
1467     */
1468    displayWidth = pScrn->displayWidth;
1469    if (nPtr->rotate) {
1470	height = pScrn->virtualX;
1471	width = pScrn->virtualY;
1472    } else {
1473	width = pScrn->virtualX;
1474	height = pScrn->virtualY;
1475    }
1476
1477    if(nPtr->shadowFB) {
1478	nPtr->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
1479	nPtr->ShadowPtr = xalloc(nPtr->ShadowPitch * height);
1480	displayWidth = nPtr->ShadowPitch / (pScrn->bitsPerPixel >> 3);
1481	FBStart = nPtr->ShadowPtr;
1482    } else {
1483	nPtr->ShadowPtr = NULL;
1484	FBStart = nPtr->NeoFbBase;
1485    }
1486
1487    ret = fbScreenInit(pScreen, FBStart,
1488			    width, height,
1489			    pScrn->xDpi, pScrn->yDpi,
1490			    displayWidth, pScrn->bitsPerPixel);
1491    if (!ret)
1492	return FALSE;
1493    if (pScrn->depth > 8) {
1494        /* Fixup RGB ordering */
1495        visual = pScreen->visuals + pScreen->numVisuals;
1496        while (--visual >= pScreen->visuals) {
1497	    if ((visual->class | DynamicClass) == DirectColor) {
1498		visual->offsetRed = pScrn->offset.red;
1499		visual->offsetGreen = pScrn->offset.green;
1500		visual->offsetBlue = pScrn->offset.blue;
1501		visual->redMask = pScrn->mask.red;
1502		visual->greenMask = pScrn->mask.green;
1503		visual->blueMask = pScrn->mask.blue;
1504	    }
1505	}
1506    }
1507
1508    /* must be after RGB ordering fixed */
1509    fbPictureInit(pScreen, 0, 0);
1510
1511    xf86SetBlackWhitePixels(pScreen);
1512
1513    if (!nPtr->shadowFB)
1514	NEODGAInit(pScreen);
1515
1516    nPtr->NeoHWCursorShown = FALSE;
1517    nPtr->NeoHWCursorInitialized = FALSE;
1518    nAcl->UseHWCursor = FALSE;
1519    nAcl->CursorAddress = -1;
1520
1521    nAcl->cacheStart = -1;
1522    nAcl->cacheEnd = -1;
1523    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1524               "Using linear framebuffer at: 0x%08lX\n",
1525               nPtr->NeoLinearAddr);
1526    /* Setup pointers to free space in video ram */
1527    allocatebase = (pScrn->videoRam << 10);
1528    freespace = allocatebase - pScrn->displayWidth *
1529        pScrn->virtualY * (pScrn->bitsPerPixel >> 3);
1530    currentaddr = allocatebase;
1531    xf86DrvMsg(scrnIndex, X_PROBED,
1532               "%d bytes off-screen memory available\n", freespace);
1533
1534    if (nPtr->swCursor || !nPtr->NeoMMIOBase) {
1535        xf86DrvMsg(scrnIndex, X_CONFIG,
1536                   "Using Software Cursor.\n");
1537    } else if (nPtr->NeoCursorMem <= freespace) {
1538        currentaddr -= nPtr->NeoCursorMem;
1539        freespace  -= nPtr->NeoCursorMem;
1540        /* alignment */
1541        freespace  -= currentaddr & 0x3FF;
1542        currentaddr &= 0xfffffc00;
1543        nAcl->CursorAddress = currentaddr;
1544        xf86DrvMsg(scrnIndex, X_INFO,
1545                   "Using H/W Cursor.\n");
1546    } else {
1547        xf86DrvMsg(scrnIndex, X_ERROR,
1548                   "Too little space for H/W cursor.\n");
1549    }
1550
1551    if (!nPtr->noAccel && !nPtr->NeoMMIOBase)
1552      xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1553                 "Acceleration disabled when not using MMIO\n");
1554
1555    if (nPtr->overlay > 0){
1556        if (nPtr->overlay > freespace){
1557            xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1558                       "Can not reserve %d bytes for overlay. "
1559                       "Resize to %d bytes.\n",
1560                       nPtr->overlay, freespace);
1561            nPtr->overlay = freespace;
1562        }
1563        currentaddr -= nPtr->overlay;
1564        freespace -= nPtr->overlay;
1565        nPtr->overlay_offset = currentaddr;
1566        xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Overlay at 0x%x\n",
1567                   nPtr->overlay_offset);
1568    }
1569
1570    nAcl->cacheStart = currentaddr - freespace;
1571    nAcl->cacheEnd = currentaddr;
1572    freespace = 0;
1573    if (nAcl->cacheStart < nAcl->cacheEnd) {
1574        BoxRec AvailFBArea;
1575        int lines = nAcl->cacheEnd /
1576            (pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
1577        if (!nPtr->noAccel && nPtr->NeoMMIOBase && lines > 1024)
1578            lines = 1024;
1579        AvailFBArea.x1 = 0;
1580        AvailFBArea.y1 = 0;
1581        AvailFBArea.x2 = pScrn->displayWidth;
1582        AvailFBArea.y2 = lines;
1583        xf86InitFBManager(pScreen, &AvailFBArea);
1584
1585        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1586                   "Using %i scanlines of offscreen memory \n",
1587                   lines - pScrn->virtualY);
1588    }
1589
1590    /* Setup the acceleration primitives */
1591    if (!nPtr->noAccel && nPtr->NeoMMIOBase) {
1592        Bool ret = FALSE;
1593        if (nAcl->cacheStart >= nAcl->cacheEnd) {
1594            xf86DrvMsg(scrnIndex, X_ERROR,
1595                       "Too little space for pixmap cache.\n");
1596        }
1597        switch(nPtr->NeoChipset) {
1598        case NM2070 :
1599            ret = Neo2070AccelInit(pScreen);
1600            break;
1601        case NM2090 :
1602        case NM2093 :
1603            ret = Neo2090AccelInit(pScreen);
1604            break;
1605        case NM2097 :
1606        case NM2160 :
1607            ret = Neo2097AccelInit(pScreen);
1608            break;
1609        case NM2200 :
1610        case NM2230 :
1611        case NM2360 :
1612        case NM2380 :
1613            ret = Neo2200AccelInit(pScreen);
1614            break;
1615        }
1616        xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1617                   "Acceleration %s Initialized\n",ret ? "" : "not");
1618    }
1619
1620    miInitializeBackingStore(pScreen);
1621    xf86SetBackingStore(pScreen);
1622    xf86SetSilkenMouse(pScreen);
1623
1624    /* Initialise cursor functions */
1625    miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
1626
1627    if (nAcl->CursorAddress != -1) {
1628      /* HW cursor functions */
1629      if (!NeoCursorInit(pScreen)) {
1630	xf86DrvMsg(scrnIndex, X_ERROR,
1631		   "Hardware cursor initialization failed\n");
1632	return FALSE;
1633      }
1634      nAcl->UseHWCursor = TRUE;
1635      nPtr->NeoHWCursorInitialized = TRUE;
1636    } else
1637      nAcl->UseHWCursor = FALSE;
1638
1639    if (nPtr->shadowFB) {
1640        nPtr->refreshArea = neoRefreshArea;
1641
1642	if(nPtr->rotate) {
1643	    if (!nPtr->PointerMoved) {
1644		nPtr->PointerMoved = pScrn->PointerMoved;
1645		pScrn->PointerMoved = neoPointerMoved;
1646	    }
1647	    switch(pScrn->bitsPerPixel) {
1648	    case 8:	nPtr->refreshArea = neoRefreshArea8;	break;
1649	    case 16:	nPtr->refreshArea = neoRefreshArea16;	break;
1650	    case 24:	nPtr->refreshArea = neoRefreshArea24;	break;
1651	    case 32:	nPtr->refreshArea = neoRefreshArea32;	break;
1652	    }
1653	}
1654#if 0
1655	ShadowFBInit(pScreen, nPtr->refreshArea);
1656#else
1657	shadowInit (pScreen, neoShadowUpdate, 0);
1658#endif
1659    }
1660
1661    /* Initialise default colourmap */
1662    if(!miCreateDefColormap(pScreen))
1663	return FALSE;
1664
1665    if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits,
1666                         NEOLoadPalette, NULL,
1667                         CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH))
1668	return FALSE;
1669
1670#ifndef XSERVER_LIBPCIACCESS
1671    racflag |= RAC_COLORMAP;
1672    if (nPtr->NeoHWCursorInitialized)
1673        racflag |= RAC_CURSOR;
1674
1675    pScrn->racIoFlags = pScrn->racMemFlags = racflag;
1676#endif
1677
1678    NEOInitVideo(pScreen);
1679
1680    pScreen->SaveScreen = vgaHWSaveScreenWeak();
1681
1682    /* Setup DPMS mode */
1683    if (nPtr->NeoChipset != NM2070)
1684	xf86DPMSInit(pScreen, (DPMSSetProcPtr)NeoDisplayPowerManagementSet,
1685		     0);
1686
1687    pScrn->memPhysBase = (unsigned long)nPtr->NeoLinearAddr;
1688    pScrn->fbOffset = 0;
1689
1690    /* Wrap the current CloseScreen function */
1691    nPtr->CloseScreen = pScreen->CloseScreen;
1692    pScreen->CloseScreen = NEOCloseScreen;
1693
1694    /* Report any unused options (only for the first generation) */
1695    if (serverGeneration == 1) {
1696	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1697    }
1698
1699    return TRUE;
1700}
1701
1702/* Mandatory */
1703Bool
1704NEOSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
1705{
1706    return neoModeInit(xf86Screens[scrnIndex], mode);
1707}
1708
1709/* Mandatory */
1710void
1711NEOAdjustFrame(int scrnIndex, int x, int y, int flags)
1712{
1713    ScrnInfoPtr pScrn;
1714    NEOPtr nPtr;
1715    vgaHWPtr hwp;
1716    int oldExtCRTDispAddr;
1717    int Base;
1718
1719    pScrn = xf86Screens[scrnIndex];
1720    hwp = VGAHWPTR(pScrn);
1721    nPtr = NEOPTR(pScrn);
1722
1723    if (nPtr->showcache && y) {
1724	int lastline = nPtr->NeoFbMapSize /
1725	    ((pScrn->displayWidth * pScrn->bitsPerPixel) / 8);
1726
1727	lastline -= pScrn->currentMode->VDisplay;
1728	y += pScrn->virtualY - 1;
1729        if (y > lastline) y = lastline;
1730    }
1731
1732    Base = (y * pScrn->displayWidth + x) >> 2;
1733
1734    /* Scale Base by the number of bytes per pixel. */
1735    switch (pScrn->depth) {
1736    case  8 :
1737	break;
1738    case 15 :
1739    case 16 :
1740	Base *= 2;
1741	break;
1742    case 24 :
1743	Base *= 3;
1744	break;
1745    default :
1746	break;
1747    }
1748    /*
1749     * These are the generic starting address registers.
1750     */
1751    VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
1752    VGAwCR(0x0D, (Base & 0x00FF));
1753
1754    /*
1755     * Make sure we don't clobber some other bits that might already
1756     * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
1757     * be needed.
1758     */
1759    oldExtCRTDispAddr = VGArGR(0x0E);
1760    VGAwGR(0x0E,(((Base >> 16) & 0x07) | (oldExtCRTDispAddr & 0xf8)));
1761#if 0
1762    /*
1763     * This is a workaround for a higher level bug that causes the cursor
1764     * to be at the wrong position after a virtual screen resolution change
1765     */
1766    if (nPtr->NeoHWCursorInitialized) { /*§§§ do we still need this?*/
1767	NeoRepositionCursor();
1768    }
1769#endif
1770}
1771
1772/* Mandatory */
1773static Bool
1774NEOCloseScreen(int scrnIndex, ScreenPtr pScreen)
1775{
1776    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1777    NEOPtr nPtr = NEOPTR(pScrn);
1778
1779    if(pScrn->vtSema){
1780	if (nPtr->NeoHWCursorShown)
1781	    NeoHideCursor(pScrn);
1782	neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
1783
1784	neoLock(pScrn);
1785	neoUnmapMem(pScrn);
1786    }
1787    if (nPtr->AccelInfoRec)
1788	XAADestroyInfoRec(nPtr->AccelInfoRec);
1789    if (nPtr->CursorInfo)
1790	xf86DestroyCursorInfoRec(nPtr->CursorInfo);
1791    if (nPtr->ShadowPtr)
1792	xfree(nPtr->ShadowPtr);
1793
1794    pScrn->vtSema = FALSE;
1795    pScreen->CloseScreen = nPtr->CloseScreen;
1796    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
1797}
1798
1799/* Optional */
1800static void
1801NEOFreeScreen(int scrnIndex, int flags)
1802{
1803    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
1804	vgaHWFreeHWRec(xf86Screens[scrnIndex]);
1805    NEOFreeRec(xf86Screens[scrnIndex]);
1806}
1807
1808/* Optional */
1809static ModeStatus
1810NEOValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
1811{
1812    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1813    NEOPtr nPtr = NEOPTR(pScrn);
1814    int vDisplay = mode->VDisplay * ((mode->Flags & V_DBLSCAN) ? 2 : 1);
1815
1816    /*
1817     * Is there any LineCompare Bit 10? Where?
1818     * The 9 well known VGA bits give us a maximum height of 1024
1819     */
1820    if (vDisplay > 1024)
1821	return MODE_BAD;
1822
1823    /*
1824     * Limit the modes to just those allowed by the various NeoMagic
1825     * chips.
1826     */
1827
1828    if (nPtr->overrideValidate) {
1829	xf86DrvMsg(scrnIndex, X_WARNING, "display mode validation disabled\n");
1830    } else {
1831	/*
1832	 * When the LCD is active, only allow modes that are (1) equal to
1833	 * or smaller than the size of the panel and (2) are one of the
1834	 * following sizes: 1024x768, 800x600, 640x480.
1835	 */
1836	if (nPtr->internDisp || !nPtr->externDisp) {
1837	    /* Is the mode larger than the LCD panel? */
1838	    if ((mode->HDisplay > nPtr->NeoPanelWidth) ||
1839		(vDisplay > nPtr->NeoPanelHeight)) {
1840		xf86DrvMsg(scrnIndex,X_INFO, "Removing mode (%dx%d) "
1841			   "larger than the LCD panel (%dx%d)\n",
1842			   mode->HDisplay,
1843			   mode->VDisplay,
1844			   nPtr->NeoPanelWidth,
1845			   nPtr->NeoPanelHeight);
1846		return(MODE_BAD);
1847	    }
1848
1849	    /* Is the mode one of the acceptable sizes? */
1850	    switch (mode->HDisplay) {
1851	    case 1280:
1852		if (mode->VDisplay == 1024)
1853		    return(MODE_OK);
1854		break;
1855	    case 1024 :
1856		if (mode->VDisplay == 768)
1857		    return(MODE_OK);
1858		if ((mode->VDisplay == 480) && (nPtr->NeoPanelHeight == 480))
1859		    return(MODE_OK);
1860		break;
1861	    case  800 :
1862		if (mode->VDisplay == 600)
1863		    return(MODE_OK);
1864		if ((mode->VDisplay == 480) && (nPtr->NeoPanelHeight == 480))
1865		    return(MODE_OK);
1866		break;
1867	    case  640 :
1868		if (mode->VDisplay == 480)
1869		    return(MODE_OK);
1870		break;
1871#if 1
1872	    case 320:
1873		if (mode->VDisplay == 240)
1874		    return(MODE_OK);
1875		break;
1876#endif
1877	    default:
1878		break;
1879	    }
1880
1881	    xf86DrvMsg(scrnIndex, X_INFO, "Removing mode (%dx%d) that won't "
1882		       "display properly on LCD\n",
1883		       mode->HDisplay,
1884		       mode->VDisplay);
1885	    return(MODE_BAD);
1886	}
1887    }
1888    return(MODE_OK);
1889}
1890
1891static void
1892neoLock(ScrnInfoPtr pScrn)
1893{
1894    vgaHWPtr hwp = VGAHWPTR(pScrn);
1895
1896    VGAwGR(0x09,0x00);
1897    vgaHWLock(hwp);
1898}
1899
1900static void
1901neoUnlock(ScrnInfoPtr pScrn)
1902{
1903    vgaHWPtr hwp = VGAHWPTR(pScrn);
1904
1905    vgaHWUnlock(hwp);
1906    VGAwGR(0x09,0x26);
1907}
1908
1909static Bool
1910neoMapMem(ScrnInfoPtr pScrn)
1911{
1912    NEOPtr nPtr = NEOPTR(pScrn);
1913    vgaHWPtr hwp = VGAHWPTR(pScrn);
1914
1915    if (!nPtr->noMMIO) {
1916        if (nPtr->pEnt->location.type == BUS_PCI){
1917
1918#ifndef XSERVER_LIBPCIACCESS
1919            nPtr->NeoMMIOBase =
1920                xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
1921                              nPtr->PciTag, nPtr->NeoMMIOAddr,
1922                              0x200000L);
1923            if (nPtr->NeoMMIOAddr2 != 0){
1924                nPtr->NeoMMIOBase2 =
1925                    xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
1926                                  nPtr->PciTag, nPtr->NeoMMIOAddr2,
1927                                  0x100000L);
1928            }
1929
1930#else
1931            void** result = (void**)&nPtr->NeoMMIOBase;
1932            int err = pci_device_map_range(nPtr->PciInfo,
1933                                           nPtr->NeoMMIOAddr,
1934                                           0x200000L,
1935                                           PCI_DEV_MAP_FLAG_WRITABLE,
1936                                           result);
1937            if (err)
1938                return FALSE;
1939
1940            if (nPtr->NeoMMIOAddr2 != 0){
1941                result = (void**)&nPtr->NeoMMIOBase2;
1942                err = pci_device_map_range(nPtr->PciInfo,
1943                                               nPtr->NeoMMIOAddr2,
1944                                               0x100000L,
1945                                               PCI_DEV_MAP_FLAG_WRITABLE,
1946                                               result);
1947
1948                if (err)
1949                    return FALSE;
1950            }
1951#endif
1952        } else
1953            nPtr->NeoMMIOBase =
1954                xf86MapVidMem(pScrn->scrnIndex,
1955                              VIDMEM_MMIO, nPtr->NeoMMIOAddr,
1956                              0x200000L);
1957        if (nPtr->NeoMMIOBase == NULL)
1958            return FALSE;
1959    }
1960
1961    if (nPtr->pEnt->location.type == BUS_PCI)
1962
1963#ifndef XSERVER_LIBPCIACCESS
1964        nPtr->NeoFbBase =
1965            xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1966                          nPtr->PciTag,
1967                          (unsigned long)nPtr->NeoLinearAddr,
1968                          nPtr->NeoFbMapSize);
1969#else
1970    {
1971        void** result = (void**)&nPtr->NeoFbBase;
1972        int err = pci_device_map_range(nPtr->PciInfo,
1973                                       nPtr->NeoLinearAddr,
1974                                       nPtr->NeoFbMapSize,
1975                                       PCI_DEV_MAP_FLAG_WRITABLE |
1976                                       PCI_DEV_MAP_FLAG_WRITE_COMBINE,
1977                                       result);
1978        if (err)
1979            return FALSE;
1980    }
1981#endif
1982    else
1983        nPtr->NeoFbBase =
1984            xf86MapVidMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1985                          (unsigned long)nPtr->NeoLinearAddr,
1986                          nPtr->NeoFbMapSize);
1987    if (nPtr->NeoFbBase == NULL)
1988        return FALSE;
1989    return TRUE;
1990}
1991
1992/*
1993 * Unmap the framebuffer and MMIO memory.
1994 */
1995
1996static Bool
1997neoUnmapMem(ScrnInfoPtr pScrn)
1998{
1999    NEOPtr nPtr = NEOPTR(pScrn);
2000
2001#ifndef XSERVER_LIBPCIACCESS
2002    if (nPtr->NeoMMIOBase)
2003        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase,
2004                        0x200000L);
2005#else
2006    if (nPtr->NeoMMIOBase)
2007        pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoMMIOBase, 0x200000L);
2008#endif
2009    nPtr->NeoMMIOBase = NULL;
2010#ifndef XSERVER_LIBPCIACCESS
2011    if (nPtr->NeoMMIOBase2)
2012        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase2,
2013                        0x100000L);
2014#else
2015    if (nPtr->NeoMMIOBase2)
2016        pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoMMIOBase2, 0x100000L);
2017#endif
2018    nPtr->NeoMMIOBase2 = NULL;
2019#ifndef XSERVER_LIBPCIACCESS
2020    xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoFbBase,
2021                    nPtr->NeoFbMapSize);
2022#else
2023    pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoFbBase, nPtr->NeoFbMapSize);
2024#endif
2025    nPtr->NeoFbBase = NULL;
2026
2027    return TRUE;
2028}
2029
2030static void
2031neoSave(ScrnInfoPtr pScrn)
2032{
2033    vgaRegPtr VgaSave = &VGAHWPTR(pScrn)->SavedReg;
2034    vgaHWPtr hwp = VGAHWPTR(pScrn);
2035    NEOPtr nPtr = NEOPTR(pScrn);
2036    NeoRegPtr save;
2037    int i;
2038
2039    save = &nPtr->NeoSavedReg;
2040
2041    VGAwGR(0x09,0x26);
2042    /*
2043     * Whatever code is needed to get back to bank zero goes here.
2044     */
2045    VGAwGR(0x15,0x00);
2046
2047    /* get generic registers */
2048    vgaHWSave(pScrn, VgaSave, VGA_SR_ALL);
2049
2050    /*
2051     * The port I/O code necessary to read in the extended registers
2052     * into the fields of the vgaNeoRec structure goes here.
2053     */
2054
2055    save->GeneralLockReg = VGArGR(0x0A);
2056
2057    save->ExtCRTDispAddr = VGArGR(0x0E);
2058    if (nPtr->NeoChipset != NM2070) {
2059	save->ExtCRTOffset = VGArGR(0x0F);
2060    }
2061    save->SysIfaceCntl1 = VGArGR(0x10);
2062    save->SysIfaceCntl2 = VGArGR(0x11);
2063    save->SingleAddrPage = VGArGR(0x15);
2064    save->DualAddrPage = VGArGR(0x16);
2065    save->PanelDispCntlReg1 = VGArGR(0x20);
2066    save->PanelDispCntlReg2 = VGArGR(0x25);
2067    save->PanelDispCntlReg3 = VGArGR(0x30);
2068    save->PanelVertCenterReg1 = VGArGR(0x28);
2069    save->PanelVertCenterReg2 = VGArGR(0x29);
2070    save->PanelVertCenterReg3 = VGArGR(0x2A);
2071    if (nPtr->NeoChipset != NM2070) {
2072        save->PanelVertCenterReg4 = VGArGR(0x32);
2073	save->PanelHorizCenterReg1 = VGArGR(0x33);
2074	save->PanelHorizCenterReg2 = VGArGR(0x34);
2075	save->PanelHorizCenterReg3 = VGArGR(0x35);
2076    }
2077    if (nPtr->NeoChipset == NM2160) {
2078        save->PanelHorizCenterReg4 = VGArGR(0x36);
2079    }
2080    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2081	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2082	save->PanelHorizCenterReg4 = VGArGR(0x36);
2083	save->PanelVertCenterReg5  = VGArGR(0x37);
2084	save->PanelHorizCenterReg5 = VGArGR(0x38);
2085    }
2086    save->ExtColorModeSelect = VGArGR(0x90);
2087    save->VCLK3NumeratorLow = VGArGR(0x9B);
2088    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2089	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380)
2090	save->VCLK3NumeratorHigh = VGArGR(0x8F);
2091    save->VCLK3Denominator = VGArGR(0x9F);
2092    save->ProgramVCLK = TRUE;
2093
2094    if (save->reg == NULL)
2095        save->reg = (regSavePtr)xnfcalloc(sizeof(regSaveRec), 1);
2096    else
2097        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2098		   "Non-NULL reg in NeoSave: reg=%p\n", (void *)save->reg);
2099
2100    save->reg->CR[0x23] = VGArCR(0x23);
2101    save->reg->CR[0x25] = VGArCR(0x25);
2102    save->reg->CR[0x2F] = VGArCR(0x2F);
2103    for (i = 0x40; i <= 0x59; i++) {
2104	save->reg->CR[i] = VGArCR(i);
2105    }
2106    for (i = 0x60; i <= 0x69; i++) {
2107	save->reg->CR[i] = VGArCR(i);
2108    }
2109    for (i = 0x70; i <= NEO_EXT_CR_MAX; i++) {
2110	save->reg->CR[i] = VGArCR(i);
2111    }
2112
2113    for (i = 0x0A; i <= NEO_EXT_GR_MAX; i++) {
2114        save->reg->GR[i] = VGArGR(i);
2115    }
2116}
2117
2118/*
2119 * neoProgramShadowRegs
2120 *
2121 * Setup the shadow registers to their default values.  The NeoSave
2122 * routines will restore the proper values on server exit.
2123 */
2124static void
2125neoProgramShadowRegs(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, NeoRegPtr restore)
2126{
2127    int i;
2128    Bool noProgramShadowRegs;
2129    vgaHWPtr hwp = VGAHWPTR(pScrn);
2130    NEOPtr nPtr = NEOPTR(pScrn);
2131    Bool prog_lcd;
2132
2133    /*
2134     * If display is external only and we want internal
2135     * we need to program the shadow registers.
2136     */
2137    prog_lcd = (((VGArGR(0x20) & 0x3) == 0x1) && nPtr->internDisp);
2138
2139
2140    /*
2141     * Convoluted logic for shadow register programming.
2142     *
2143     * As far as we know, shadow programming is needed for the 2070,
2144     * but not in stretched modes.  Special case this code.
2145     */
2146    switch (nPtr->NeoChipset) {
2147    case NM2070:
2148	/* Program the shadow regs by default */
2149	noProgramShadowRegs = FALSE;
2150	if (!nPtr->progLcdRegs && !prog_lcd)
2151	    noProgramShadowRegs = TRUE;
2152
2153	if (restore->PanelDispCntlReg2 & 0x84) {
2154	    /* Don't program by default if in stretch mode */
2155	    noProgramShadowRegs = TRUE;
2156	    if (nPtr->progLcdStretch)
2157		noProgramShadowRegs = FALSE;
2158	}
2159	break;
2160    case NM2090:
2161    case NM2093:
2162    case NM2097:
2163    case NM2160:
2164    case NM2200:
2165    case NM2230:
2166    case NM2360:
2167    case NM2380:
2168    default:
2169	/* Don't program the shadow regs by default */
2170	noProgramShadowRegs = TRUE;
2171	if (nPtr->progLcdRegs || prog_lcd)
2172	    noProgramShadowRegs = FALSE;
2173
2174	if (restore->PanelDispCntlReg2 & 0x84) {
2175	    /* Only change the behavior if an option is set */
2176	    if (nPtr->progLcdStretchOpt)
2177		noProgramShadowRegs = !nPtr->progLcdStretch;
2178	}
2179	break;
2180    }
2181
2182    if (noProgramShadowRegs) {
2183	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,5,"Not programming shadow registers\n");
2184	if (nPtr->NeoSavedReg.reg){
2185	    for (i = 0x40; i <= 0x59; i++) {
2186		VGAwCR(i, nPtr->NeoSavedReg.reg->CR[i]);
2187	    }
2188	    for (i = 0x60; i <= 0x64; i++) {
2189		VGAwCR(i, nPtr->NeoSavedReg.reg->CR[i]);
2190	    }
2191	}
2192    } else {
2193	/*
2194	 * Program the shadow regs based on the panel width.  This works
2195	 * fine for normal sized panels, but what about the odd ones like
2196	 * the Libretto 100 which has an 800x480 panel???
2197	 */
2198	switch (nPtr->NeoPanelWidth) {
2199	case 640 :
2200	    VGAwCR(0x40,0x5F);
2201	    VGAwCR(0x41,0x50);
2202	    VGAwCR(0x42,0x02);
2203	    VGAwCR(0x43,0x55);
2204	    VGAwCR(0x44,0x81);
2205	    VGAwCR(0x45,0x0B);
2206	    VGAwCR(0x46,0x2E);
2207	    VGAwCR(0x47,0xEA);
2208	    VGAwCR(0x48,0x0C);
2209	    VGAwCR(0x49,0xE7);
2210	    VGAwCR(0x4A,0x04);
2211	    VGAwCR(0x4B,0x2D);
2212	    VGAwCR(0x4C,0x28);
2213	    VGAwCR(0x4D,0x90);
2214	    VGAwCR(0x4E,0x2B);
2215	    VGAwCR(0x4F,0xA0);
2216	    break;
2217	case 800 :
2218	    switch (nPtr->NeoPanelHeight) {
2219	    case 600:
2220		VGAwCR(0x40,0x7F);
2221		VGAwCR(0x41,0x63);
2222		VGAwCR(0x42,0x02);
2223		VGAwCR(0x43,0x6C);
2224		VGAwCR(0x44,0x1C);
2225		VGAwCR(0x45,0x72);
2226		VGAwCR(0x46,0xE0);
2227		VGAwCR(0x47,0x58);
2228		VGAwCR(0x48,0x0C);
2229		VGAwCR(0x49,0x57);
2230		VGAwCR(0x4A,0x73);
2231		VGAwCR(0x4B,0x3D);
2232		VGAwCR(0x4C,0x31);
2233		VGAwCR(0x4D,0x01);
2234		VGAwCR(0x4E,0x36);
2235		VGAwCR(0x4F,0x1E);
2236		if (nPtr->NeoChipset != NM2070) {
2237		    VGAwCR(0x50,0x6B);
2238		    VGAwCR(0x51,0x4F);
2239		    VGAwCR(0x52,0x0E);
2240		    VGAwCR(0x53,0x58);
2241		    VGAwCR(0x54,0x88);
2242		    VGAwCR(0x55,0x33);
2243		    VGAwCR(0x56,0x27);
2244		    VGAwCR(0x57,0x16);
2245		    VGAwCR(0x58,0x2C);
2246		    VGAwCR(0x59,0x94);
2247		}
2248		break;
2249	    case 480:
2250		VGAwCR(0x40,0x7F);
2251		VGAwCR(0x41,0x63);
2252		VGAwCR(0x42,0x02);
2253		VGAwCR(0x43,0x6B);
2254		VGAwCR(0x44,0x1B);
2255		VGAwCR(0x45,0x72);
2256		VGAwCR(0x46,0xE0);
2257		VGAwCR(0x47,0x1C);
2258		VGAwCR(0x48,0x00);
2259		VGAwCR(0x49,0x57);
2260		VGAwCR(0x4A,0x73);
2261		VGAwCR(0x4B,0x3E);
2262		VGAwCR(0x4C,0x31);
2263		VGAwCR(0x4D,0x01);
2264		VGAwCR(0x4E,0x36);
2265		VGAwCR(0x4F,0x1E);
2266		VGAwCR(0x50,0x6B);
2267		VGAwCR(0x51,0x4F);
2268		VGAwCR(0x52,0x0E);
2269		VGAwCR(0x53,0x57);
2270		VGAwCR(0x54,0x87);
2271		VGAwCR(0x55,0x33);
2272		VGAwCR(0x56,0x27);
2273		VGAwCR(0x57,0x16);
2274		VGAwCR(0x58,0x2C);
2275		VGAwCR(0x59,0x94);
2276		break;
2277		break;
2278		/* Not done */
2279	    }
2280	    break;
2281	case 1024 :
2282	    switch (nPtr->NeoPanelHeight) {
2283	    case 768:
2284		VGAwCR(0x40,0xA3);
2285		VGAwCR(0x41,0x7F);
2286		VGAwCR(0x42,0x06);
2287		VGAwCR(0x43,0x85);
2288		VGAwCR(0x44,0x96);
2289		VGAwCR(0x45,0x24);
2290		VGAwCR(0x46,0xE5);
2291		VGAwCR(0x47,0x02);
2292		VGAwCR(0x48,0x08);
2293		VGAwCR(0x49,0xFF);
2294		VGAwCR(0x4A,0x25);
2295		VGAwCR(0x4B,0x4F);
2296		VGAwCR(0x4C,0x40);
2297		VGAwCR(0x4D,0x00);
2298		VGAwCR(0x4E,0x44);
2299		VGAwCR(0x4F,0x0C);
2300		VGAwCR(0x50,0x7A);
2301		VGAwCR(0x51,0x56);
2302		VGAwCR(0x52,0x00);
2303		VGAwCR(0x53,0x5D);
2304		VGAwCR(0x54,0x0E);
2305		VGAwCR(0x55,0x3B);
2306		VGAwCR(0x56,0x2B);
2307		VGAwCR(0x57,0x00);
2308		VGAwCR(0x58,0x2F);
2309		VGAwCR(0x59,0x18);
2310		VGAwCR(0x60,0x88);
2311		VGAwCR(0x61,0x63);
2312		VGAwCR(0x62,0x0B);
2313		VGAwCR(0x63,0x69);
2314		VGAwCR(0x64,0x1A);
2315		break;
2316	    case 480:
2317		VGAwCR(0x40,0xA3);
2318		VGAwCR(0x41,0x7F);
2319		VGAwCR(0x42,0x1B);
2320		VGAwCR(0x43,0x89);
2321		VGAwCR(0x44,0x16);
2322		VGAwCR(0x45,0x0B);
2323		VGAwCR(0x46,0x2C);
2324		VGAwCR(0x47,0xE8);
2325		VGAwCR(0x48,0x0C);
2326		VGAwCR(0x49,0xE7);
2327		VGAwCR(0x4A,0x09);
2328		VGAwCR(0x4B,0x4F);
2329		VGAwCR(0x4C,0x40);
2330		VGAwCR(0x4D,0x00);
2331		VGAwCR(0x4E,0x44);
2332		VGAwCR(0x4F,0x0C);
2333		VGAwCR(0x50,0x7A);
2334		VGAwCR(0x51,0x56);
2335		VGAwCR(0x52,0x00);
2336		VGAwCR(0x53,0x5D);
2337		VGAwCR(0x54,0x0E);
2338		VGAwCR(0x55,0x3B);
2339		VGAwCR(0x56,0x2A);
2340		VGAwCR(0x57,0x00);
2341		VGAwCR(0x58,0x2F);
2342		VGAwCR(0x59,0x18);
2343		VGAwCR(0x60,0x88);
2344		VGAwCR(0x61,0x63);
2345		VGAwCR(0x62,0x0B);
2346		VGAwCR(0x63,0x69);
2347		VGAwCR(0x64,0x1A);
2348		break;
2349	    }
2350	    break;
2351	case 1280:
2352#ifdef NOT_DONE
2353	    VGAwCR(0x40,0x?? );
2354            .
2355		.
2356		.
2357		VGAwCR(0x64,0x?? );
2358		break;
2359#else
2360		/* Probe should prevent this case for now */
2361		FatalError("1280 panel support incomplete\n");
2362#endif
2363	}
2364    }
2365}
2366
2367static void
2368neoRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, NeoRegPtr restore,
2369	     Bool restoreText)
2370{
2371    NEOPtr nPtr = NEOPTR(pScrn);
2372    vgaHWPtr hwp = VGAHWPTR(pScrn);
2373    unsigned char temp;
2374    int i;
2375    Bool clock_hi = FALSE;
2376
2377    vgaHWProtect(pScrn,TRUE);		/* Blank the screen */
2378
2379    VGAwGR(0x09,0x26);
2380
2381    /* Init the shadow registers if necessary */
2382    neoProgramShadowRegs(pScrn, VgaReg, restore);
2383
2384    VGAwGR(0x15,0x00);
2385
2386    VGAwGR(0x0A,restore->GeneralLockReg);
2387
2388    /*
2389     * The color mode needs to be set before calling vgaHWRestore
2390     * to ensure the DAC is initialized properly.
2391     *
2392     * NOTE: Make sure we don't change bits make sure we don't change
2393     * any reserved bits.
2394     */
2395    temp = VGArGR(0x90);
2396
2397    switch (nPtr->NeoChipset) {
2398    case NM2070 :
2399	temp &= 0xF0; /* Save bits 7:4 */
2400	temp |= (restore->ExtColorModeSelect & ~0xF0);
2401	break;
2402    case NM2090 :
2403    case NM2093 :
2404    case NM2097 :
2405    case NM2160 :
2406    case NM2200 :
2407    case NM2230 :
2408    case NM2360 :
2409    case NM2380 :
2410	temp &= 0x70; /* Save bits 6:4 */
2411	temp |= (restore->ExtColorModeSelect & ~0x70);
2412	break;
2413    }
2414    VGAwGR(0x90,temp);
2415
2416    /*
2417     * In some rare cases a lockup might occur if we don't delay
2418     * here. (Reported by Miles Lane)
2419     */
2420    usleep(200000);
2421    /*
2422     * Disable horizontal and vertical graphics and text expansions so
2423     * that vgaHWRestore works properly.
2424     */
2425    temp = VGArGR(0x25);
2426    temp &= 0x39;
2427    VGAwGR(0x25, temp);
2428
2429    /*
2430     * Sleep for 200ms to make sure that the two operations above have
2431     * had time to take effect.
2432     */
2433    usleep(200000);
2434    /*
2435     * This function handles restoring the generic VGA registers.  */
2436    vgaHWRestore(pScrn, VgaReg,
2437		 VGA_SR_MODE
2438		 | (restoreText ? (VGA_SR_FONTS | VGA_SR_CMAP) : 0));
2439
2440    VGAwGR(0x0E, restore->ExtCRTDispAddr);
2441    VGAwGR(0x0F, restore->ExtCRTOffset);
2442    temp = VGArGR(0x10);
2443    temp &= 0x0F; /* Save bits 3:0 */
2444    temp |= (restore->SysIfaceCntl1 & ~0x0F);
2445    VGAwGR(0x10, temp);
2446
2447    VGAwGR(0x11, restore->SysIfaceCntl2);
2448    VGAwGR(0x15, restore->SingleAddrPage);
2449    VGAwGR(0x16, restore->DualAddrPage);
2450
2451    temp = VGArGR(0x20);
2452    switch (nPtr->NeoChipset) {
2453    case NM2070 :
2454	temp &= 0xFC; /* Save bits 7:2 */
2455	temp |= (restore->PanelDispCntlReg1 & ~0xFC);
2456	break;
2457    case NM2090 :
2458    case NM2093 :
2459    case NM2097 :
2460    case NM2160 :
2461	temp &= 0xDC; /* Save bits 7:6,4:2 */
2462	temp |= (restore->PanelDispCntlReg1 & ~0xDC);
2463	break;
2464    case NM2200 :
2465    case NM2230 :
2466    case NM2360 :
2467    case NM2380 :
2468	temp &= 0x98; /* Save bits 7,4:3 */
2469	temp |= (restore->PanelDispCntlReg1 & ~0x98);
2470	break;
2471    }
2472    VGAwGR(0x20, temp);
2473
2474    temp = VGArGR(0x25);
2475    temp &= 0x38; /* Save bits 5:3 */
2476    temp |= (restore->PanelDispCntlReg2 & ~0x38);
2477    VGAwGR(0x25, temp);
2478
2479    if (nPtr->NeoChipset != NM2070) {
2480	temp = VGArGR(0x30);
2481	temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
2482	temp |= (restore->PanelDispCntlReg3 & ~0xEF);
2483	VGAwGR(0x30, temp);
2484    }
2485
2486    VGAwGR(0x28, restore->PanelVertCenterReg1);
2487    VGAwGR(0x29, restore->PanelVertCenterReg2);
2488    VGAwGR(0x2a, restore->PanelVertCenterReg3);
2489
2490    if (nPtr->NeoChipset != NM2070) {
2491	VGAwGR(0x32, restore->PanelVertCenterReg4);
2492	VGAwGR(0x33, restore->PanelHorizCenterReg1);
2493	VGAwGR(0x34, restore->PanelHorizCenterReg2);
2494	VGAwGR(0x35, restore->PanelHorizCenterReg3);
2495    }
2496
2497    if (nPtr->NeoChipset == NM2160) {
2498	VGAwGR(0x36, restore->PanelHorizCenterReg4);
2499    }
2500
2501    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2502	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2503        VGAwGR(0x36, restore->PanelHorizCenterReg4);
2504        VGAwGR(0x37, restore->PanelVertCenterReg5);
2505        VGAwGR(0x38, restore->PanelHorizCenterReg5);
2506    }
2507    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2508	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380)
2509	clock_hi = TRUE;
2510
2511    /* Program VCLK3 if needed. */
2512    if (restore->ProgramVCLK
2513	 && ((VGArGR(0x9B) != restore->VCLK3NumeratorLow)
2514	    || (VGArGR(0x9F) !=  restore->VCLK3Denominator)
2515	    || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
2516			     != (restore->VCLK3NumeratorHigh & ~0x0F))))) {
2517	VGAwGR(0x9B, restore->VCLK3NumeratorLow);
2518	if (clock_hi) {
2519	    temp = VGArGR(0x8F);
2520	    temp &= 0x0F; /* Save bits 3:0 */
2521	    temp |= (restore->VCLK3NumeratorHigh & ~0x0F);
2522	    VGAwGR(0x8F, temp);
2523	}
2524	VGAwGR(0x9F, restore->VCLK3Denominator);
2525    }
2526    if (restore->biosMode)
2527	VGAwCR(0x23,restore->biosMode);
2528
2529    if (restore->reg) {
2530	VGAwCR(0x23,restore->reg->CR[0x23]);
2531	VGAwCR(0x25,restore->reg->CR[0x25]);
2532	VGAwCR(0x2F,restore->reg->CR[0x2F]);
2533	for (i = 0x40; i <= 0x59; i++) {
2534	    VGAwCR(i, restore->reg->CR[i]);
2535	}
2536	for (i = 0x60; i <= 0x69; i++) {
2537	    VGAwCR(i, restore->reg->CR[i]);
2538	}
2539	for (i = 0x70; i <= NEO_EXT_CR_MAX; i++) {
2540	    VGAwCR(i, restore->reg->CR[i]);
2541	}
2542
2543	for (i = 0x0a; i <= 0x3f; i++) {
2544	    VGAwGR(i, restore->reg->GR[i]);
2545	}
2546	for (i = 0x90; i <= NEO_EXT_GR_MAX; i++) {
2547	    VGAwGR(i, restore->reg->GR[i]);
2548	}
2549    }
2550
2551    VGAwGR (0x93, 0xc0); /* Gives faster framebuffer writes */
2552
2553    /* Program vertical extension register */
2554    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2555	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2556	VGAwCR(0x70, restore->VerticalExt);
2557    }
2558
2559    vgaHWProtect(pScrn, FALSE);		/* Turn on screen */
2560}
2561
2562static Bool
2563neoModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
2564{
2565    NEOPtr nPtr = NEOPTR(pScrn);
2566    NEOACLPtr nAcl = NEOACLPTR(pScrn);
2567    int hoffset, voffset;
2568    vgaHWPtr hwp = VGAHWPTR(pScrn);
2569    NeoRegPtr NeoNew = &nPtr->NeoModeReg;
2570    vgaRegPtr NeoStd = &hwp->ModeReg;
2571    Bool noLcdStretch = nPtr->noLcdStretch;
2572    int clockMul = 1;
2573
2574    neoUnlock(pScrn);
2575
2576    /*
2577     * This will allocate the datastructure and initialize all of the
2578     * generic VGA registers.
2579     */
2580
2581    if (!vgaHWInit(pScrn, mode))
2582	return(FALSE);
2583
2584    /*
2585     * Several registers need to be corrected from the default values
2586     * assigned by vgaHWinit().
2587     */
2588    pScrn->vtSema = TRUE;
2589
2590    /*
2591     * The default value assigned by vgaHW.c is 0x41, but this does
2592     * not work for NeoMagic.
2593     */
2594    NeoStd->Attribute[16] = 0x01;
2595
2596    switch (pScrn->depth) {
2597    case  8 :
2598	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 3;
2599	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 11;
2600	NeoNew->ExtColorModeSelect = 0x11;
2601	break;
2602    case 15 :
2603        NeoNew->ExtColorModeSelect = 0x12;
2604	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 2;
2605	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 10;
2606        break;
2607    case 16 :
2608        NeoNew->ExtColorModeSelect = 0x13;
2609	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 2;
2610	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 10;
2611	break;
2612    case 24 :
2613	NeoStd->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3;
2614	NeoNew->ExtCRTOffset   = (pScrn->displayWidth * 3) >> 11;
2615	NeoNew->ExtColorModeSelect = 0x14;
2616	break;
2617    default :
2618	break;
2619    }
2620
2621    NeoNew->ExtCRTDispAddr = 0x10;
2622
2623    /* Vertical Extension */
2624    NeoNew->VerticalExt = (((mode->CrtcVTotal -2) & 0x400) >> 10 )
2625      | (((mode->CrtcVDisplay -1) & 0x400) >> 9 )
2626        | (((mode->CrtcVSyncStart) & 0x400) >> 8 )
2627          | (((mode->CrtcVBlankStart - 1) & 0x400) >> 7 );
2628
2629    /* Fast write bursts on unless disabled. */
2630    if (nPtr->onPciBurst) {
2631	NeoNew->SysIfaceCntl1 = 0x30;
2632    } else {
2633	NeoNew->SysIfaceCntl1 = 0x00;
2634    }
2635
2636    /* If they are used, enable linear addressing and/or enable MMIO. */
2637    NeoNew->SysIfaceCntl2 = 0x00;
2638    NeoNew->SysIfaceCntl2 |= 0x80;
2639    if (!nPtr->noMMIO)
2640	NeoNew->SysIfaceCntl2 |= 0x40;
2641
2642    /* Enable any user specified display devices. */
2643    NeoNew->PanelDispCntlReg1 = 0x00;
2644    if (nPtr->internDisp) {
2645	NeoNew->PanelDispCntlReg1 |= 0x02;
2646    }
2647    if (nPtr->externDisp) {
2648	NeoNew->PanelDispCntlReg1 |= 0x01;
2649    }
2650
2651#if 0
2652    /*
2653     * This was replaced: if no devices are specified take the
2654     * probed settings. If the probed settings are bogus fallback
2655     * to internal only.
2656     */
2657    /* If the user did not specify any display devices, then... */
2658    if (NeoNew->PanelDispCntlReg1 == 0x00) {
2659	/* Default to internal (i.e., LCD) only. */
2660	NeoNew->PanelDispCntlReg1 |= 0x02;
2661    }
2662#endif
2663    /* If we are using a fixed mode, then tell the chip we are. */
2664    switch (mode->HDisplay) {
2665    case 1280:
2666	NeoNew->PanelDispCntlReg1 |= 0x60;
2667        break;
2668    case 1024:
2669	NeoNew->PanelDispCntlReg1 |= 0x40;
2670        break;
2671    case 800:
2672	NeoNew->PanelDispCntlReg1 |= 0x20;
2673        break;
2674    case 640:
2675    default:
2676        break;
2677    }
2678
2679    /* Setup shadow register locking. */
2680    switch (NeoNew->PanelDispCntlReg1 & 0x03) {
2681    case 0x01 : /* External CRT only mode: */
2682	NeoNew->GeneralLockReg = 0x00;
2683	/* We need to program the VCLK for external display only mode. */
2684	NeoNew->ProgramVCLK = TRUE;
2685	break;
2686    case 0x02 : /* Internal LCD only mode: */
2687    case 0x03 : /* Simultaneous internal/external (LCD/CRT) mode: */
2688	NeoNew->GeneralLockReg = 0x01;
2689	/* Don't program the VCLK when using the LCD. */
2690	NeoNew->ProgramVCLK = FALSE;
2691	break;
2692    }
2693
2694    /*
2695     * If the screen is to be stretched, turn on stretching for the
2696     * various modes.
2697     *
2698     * OPTION_LCD_STRETCH means stretching should be turned off!
2699     */
2700    NeoNew->PanelDispCntlReg2 = 0x00;
2701    NeoNew->PanelDispCntlReg3 = 0x00;
2702    nAcl->NoCursorMode = FALSE;
2703
2704    if ((!noLcdStretch) &&
2705	(NeoNew->PanelDispCntlReg1 & 0x02)) {
2706	if (mode->HDisplay == nPtr->NeoPanelWidth) {
2707	    /*
2708	     * Don't disable the flag.  It will be needed if another mode
2709	     * is selected.
2710	     */
2711	    /*
2712	     * No stretching required when the requested display width
2713	     * equals the panel width.
2714	     */
2715	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Stretching disabled\n");
2716	        noLcdStretch = TRUE;
2717	} else {
2718
2719	    switch (mode->HDisplay) {
2720	    case  320 : /* Needs testing.  KEM -- 24 May 98 */
2721	    case  400 : /* Needs testing.  KEM -- 24 May 98 */
2722	    case  640 :
2723	    case  800 :
2724	    case 1024 :
2725		NeoNew->PanelDispCntlReg2 |= 0xC6;
2726		nAcl->NoCursorMode = TRUE;
2727		break;
2728	    default   :
2729		/* No stretching in these modes. */
2730		xf86DrvMsg(pScrn->scrnIndex,X_INFO,
2731			   "Stretching disabled not supported in this mode\n");
2732		noLcdStretch = TRUE;
2733		break;
2734	    }
2735	}
2736    } else if (mode->Flags & V_DBLSCAN) {
2737	nAcl->NoCursorMode = TRUE;
2738    }
2739
2740    /*
2741     * If the screen is to be centerd, turn on the centering for the
2742     * various modes.
2743     */
2744    NeoNew->PanelVertCenterReg1  = 0x00;
2745    NeoNew->PanelVertCenterReg2  = 0x00;
2746    NeoNew->PanelVertCenterReg3  = 0x00;
2747    NeoNew->PanelVertCenterReg4  = 0x00;
2748    NeoNew->PanelVertCenterReg5  = 0x00;
2749    NeoNew->PanelHorizCenterReg1 = 0x00;
2750    NeoNew->PanelHorizCenterReg2 = 0x00;
2751    NeoNew->PanelHorizCenterReg3 = 0x00;
2752    NeoNew->PanelHorizCenterReg4 = 0x00;
2753    NeoNew->PanelHorizCenterReg5 = 0x00;
2754
2755    if (nPtr->lcdCenter &&
2756	(NeoNew->PanelDispCntlReg1 & 0x02)) {
2757	Bool doCenter = FALSE;
2758
2759	hoffset = 0;
2760	voffset = 0;
2761	if (mode->HDisplay == nPtr->NeoPanelWidth) {
2762	    /*
2763	     * No centering required when the requested display width
2764	     * equals the panel width.
2765	     */
2766	} else {
2767	    NeoNew->PanelDispCntlReg3 |= 0x10;
2768	    if (noLcdStretch) {
2769		/* Calculate the horizontal offsets. */
2770		int HDisplay = mode->HDisplay
2771		    << ((mode->VDisplay < 480) ? 1 : 0);
2772		hoffset = ((nPtr->NeoPanelWidth - HDisplay) >> 4) - 1;
2773		if (mode->VDisplay < 480)
2774		    hoffset >>= 1;
2775		doCenter = TRUE;
2776	    } else {
2777		/* Stretched modes cannot be centered. */
2778		hoffset = 0;
2779	    }
2780	}
2781	if (mode->VDisplay == nPtr->NeoPanelHeight) {
2782	    /*
2783	     * No centering required when the requested display width
2784	     * equals the panel width.
2785	     */
2786	} else {
2787	    NeoNew->PanelDispCntlReg2 |= 0x01;
2788	    if (noLcdStretch) {
2789		/* Calculate the vertical offsets. */
2790		int VDisplay = mode->VDisplay
2791		    << ((mode->Flags & V_DBLSCAN) ? 1 : 0);
2792		voffset = ((nPtr->NeoPanelHeight - VDisplay) >> 1) - 2;
2793		doCenter = TRUE;
2794	    } else {
2795		/* Stretched modes cannot be centered. */
2796		voffset = 0;
2797	    }
2798	}
2799
2800	if (doCenter) {
2801	    switch (mode->HDisplay) {
2802	    case  320 : /* Needs testing.  KEM -- 24 May 98 */
2803  		NeoNew->PanelHorizCenterReg3 = hoffset;
2804		NeoNew->PanelVertCenterReg3  = voffset;
2805		break;
2806	    case  400 : /* Needs testing.  KEM -- 24 May 98 */
2807		NeoNew->PanelHorizCenterReg4 = hoffset;
2808		NeoNew->PanelVertCenterReg1  = voffset;
2809		break;
2810	    case  640 :
2811		NeoNew->PanelHorizCenterReg1 = hoffset;
2812		NeoNew->PanelVertCenterReg3  = voffset;
2813		break;
2814	    case  800 :
2815		NeoNew->PanelHorizCenterReg2 = hoffset;
2816		switch (mode->VDisplay) {
2817		case 600:
2818		    NeoNew->PanelVertCenterReg4  = voffset;
2819		    break;
2820		case 480:
2821		    /* Not sure if this is correct */
2822		    NeoNew->PanelVertCenterReg3  = voffset;
2823		    break;
2824		}
2825		break;
2826	    case 1024 :
2827		NeoNew->PanelHorizCenterReg5 = hoffset;
2828		NeoNew->PanelVertCenterReg5  = voffset;
2829		break;
2830	    case 1280 :
2831	    default   :
2832		/* No centering in these modes. */
2833		break;
2834	    }
2835	}
2836    }
2837
2838    if (!noLcdStretch &&
2839	(NeoNew->PanelDispCntlReg1 & 0x02))  {
2840	if (mode->HDisplay != nPtr->NeoPanelWidth)
2841	    nPtr->videoHZoom = (double)nPtr->NeoPanelWidth/mode->HDisplay;
2842	if (mode->VDisplay != nPtr->NeoPanelHeight)
2843	    nPtr->videoVZoom = (double)nPtr->NeoPanelHeight/mode->VDisplay;
2844    } else {
2845	nPtr->videoHZoom = 1.0;
2846	nPtr->videoVZoom = 1.0;
2847    }
2848    /* Do double scan */
2849    if (mode->VDisplay < 480) {
2850	NeoStd->Sequencer[1] |= 0x8;
2851	clockMul = 2;
2852    }
2853
2854    NeoNew->biosMode = neoFindMode(mode->HDisplay,mode->VDisplay,pScrn->depth);
2855
2856    /*
2857     * New->reg should be empty.  Just in
2858     * case it isn't, warn us and clear it anyway.
2859     */
2860    if (NeoNew->reg) {
2861	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2862		   "Non-NULL reg in NeoInit: reg=%p\n", (void *)NeoNew->reg);
2863	xfree(NeoNew->reg);
2864	NeoNew->reg = NULL;
2865    }
2866
2867    /*
2868     * Calculate the VCLK that most closely matches the requested dot
2869     * clock.
2870     */
2871    neoCalcVCLK(pScrn, mode->SynthClock*clockMul);
2872
2873    /* Since we program the clocks ourselves, always use VCLK3. */
2874    NeoStd->MiscOutReg |= 0x0C;
2875
2876    neoRestore(pScrn, NeoStd, NeoNew, FALSE);
2877
2878    return(TRUE);
2879}
2880
2881/*
2882 * neoCalcVCLK --
2883 *
2884 * Determine the closest clock frequency to the one requested.
2885 */
2886#define REF_FREQ 14.31818
2887#define MAX_N 127
2888#define MAX_D 31
2889#define MAX_F 1
2890
2891static void
2892neoCalcVCLK(ScrnInfoPtr pScrn, long freq)
2893{
2894    NEOPtr nPtr = NEOPTR(pScrn);
2895
2896    int n, d, f;
2897    double f_out;
2898    double f_diff;
2899    int n_best = 0, d_best = 1, f_best = 0;
2900    double f_best_diff = 999999.0;
2901    double f_target = freq/1000.0;
2902
2903    for (f = 0; f <= MAX_F; f++)
2904	for (n = 0; n <= MAX_N; n++)
2905	    for (d = 1; d <= MAX_D; d++) {
2906		f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
2907		f_diff = abs(f_out-f_target);
2908		if (f_diff < f_best_diff) {
2909		    f_best_diff = f_diff;
2910		    n_best = n;
2911		    d_best = d;
2912		    f_best = f;
2913		}
2914	    }
2915
2916    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2917	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2918        /* NOT_DONE:  We are trying the full range of the 2200 clock.
2919           We should be able to try n up to 2047 */
2920	nPtr->NeoModeReg.VCLK3NumeratorLow  = n_best;
2921	nPtr->NeoModeReg.VCLK3NumeratorHigh = (f_best << 7);
2922    }
2923    else {
2924	nPtr->NeoModeReg.VCLK3NumeratorLow  = n_best | (f_best << 7);
2925    }
2926    nPtr->NeoModeReg.VCLK3Denominator = d_best;
2927#ifdef DEBUG
2928    ErrorF("neoVCLK: f:%f NumLow=%i NumHi=%i Den=%i Df=%f\n",
2929	   f_target,
2930	   nPtr->NeoModeReg.VCLK3NumeratorLow,
2931	   nPtr->NeoModeReg.VCLK3NumeratorHigh,
2932	   nPtr->NeoModeReg.VCLK3Denominator,
2933	   f_best_diff);
2934#endif
2935}
2936
2937/*
2938 * NeoDisplayPowerManagementSet --
2939 *
2940 * Sets VESA Display Power Management Signaling (DPMS) Mode.
2941 */
2942static void
2943NeoDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
2944			     int flags)
2945{
2946    NEOPtr nPtr = NEOPTR(pScrn);
2947    vgaHWPtr hwp = VGAHWPTR(pScrn);
2948    unsigned char SEQ01 = 0;
2949    unsigned char LogicPowerMgmt = 0;
2950    unsigned char LCD_on = 0;
2951
2952    if (!pScrn->vtSema)
2953	return;
2954
2955    switch (PowerManagementMode) {
2956    case DPMSModeOn:
2957	/* Screen: On; HSync: On, VSync: On */
2958	SEQ01 = 0x00;
2959	LogicPowerMgmt = 0x00;
2960	if (nPtr->internDisp || ! nPtr->externDisp)
2961	    LCD_on = 0x02;
2962	else
2963	    LCD_on = 0x00;
2964	break;
2965    case DPMSModeStandby:
2966	/* Screen: Off; HSync: Off, VSync: On */
2967	SEQ01 = 0x20;
2968	LogicPowerMgmt = 0x10;
2969	LCD_on = 0x00;
2970	break;
2971    case DPMSModeSuspend:
2972	/* Screen: Off; HSync: On, VSync: Off */
2973	SEQ01 = 0x20;
2974	LogicPowerMgmt = 0x20;
2975	LCD_on = 0x00;
2976	break;
2977    case DPMSModeOff:
2978	/* Screen: Off; HSync: Off, VSync: Off */
2979	SEQ01 = 0x20;
2980	LogicPowerMgmt = 0x30;
2981	LCD_on = 0x00;
2982	break;
2983    }
2984
2985    /* Turn the screen on/off */
2986    SEQ01 |= VGArSR(0x01) & ~0x20;
2987    VGAwSR(0x01, SEQ01);
2988
2989    /* Turn the LCD on/off */
2990    LCD_on |= VGArGR(0x20) & ~0x02;
2991    VGAwGR(0x20, LCD_on);
2992
2993    /* Set the DPMS mode */
2994    LogicPowerMgmt |= 0x80;
2995    LogicPowerMgmt |= VGArGR(0x01) & ~0xF0;
2996    VGAwGR(0x01,LogicPowerMgmt);
2997}
2998
2999static unsigned int
3000neo_ddc1Read(ScrnInfoPtr pScrn)
3001{
3002    register vgaHWPtr hwp = VGAHWPTR(pScrn);
3003    register unsigned int tmp;
3004
3005    /* This needs to be investigated: we may have to swap this around */
3006    while (!(hwp->readST01(hwp)&0x8)) {};
3007    while (hwp->readST01(hwp)&0x8) {};
3008
3009    tmp = (VGArGR(0xA1) & 0x08);
3010
3011    return (tmp);
3012}
3013
3014static xf86MonPtr
3015neo_ddc1(int scrnIndex)
3016{
3017    vgaHWPtr hwp = VGAHWPTR(xf86Screens[scrnIndex]);
3018    unsigned int reg1, reg2, reg3;
3019    xf86MonPtr ret;
3020
3021    /* initialize chipset */
3022    reg1 = VGArCR(0x21);
3023    reg2 = VGArCR(0x1D);
3024    reg3 = VGArCR(0xA1);
3025    VGAwCR(0x21,0x00);
3026    VGAwCR(0x1D,0x01);  /* some Voodoo */
3027    VGAwGR(0xA1,0x2F);
3028    ret =  xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),neo_ddc1Read);
3029    /* undo initialization */
3030    VGAwCR(0x21,reg1);
3031    VGAwCR(0x1D,reg2);
3032    VGAwGR(0xA1,reg3);
3033    return ret;
3034}
3035
3036static Bool
3037neoDoDDC1(ScrnInfoPtr pScrn)
3038{
3039    Bool ret = FALSE;
3040    vgaHWPtr hwp = VGAHWPTR(pScrn);
3041
3042    VGAwGR(0x09,0x26);
3043    ret = xf86SetDDCproperties(pScrn,
3044				xf86PrintEDID(neo_ddc1(pScrn->scrnIndex)));
3045    VGAwGR(0x09,0x00);
3046
3047    return ret;
3048}
3049
3050static Bool
3051neoDoDDC2(ScrnInfoPtr pScrn)
3052{
3053    NEOPtr nPtr = NEOPTR(pScrn);
3054    vgaHWPtr hwp = VGAHWPTR(pScrn);
3055    Bool ret = FALSE;
3056
3057    VGAwGR(0x09,0x26);
3058    if (xf86LoadSubModule(pScrn, "i2c")) {
3059	if (neo_I2CInit(pScrn)) {
3060	    ret = xf86SetDDCproperties(pScrn,xf86PrintEDID(xf86DoEDID_DDC2(
3061					      pScrn->scrnIndex,nPtr->I2C)));
3062	}
3063    }
3064    VGAwGR(0x09,0x00);
3065
3066    return ret;
3067}
3068
3069static Bool
3070neoDoDDCVBE(ScrnInfoPtr pScrn)
3071{
3072    NEOPtr nPtr = NEOPTR(pScrn);
3073    vgaHWPtr hwp = VGAHWPTR(pScrn);
3074    vbeInfoPtr pVbe;
3075    Bool ret = FALSE;
3076
3077    VGAwGR(0x09,0x26);
3078    if (xf86LoadSubModule(pScrn, "vbe")) {
3079        if ((pVbe = VBEInit(NULL,nPtr->pEnt->index))) {
3080	  ret = xf86SetDDCproperties(
3081				     pScrn,xf86PrintEDID(vbeDoEDID(pVbe,NULL)));
3082	  vbeFree(pVbe);
3083	}
3084    }
3085    VGAwGR(0x09,0x00);
3086    return ret;
3087}
3088
3089static int
3090neoFindMode(int xres, int yres, int depth)
3091{
3092    int xres_s;
3093    int i, size;
3094    biosMode *mode;
3095
3096    switch (depth) {
3097    case 8:
3098	size = sizeof(bios8) / sizeof(biosMode);
3099	mode = bios8;
3100	break;
3101    case 15:
3102	size = sizeof(bios15) / sizeof(biosMode);
3103	mode = bios15;
3104	break;
3105    case 16:
3106	size = sizeof(bios16) / sizeof(biosMode);
3107	mode = bios16;
3108	break;
3109    case 24:
3110	size = sizeof(bios24) / sizeof(biosMode);
3111	mode = bios24;
3112	break;
3113    default:
3114	return 0;
3115    }
3116
3117    for (i = 0; i < size; i++) {
3118	if (xres <= mode[i].x_res) {
3119	    xres_s = mode[i].x_res;
3120	    for (; i < size; i++) {
3121		if (mode[i].x_res != xres_s)
3122		    return mode[i-1].mode;
3123		if (yres <= mode[i].y_res)
3124		    return mode[i].mode;
3125	    }
3126	}
3127    }
3128    return mode[size - 1].mode;
3129
3130}
3131
3132static void
3133neoProbeDDC(ScrnInfoPtr pScrn, int index)
3134{
3135    vbeInfoPtr pVbe;
3136
3137    if (xf86LoadSubModule(pScrn, "vbe")) {
3138        if ((pVbe = VBEInit(NULL,index))) {
3139	    ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3140	    vbeFree(pVbe);
3141	}
3142    }
3143}
3144