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