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