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