neo_driver.c revision 692f60a7
1692f60a7Smrg/**********************************************************************
2692f60a7SmrgCopyright 1998, 1999 by Precision Insight, Inc., Cedar Park, Texas.
3692f60a7Smrg
4692f60a7Smrg                        All Rights Reserved
5692f60a7Smrg
6692f60a7SmrgPermission to use, copy, modify, distribute, and sell this software and
7692f60a7Smrgits documentation for any purpose is hereby granted without fee,
8692f60a7Smrgprovided that the above copyright notice appear in all copies and that
9692f60a7Smrgboth that copyright notice and this permission notice appear in
10692f60a7Smrgsupporting documentation, and that the name of Precision Insight not be
11692f60a7Smrgused in advertising or publicity pertaining to distribution of the
12692f60a7Smrgsoftware without specific, written prior permission.  Precision Insight
13692f60a7Smrgand its suppliers make no representations about the suitability of this
14692f60a7Smrgsoftware for any purpose.  It is provided "as is" without express or
15692f60a7Smrgimplied warranty.
16692f60a7Smrg
17692f60a7SmrgPRECISION INSIGHT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18692f60a7SmrgINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19692f60a7SmrgEVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20692f60a7SmrgSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21692f60a7SmrgRESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22692f60a7SmrgCONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23692f60a7SmrgCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24692f60a7Smrg**********************************************************************/
25692f60a7Smrg
26692f60a7Smrg/*
27692f60a7Smrg * Copyright 1998, 1999 Egbert Eich
28692f60a7Smrg * Copyright 2000, 2001 SuSE GmbH, Author: Egbert Eich
29692f60a7Smrg * Copyright 2002 SuSE Linux AG, Author: Egbert Eich
30692f60a7Smrg * Copyright 2002 Shigehiro Nomura
31692f60a7Smrg */
32692f60a7Smrg
33692f60a7Smrg/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/neomagic/neo_driver.c,v 1.74 2003/12/31 05:07:30 dawes Exp $ */
34692f60a7Smrg
35692f60a7Smrg/*
36692f60a7Smrg * The original Precision Insight driver for
37692f60a7Smrg * XFree86 v.3.3 has been sponsored by Red Hat.
38692f60a7Smrg *
39692f60a7Smrg * Authors:
40692f60a7Smrg *   Jens Owen (jens@tungstengraphics.com)
41692f60a7Smrg *   Kevin E. Martin (kevin@precisioninsight.com)
42692f60a7Smrg *
43692f60a7Smrg * Port to Xfree86 v.4.0
44692f60a7Smrg *   1998, 1999 by Egbert Eich (Egbert.Eich@Physik.TU-Darmstadt.DE)
45692f60a7Smrg */
46692f60a7Smrg
47692f60a7Smrg#ifdef HAVE_CONFIG_H
48692f60a7Smrg#include "config.h"
49692f60a7Smrg#endif
50692f60a7Smrg
51692f60a7Smrg/* All drivers should typically include these */
52692f60a7Smrg#include "xf86.h"
53692f60a7Smrg#include "xf86_OSproc.h"
54692f60a7Smrg
55692f60a7Smrg/* Everything using inb/outb, etc needs "compiler.h" */
56692f60a7Smrg#include "compiler.h"
57692f60a7Smrg
58692f60a7Smrg#include "xf86Resources.h"
59692f60a7Smrg
60692f60a7Smrg/* Drivers for PCI hardware need this */
61692f60a7Smrg#include "xf86PciInfo.h"
62692f60a7Smrg
63692f60a7Smrg/* Drivers that need to access the PCI config space directly need this */
64692f60a7Smrg#include "xf86Pci.h"
65692f60a7Smrg
66692f60a7Smrg/* This is used for module versioning */
67692f60a7Smrg#include "xf86Version.h"
68692f60a7Smrg
69692f60a7Smrg/* All drivers using the vgahw module need this */
70692f60a7Smrg#include "vgaHW.h"
71692f60a7Smrg
72692f60a7Smrg/* All drivers initialising the SW cursor need this */
73692f60a7Smrg#include "mipointer.h"
74692f60a7Smrg
75692f60a7Smrg/* All drivers implementing backing store need this */
76692f60a7Smrg#include "mibstore.h"
77692f60a7Smrg
78692f60a7Smrg/* All drivers using the mi banking wrapper need this */
79692f60a7Smrg#include "mibank.h"
80692f60a7Smrg
81692f60a7Smrg/* All drivers using the mi colormap manipulation need this */
82692f60a7Smrg#include "micmap.h"
83692f60a7Smrg
84692f60a7Smrg#include "xf86cmap.h"
85692f60a7Smrg
86692f60a7Smrg#include "fb.h"
87692f60a7Smrg#include "fbpseudocolor.h"
88692f60a7Smrg
89692f60a7Smrg/* Needed by Resources Access Control (RAC) */
90692f60a7Smrg#include "xf86RAC.h"
91692f60a7Smrg
92692f60a7Smrg/* int10 */
93692f60a7Smrg#include "xf86int10.h"
94692f60a7Smrg#include "vbe.h"
95692f60a7Smrg
96692f60a7Smrg/* Needed for Device Data Channel (DDC) support */
97692f60a7Smrg#include "xf86DDC.h"
98692f60a7Smrg
99692f60a7Smrg#include "picturestr.h"
100692f60a7Smrg
101692f60a7Smrg#include "xf86xv.h"
102692f60a7Smrg#include <X11/extensions/Xv.h>
103692f60a7Smrg
104692f60a7Smrg/*
105692f60a7Smrg * Driver data structures.
106692f60a7Smrg */
107692f60a7Smrg#include "neo.h"
108692f60a7Smrg#include "neo_reg.h"
109692f60a7Smrg#include "neo_macros.h"
110692f60a7Smrg
111692f60a7Smrg/* These need to be checked */
112692f60a7Smrg#include <X11/X.h>
113692f60a7Smrg#include <X11/Xproto.h>
114692f60a7Smrg#include "scrnintstr.h"
115692f60a7Smrg#include "servermd.h"
116692f60a7Smrg#ifdef XFreeXDGA
117692f60a7Smrg#define _XF86DGA_SERVER_
118692f60a7Smrg#include <X11/extensions/xf86dgastr.h>
119692f60a7Smrg#endif
120692f60a7Smrg
121692f60a7Smrg/* Mandatory functions */
122692f60a7Smrgstatic const OptionInfoRec *	NEOAvailableOptions(int chipid, int busid);
123692f60a7Smrgstatic void     NEOIdentify(int flags);
124692f60a7Smrgstatic Bool     NEOProbe(DriverPtr drv, int flags);
125692f60a7Smrgstatic Bool     NEOPreInit(ScrnInfoPtr pScrn, int flags);
126692f60a7Smrgstatic Bool     NEOScreenInit(int Index, ScreenPtr pScreen, int argc,
127692f60a7Smrg                                  char **argv);
128692f60a7Smrgstatic Bool     NEOEnterVT(int scrnIndex, int flags);
129692f60a7Smrgstatic void     NEOLeaveVT(int scrnIndex, int flags);
130692f60a7Smrgstatic Bool     NEOCloseScreen(int scrnIndex, ScreenPtr pScreen);
131692f60a7Smrgstatic void     NEOFreeScreen(int scrnIndex, int flags);
132692f60a7Smrgstatic ModeStatus NEOValidMode(int scrnIndex, DisplayModePtr mode,
133692f60a7Smrg                               Bool verbose, int flags);
134692f60a7Smrg
135692f60a7Smrg/* Internally used functions */
136692f60a7Smrgstatic int      neoFindIsaDevice(GDevPtr dev);
137692f60a7Smrgstatic Bool     neoModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
138692f60a7Smrgstatic void     neoSave(ScrnInfoPtr pScrn);
139692f60a7Smrgstatic void     neoRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
140692f60a7Smrg				 NeoRegPtr NeoReg, Bool restoreText);
141692f60a7Smrgstatic void     neoLock(ScrnInfoPtr pScrn);
142692f60a7Smrgstatic void     neoUnlock(ScrnInfoPtr pScrn);
143692f60a7Smrgstatic Bool	neoMapMem(ScrnInfoPtr pScrn);
144692f60a7Smrgstatic Bool	neoUnmapMem(ScrnInfoPtr pScrn);
145692f60a7Smrgstatic void     neoProgramShadowRegs(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
146692f60a7Smrg				     NeoRegPtr restore);
147692f60a7Smrgstatic void     neoCalcVCLK(ScrnInfoPtr pScrn, long freq);
148692f60a7Smrgstatic xf86MonPtr  neo_ddc1(int scrnIndex);
149692f60a7Smrgstatic Bool     neoDoDDC1(ScrnInfoPtr pScrn);
150692f60a7Smrgstatic Bool     neoDoDDC2(ScrnInfoPtr pScrn);
151692f60a7Smrgstatic Bool     neoDoDDCVBE(ScrnInfoPtr pScrn);
152692f60a7Smrgstatic void     neoProbeDDC(ScrnInfoPtr pScrn, int index);
153692f60a7Smrgstatic void     NeoDisplayPowerManagementSet(ScrnInfoPtr pScrn,
154692f60a7Smrg				int PowerManagementMode, int flags);
155692f60a7Smrgstatic int      neoFindMode(int xres, int yres, int depth);
156692f60a7Smrg
157692f60a7Smrg#define NEO_VERSION 4000
158692f60a7Smrg#define NEO_NAME "NEOMAGIC"
159692f60a7Smrg#define NEO_DRIVER_NAME "neomagic"
160692f60a7Smrg
161692f60a7Smrg#define NEO_MAJOR_VERSION 1
162692f60a7Smrg#define NEO_MINOR_VERSION 1
163692f60a7Smrg#define NEO_PATCHLEVEL 1
164692f60a7Smrg
165692f60a7Smrg/*
166692f60a7Smrg * This is intentionally screen-independent.  It indicates the binding
167692f60a7Smrg * choice made in the first PreInit.
168692f60a7Smrg */
169692f60a7Smrgstatic int pix24bpp = 0;
170692f60a7Smrg
171692f60a7Smrg
172692f60a7Smrgstatic biosMode bios8[] = {
173692f60a7Smrg    { 320, 240, 0x40 },
174692f60a7Smrg    { 300, 400, 0x42 },
175692f60a7Smrg    { 640, 400, 0x20 },
176692f60a7Smrg    { 640, 480, 0x21 },
177692f60a7Smrg    { 800, 600, 0x23 },
178692f60a7Smrg    { 1024, 768, 0x25 }
179692f60a7Smrg};
180692f60a7Smrg
181692f60a7Smrgstatic biosMode bios15[] = {
182692f60a7Smrg    { 320, 200, 0x2D },
183692f60a7Smrg    { 640, 480, 0x30 },
184692f60a7Smrg    { 800, 600, 0x33 },
185692f60a7Smrg    { 1024, 768, 0x36 }
186692f60a7Smrg};
187692f60a7Smrg
188692f60a7Smrgstatic biosMode bios16[] = {
189692f60a7Smrg    { 320, 200, 0x2e },
190692f60a7Smrg    { 320, 240, 0x41 },
191692f60a7Smrg    { 300, 400, 0x43 },
192692f60a7Smrg    { 640, 480, 0x31 },
193692f60a7Smrg    { 800, 600, 0x34 },
194692f60a7Smrg    { 1024, 768, 0x37 }
195692f60a7Smrg};
196692f60a7Smrg
197692f60a7Smrgstatic biosMode bios24[] = {
198692f60a7Smrg    { 640, 480, 0x32 },
199692f60a7Smrg    { 800, 600, 0x35 },
200692f60a7Smrg    { 1024, 768, 0x38 }
201692f60a7Smrg};
202692f60a7Smrg
203692f60a7Smrgstatic DisplayModeRec neo800x480Mode = {
204692f60a7Smrg	NULL,           /* prev */
205692f60a7Smrg	NULL,           /* next */
206692f60a7Smrg	"800x480",      /* identifier of this mode */
207692f60a7Smrg	MODE_OK,        /* mode status */
208692f60a7Smrg	M_T_BUILTIN,    /* mode type */
209692f60a7Smrg	35260,		/* Clock frequency */
210692f60a7Smrg	800,		/* HDisplay */
211692f60a7Smrg	856,		/* HSyncStart */
212692f60a7Smrg	1040,		/* HSyncEnd */
213692f60a7Smrg	1056,		/* HTotal */
214692f60a7Smrg	0,		/* HSkew */
215692f60a7Smrg	480,		/* VDisplay */
216692f60a7Smrg	480,		/* VSyncStart */
217692f60a7Smrg	486,		/* VSyncEnd */
218692f60a7Smrg	488,		/* VTotal */
219692f60a7Smrg	0,		/* VScan */
220692f60a7Smrg	V_PHSYNC | V_PVSYNC,	/* Flags */
221692f60a7Smrg	-1,		/* ClockIndex */
222692f60a7Smrg	35260,		/* SynthClock */
223692f60a7Smrg	800,		/* CRTC HDisplay */
224692f60a7Smrg	800,            /* CRTC HBlankStart */
225692f60a7Smrg	856,            /* CRTC HSyncStart */
226692f60a7Smrg	1040,           /* CRTC HSyncEnd */
227692f60a7Smrg	872,            /* CRTC HBlankEnd */
228692f60a7Smrg	1048,           /* CRTC HTotal */
229692f60a7Smrg	0,              /* CRTC HSkew */
230692f60a7Smrg	480,		/* CRTC VDisplay */
231692f60a7Smrg	480,		/* CRTC VBlankStart */
232692f60a7Smrg	480,		/* CRTC VSyncStart */
233692f60a7Smrg	486,		/* CRTC VSyncEnd */
234692f60a7Smrg	487,		/* CRTC VBlankEnd */
235692f60a7Smrg	488,		/* CRTC VTotal */
236692f60a7Smrg	FALSE,		/* CrtcHAdjusted */
237692f60a7Smrg	FALSE,		/* CrtcVAdjusted */
238692f60a7Smrg	0,		/* PrivSize */
239692f60a7Smrg	NULL,		/* Private */
240692f60a7Smrg	0.0,		/* HSync */
241692f60a7Smrg	0.0		/* VRefresh */
242692f60a7Smrg};
243692f60a7Smrg
244692f60a7Smrgstatic DisplayModeRec neo1024x480Mode = {
245692f60a7Smrg	NULL,           /* prev */
246692f60a7Smrg	NULL,           /* next */
247692f60a7Smrg	"1024x480",      /* identifier of this mode */
248692f60a7Smrg	MODE_OK,        /* mode status */
249692f60a7Smrg	M_T_BUILTIN,    /* mode type */
250692f60a7Smrg	45900,		/* Clock frequency */
251692f60a7Smrg	1024,		/* HDisplay */
252692f60a7Smrg	1048,		/* HSyncStart */
253692f60a7Smrg	1184,		/* HSyncEnd */
254692f60a7Smrg	1344,		/* HTotal */
255692f60a7Smrg	0,		/* HSkew */
256692f60a7Smrg	480,		/* VDisplay */
257692f60a7Smrg	480,		/* VSyncStart */
258692f60a7Smrg	486,		/* VSyncEnd */
259692f60a7Smrg	488,		/* VTotal */
260692f60a7Smrg	0,		/* VScan */
261692f60a7Smrg	V_PHSYNC | V_PVSYNC,	/* Flags */
262692f60a7Smrg	-1,		/* ClockIndex */
263692f60a7Smrg	45900,		/* SynthClock */
264692f60a7Smrg	1024,		/* CRTC HDisplay */
265692f60a7Smrg	1024,            /* CRTC HBlankStart */
266692f60a7Smrg	1048,            /* CRTC HSyncStart */
267692f60a7Smrg	1184,           /* CRTC HSyncEnd */
268692f60a7Smrg	1072,            /* CRTC HBlankEnd */
269692f60a7Smrg	1344,           /* CRTC HTotal */
270692f60a7Smrg	0,              /* CRTC HSkew */
271692f60a7Smrg	480,		/* CRTC VDisplay */
272692f60a7Smrg	480,		/* CRTC VBlankStart */
273692f60a7Smrg	480,		/* CRTC VSyncStart */
274692f60a7Smrg	486,		/* CRTC VSyncEnd */
275692f60a7Smrg	487,		/* CRTC VBlankEnd */
276692f60a7Smrg	488,		/* CRTC VTotal */
277692f60a7Smrg	FALSE,		/* CrtcHAdjusted */
278692f60a7Smrg	FALSE,		/* CrtcVAdjusted */
279692f60a7Smrg	0,		/* PrivSize */
280692f60a7Smrg	NULL,		/* Private */
281692f60a7Smrg	0.0,		/* HSync */
282692f60a7Smrg	0.0		/* VRefresh */
283692f60a7Smrg};
284692f60a7Smrg
285692f60a7Smrg/*
286692f60a7Smrg * This contains the functions needed by the server after loading the driver
287692f60a7Smrg * module.  It must be supplied, and gets passed back by the SetupProc
288692f60a7Smrg * function in the dynamic case.  In the static case, a reference to this
289692f60a7Smrg * is compiled in, and this requires that the name of this DriverRec be
290692f60a7Smrg * an upper-case version of the driver name.
291692f60a7Smrg */
292692f60a7Smrg
293692f60a7Smrg_X_EXPORT DriverRec NEOMAGIC = {
294692f60a7Smrg    NEO_VERSION,
295692f60a7Smrg    NEO_DRIVER_NAME,
296692f60a7Smrg    NEOIdentify,
297692f60a7Smrg    NEOProbe,
298692f60a7Smrg    NEOAvailableOptions,
299692f60a7Smrg    NULL,
300692f60a7Smrg    0
301692f60a7Smrg};
302692f60a7Smrg
303692f60a7Smrgstatic SymTabRec NEOChipsets[] = {
304692f60a7Smrg    { NM2070,   "neo2070" },
305692f60a7Smrg    { NM2090,   "neo2090" },
306692f60a7Smrg    { NM2093,   "neo2093" },
307692f60a7Smrg    { NM2097,   "neo2097" },
308692f60a7Smrg    { NM2160,   "neo2160" },
309692f60a7Smrg    { NM2200,   "neo2200" },
310692f60a7Smrg    { NM2230,   "neo2230" },
311692f60a7Smrg    { NM2360,   "neo2360" },
312692f60a7Smrg    { NM2380,   "neo2380" },
313692f60a7Smrg    { -1,		 NULL }
314692f60a7Smrg};
315692f60a7Smrg
316692f60a7Smrg/* Conversion PCI ID to chipset name */
317692f60a7Smrgstatic PciChipsets NEOPCIchipsets[] = {
318692f60a7Smrg    { NM2070,  PCI_CHIP_NM2070,  RES_SHARED_VGA },
319692f60a7Smrg    { NM2090,  PCI_CHIP_NM2090,  RES_SHARED_VGA },
320692f60a7Smrg    { NM2093,  PCI_CHIP_NM2093,  RES_SHARED_VGA },
321692f60a7Smrg    { NM2097,  PCI_CHIP_NM2097,  RES_SHARED_VGA },
322692f60a7Smrg    { NM2160,  PCI_CHIP_NM2160,  RES_SHARED_VGA },
323692f60a7Smrg    { NM2200,  PCI_CHIP_NM2200,  RES_SHARED_VGA },
324692f60a7Smrg    { NM2230,  PCI_CHIP_NM2230,  RES_SHARED_VGA },
325692f60a7Smrg    { NM2360,  PCI_CHIP_NM2360,  RES_SHARED_VGA },
326692f60a7Smrg    { NM2380,  PCI_CHIP_NM2380,  RES_SHARED_VGA },
327692f60a7Smrg    { -1,	     -1,	     RES_UNDEFINED}
328692f60a7Smrg};
329692f60a7Smrg
330692f60a7Smrgstatic IsaChipsets NEOISAchipsets[] = {
331692f60a7Smrg    { NM2070,               RES_EXCLUSIVE_VGA },
332692f60a7Smrg    { NM2090,               RES_EXCLUSIVE_VGA },
333692f60a7Smrg    { NM2093,               RES_EXCLUSIVE_VGA },
334692f60a7Smrg    { NM2097,               RES_EXCLUSIVE_VGA },
335692f60a7Smrg    { NM2160,               RES_EXCLUSIVE_VGA },
336692f60a7Smrg    { NM2200,               RES_EXCLUSIVE_VGA },
337692f60a7Smrg    { -1,			RES_UNDEFINED }
338692f60a7Smrg};
339692f60a7Smrg
340692f60a7Smrg/* The options supported by the Neomagic Driver */
341692f60a7Smrgtypedef enum {
342692f60a7Smrg    OPTION_NOLINEAR_MODE,
343692f60a7Smrg    OPTION_NOACCEL,
344692f60a7Smrg    OPTION_SW_CURSOR,
345692f60a7Smrg    OPTION_NO_MMIO,
346692f60a7Smrg    OPTION_INTERN_DISP,
347692f60a7Smrg    OPTION_EXTERN_DISP,
348692f60a7Smrg    OPTION_LCD_CENTER,
349692f60a7Smrg    OPTION_LCD_STRETCH,
350692f60a7Smrg    OPTION_SHADOW_FB,
351692f60a7Smrg    OPTION_PCI_BURST,
352692f60a7Smrg    OPTION_PROG_LCD_MODE_REGS,
353692f60a7Smrg    OPTION_PROG_LCD_MODE_STRETCH,
354692f60a7Smrg    OPTION_OVERRIDE_VALIDATE_MODE,
355692f60a7Smrg    OPTION_SHOWCACHE,
356692f60a7Smrg    OPTION_ROTATE,
357692f60a7Smrg    OPTION_VIDEO_KEY,
358692f60a7Smrg    OPTION_OVERLAYMEM,
359692f60a7Smrg    OPTION_VIDEO_INTERLACE,
360692f60a7Smrg    OPTION_DISPLAY_HEIGHT_480,
361692f60a7Smrg    OPTION_STRANGE_LOCKUPS
362692f60a7Smrg} NEOOpts;
363692f60a7Smrg
364692f60a7Smrgstatic const OptionInfoRec NEO_2070_Options[] = {
365692f60a7Smrg    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
366692f60a7Smrg    { OPTION_SW_CURSOR,	"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
367692f60a7Smrg    { OPTION_NO_MMIO,	"noMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
368692f60a7Smrg    { OPTION_INTERN_DISP,"internDisp",	OPTV_BOOLEAN,	{0}, FALSE },
369692f60a7Smrg    { OPTION_EXTERN_DISP,"externDisp",  OPTV_BOOLEAN,	{0}, FALSE },
370692f60a7Smrg    { OPTION_LCD_CENTER, "LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
371692f60a7Smrg    { OPTION_LCD_STRETCH, "NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
372692f60a7Smrg    { OPTION_SHADOW_FB,   "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
373692f60a7Smrg    { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,   {0}, FALSE },
374692f60a7Smrg    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
375692f60a7Smrg    { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
376692f60a7Smrg    { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
377692f60a7Smrg      OPTV_BOOLEAN, {0}, FALSE },
378692f60a7Smrg    { OPTION_PROG_LCD_MODE_STRETCH, "progLcdModeStretch",
379692f60a7Smrg      OPTV_BOOLEAN, {0}, FALSE },
380692f60a7Smrg    { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
381692f60a7Smrg      OPTV_BOOLEAN, {0}, FALSE },
382692f60a7Smrg    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
383692f60a7Smrg    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
384692f60a7Smrg    { OPTION_VIDEO_INTERLACE, "Interlace",
385692f60a7Smrg      OPTV_INTEGER,   {0}, FALSE },
386692f60a7Smrg    { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
387692f60a7Smrg};
388692f60a7Smrg
389692f60a7Smrgstatic const OptionInfoRec NEOOptions[] = {
390692f60a7Smrg    { OPTION_NOLINEAR_MODE,"NoLinear",  OPTV_BOOLEAN,	{0}, FALSE },
391692f60a7Smrg    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
392692f60a7Smrg    { OPTION_SW_CURSOR,	"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
393692f60a7Smrg    { OPTION_NO_MMIO,	"noMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
394692f60a7Smrg    { OPTION_INTERN_DISP,"internDisp",	OPTV_BOOLEAN,	{0}, FALSE },
395692f60a7Smrg    { OPTION_EXTERN_DISP,"externDisp",	OPTV_BOOLEAN,	{0}, FALSE },
396692f60a7Smrg    { OPTION_LCD_CENTER, "LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
397692f60a7Smrg    { OPTION_SHADOW_FB,  "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
398692f60a7Smrg    { OPTION_LCD_STRETCH,"NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
399692f60a7Smrg    { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,	{0}, FALSE },
400692f60a7Smrg    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
401692f60a7Smrg    { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
402692f60a7Smrg    { OPTION_STRANGE_LOCKUPS, "StrangeLockups", OPTV_BOOLEAN, {0}, FALSE },
403692f60a7Smrg    { OPTION_DISPLAY_HEIGHT_480, "DisplayHeight480",
404692f60a7Smrg      OPTV_BOOLEAN, {0}, FALSE },
405692f60a7Smrg    { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
406692f60a7Smrg      OPTV_BOOLEAN, {0}, FALSE },
407692f60a7Smrg    { OPTION_PROG_LCD_MODE_STRETCH, "progLcdModeStretch",
408692f60a7Smrg      OPTV_BOOLEAN, {0}, FALSE },
409692f60a7Smrg    { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
410692f60a7Smrg      OPTV_BOOLEAN, {0}, FALSE },
411692f60a7Smrg    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
412692f60a7Smrg    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
413692f60a7Smrg    { OPTION_VIDEO_INTERLACE, "Interlace",
414692f60a7Smrg      OPTV_INTEGER,   {0}, FALSE },
415692f60a7Smrg    { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
416692f60a7Smrg};
417692f60a7Smrg
418692f60a7Smrg/*
419692f60a7Smrg * List of symbols from other modules that this module references.  This
420692f60a7Smrg * list is used to tell the loader that it is OK for symbols here to be
421692f60a7Smrg * unresolved providing that it hasn't been told that they haven't been
422692f60a7Smrg * told that they are essential via a call to xf86LoaderReqSymbols() or
423692f60a7Smrg * xf86LoaderReqSymLists().  The purpose is this is to avoid warnings about
424692f60a7Smrg * unresolved symbols that are not required.
425692f60a7Smrg */
426692f60a7Smrg
427692f60a7Smrgstatic const char *vgahwSymbols[] = {
428692f60a7Smrg    "vgaHWFreeHWRec",
429692f60a7Smrg    "vgaHWGetHWRec",
430692f60a7Smrg    "vgaHWGetIOBase",
431692f60a7Smrg    "vgaHWGetIndex",
432692f60a7Smrg    "vgaHWInit",
433692f60a7Smrg    "vgaHWLock",
434692f60a7Smrg    "vgaHWMapMem",
435692f60a7Smrg    "vgaHWProtect",
436692f60a7Smrg    "vgaHWRestore",
437692f60a7Smrg    "vgaHWSave",
438692f60a7Smrg    "vgaHWSaveScreenWeak",
439692f60a7Smrg    "vgaHWSetStdFuncs",
440692f60a7Smrg    "vgaHWUnlock",
441692f60a7Smrg    "vgaHWddc1SetSpeedWeak",
442692f60a7Smrg    NULL
443692f60a7Smrg};
444692f60a7Smrg
445692f60a7Smrgstatic const char *fbSymbols[] = {
446692f60a7Smrg    "fbPictureInit",
447692f60a7Smrg    "fbScreenInit",
448692f60a7Smrg    NULL
449692f60a7Smrg};
450692f60a7Smrg
451692f60a7Smrgstatic const char *xaaSymbols[] = {
452692f60a7Smrg    "XAACreateInfoRec",
453692f60a7Smrg    "XAADestroyInfoRec",
454692f60a7Smrg    "XAAInit",
455692f60a7Smrg    NULL
456692f60a7Smrg};
457692f60a7Smrg
458692f60a7Smrgstatic const char *ramdacSymbols[] = {
459692f60a7Smrg    "xf86CreateCursorInfoRec",
460692f60a7Smrg    "xf86DestroyCursorInfoRec",
461692f60a7Smrg    "xf86InitCursor",
462692f60a7Smrg    NULL
463692f60a7Smrg};
464692f60a7Smrg
465692f60a7Smrgstatic const char *shadowSymbols[] = {
466692f60a7Smrg    "shadowInit",
467692f60a7Smrg    NULL
468692f60a7Smrg};
469692f60a7Smrg
470692f60a7Smrgstatic const char *ddcSymbols[] = {
471692f60a7Smrg    "xf86DoEDID_DDC1",
472692f60a7Smrg    "xf86DoEDID_DDC2",
473692f60a7Smrg    "xf86PrintEDID",
474692f60a7Smrg    "xf86SetDDCproperties",
475692f60a7Smrg    NULL
476692f60a7Smrg};
477692f60a7Smrg
478692f60a7Smrgstatic const char *vbeSymbols[] = {
479692f60a7Smrg    "VBEInit",
480692f60a7Smrg    "vbeDoEDID",
481692f60a7Smrg    "vbeFree",
482692f60a7Smrg    NULL
483692f60a7Smrg};
484692f60a7Smrg
485692f60a7Smrgstatic const char *i2cSymbols[] = {
486692f60a7Smrg    "xf86CreateI2CBusRec",
487692f60a7Smrg    "xf86I2CBusInit",
488692f60a7Smrg    NULL
489692f60a7Smrg};
490692f60a7Smrg
491692f60a7Smrg#ifdef XFree86LOADER
492692f60a7Smrg
493692f60a7Smrgstatic MODULESETUPPROTO(neoSetup);
494692f60a7Smrg
495692f60a7Smrgstatic XF86ModuleVersionInfo neoVersRec =
496692f60a7Smrg{
497692f60a7Smrg	"neomagic",
498692f60a7Smrg	MODULEVENDORSTRING,
499692f60a7Smrg	MODINFOSTRING1,
500692f60a7Smrg	MODINFOSTRING2,
501692f60a7Smrg	XORG_VERSION_CURRENT,
502692f60a7Smrg	NEO_MAJOR_VERSION, NEO_MINOR_VERSION, NEO_PATCHLEVEL,
503692f60a7Smrg	ABI_CLASS_VIDEODRV,
504692f60a7Smrg	ABI_VIDEODRV_VERSION,
505692f60a7Smrg	MOD_CLASS_VIDEODRV,
506692f60a7Smrg	{0,0,0,0}
507692f60a7Smrg};
508692f60a7Smrg
509692f60a7Smrg/*
510692f60a7Smrg * This is the module init data.
511692f60a7Smrg * Its name has to be the driver name followed by ModuleData
512692f60a7Smrg */
513692f60a7Smrg_X_EXPORT XF86ModuleData neomagicModuleData = { &neoVersRec, neoSetup, NULL };
514692f60a7Smrg
515692f60a7Smrgstatic pointer
516692f60a7SmrgneoSetup(pointer module, pointer opts, int *errmaj, int *errmin)
517692f60a7Smrg{
518692f60a7Smrg    static Bool setupDone = FALSE;
519692f60a7Smrg
520692f60a7Smrg    if (!setupDone) {
521692f60a7Smrg	setupDone = TRUE;
522692f60a7Smrg        xf86AddDriver(&NEOMAGIC, module, 0);
523692f60a7Smrg
524692f60a7Smrg	/*
525692f60a7Smrg	 * Modules that this driver always requires can be loaded here
526692f60a7Smrg	 * by calling LoadSubModule().
527692f60a7Smrg	 */
528692f60a7Smrg
529692f60a7Smrg	/*
530692f60a7Smrg	 * Tell the loader about symbols from other modules that this module
531692f60a7Smrg	 * might refer to.
532692f60a7Smrg	 */
533692f60a7Smrg	LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols,
534692f60a7Smrg			  ramdacSymbols, shadowSymbols,
535692f60a7Smrg			  ddcSymbols, vbeSymbols, i2cSymbols, NULL);
536692f60a7Smrg	/*
537692f60a7Smrg	 * The return value must be non-NULL on success even though there
538692f60a7Smrg	 * is no TearDownProc.
539692f60a7Smrg	 */
540692f60a7Smrg  	return (pointer)1;
541692f60a7Smrg    } else {
542692f60a7Smrg	if (errmaj) *errmaj = LDR_ONCEONLY;
543692f60a7Smrg	return NULL;
544692f60a7Smrg    }
545692f60a7Smrg}
546692f60a7Smrg
547692f60a7Smrg#endif /* XFree86LOADER */
548692f60a7Smrg
549692f60a7Smrgstatic Bool
550692f60a7SmrgNEOGetRec(ScrnInfoPtr pScrn)
551692f60a7Smrg{
552692f60a7Smrg    /*
553692f60a7Smrg     * Allocate a NEORec, and hook it into pScrn->driverPrivate.
554692f60a7Smrg     * pScrn->driverPrivate is initialised to NULL, so we can check if
555692f60a7Smrg     * the allocation has already been done.
556692f60a7Smrg     */
557692f60a7Smrg    if (pScrn->driverPrivate != NULL)
558692f60a7Smrg	return TRUE;
559692f60a7Smrg
560692f60a7Smrg    pScrn->driverPrivate = xnfcalloc(sizeof(NEORec), 1);
561692f60a7Smrg
562692f60a7Smrg    if (pScrn->driverPrivate == NULL)
563692f60a7Smrg	return FALSE;
564692f60a7Smrg        return TRUE;
565692f60a7Smrg}
566692f60a7Smrg
567692f60a7Smrgstatic void
568692f60a7SmrgNEOFreeRec(ScrnInfoPtr pScrn)
569692f60a7Smrg{
570692f60a7Smrg    if (pScrn->driverPrivate == NULL)
571692f60a7Smrg	return;
572692f60a7Smrg    xfree(pScrn->driverPrivate);
573692f60a7Smrg    pScrn->driverPrivate = NULL;
574692f60a7Smrg}
575692f60a7Smrg
576692f60a7Smrgstatic const OptionInfoRec *
577692f60a7SmrgNEOAvailableOptions(int chipid, int busid)
578692f60a7Smrg{
579692f60a7Smrg    int chip = (chipid & 0x0000ffff);
580692f60a7Smrg
581692f60a7Smrg    if (chip == PCI_CHIP_NM2070)
582692f60a7Smrg	return NEO_2070_Options;
583692f60a7Smrg    else
584692f60a7Smrg    	return NEOOptions;
585692f60a7Smrg}
586692f60a7Smrg
587692f60a7Smrg/* Mandatory */
588692f60a7Smrgstatic void
589692f60a7SmrgNEOIdentify(int flags)
590692f60a7Smrg{
591692f60a7Smrg    xf86PrintChipsets(NEO_NAME, "Driver for Neomagic chipsets",
592692f60a7Smrg			NEOChipsets);
593692f60a7Smrg}
594692f60a7Smrg
595692f60a7Smrg/* Mandatory */
596692f60a7Smrgstatic Bool
597692f60a7SmrgNEOProbe(DriverPtr drv, int flags)
598692f60a7Smrg{
599692f60a7Smrg    Bool foundScreen = FALSE;
600692f60a7Smrg    int numDevSections, numUsed;
601692f60a7Smrg    GDevPtr *devSections;
602692f60a7Smrg    int *usedChips;
603692f60a7Smrg    int i;
604692f60a7Smrg
605692f60a7Smrg    /*
606692f60a7Smrg     * Find the config file Device sections that match this
607692f60a7Smrg     * driver, and return if there are none.
608692f60a7Smrg     */
609692f60a7Smrg    if ((numDevSections = xf86MatchDevice(NEO_DRIVER_NAME,
610692f60a7Smrg					  &devSections)) <= 0) {
611692f60a7Smrg	return FALSE;
612692f60a7Smrg    }
613692f60a7Smrg
614692f60a7Smrg    /* PCI BUS */
615692f60a7Smrg    if (xf86GetPciVideoInfo() ) {
616692f60a7Smrg	numUsed = xf86MatchPciInstances(NEO_NAME, PCI_VENDOR_NEOMAGIC,
617692f60a7Smrg					NEOChipsets, NEOPCIchipsets,
618692f60a7Smrg					devSections,numDevSections,
619692f60a7Smrg					drv, &usedChips);
620692f60a7Smrg
621692f60a7Smrg	if (numUsed > 0) {
622692f60a7Smrg	    if (flags & PROBE_DETECT)
623692f60a7Smrg		foundScreen = TRUE;
624692f60a7Smrg	    else for (i = 0; i < numUsed; i++) {
625692f60a7Smrg		ScrnInfoPtr pScrn = NULL;
626692f60a7Smrg		/* Allocate a ScrnInfoRec and claim the slot */
627692f60a7Smrg		if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
628692f60a7Smrg						       NEOPCIchipsets,NULL, NULL,
629692f60a7Smrg						       NULL, NULL, NULL))) {
630692f60a7Smrg		    pScrn->driverVersion = NEO_VERSION;
631692f60a7Smrg		    pScrn->driverName    = NEO_DRIVER_NAME;
632692f60a7Smrg		    pScrn->name          = NEO_NAME;
633692f60a7Smrg		    pScrn->Probe         = NEOProbe;
634692f60a7Smrg		    pScrn->PreInit       = NEOPreInit;
635692f60a7Smrg		    pScrn->ScreenInit    = NEOScreenInit;
636692f60a7Smrg		    pScrn->SwitchMode    = NEOSwitchMode;
637692f60a7Smrg		    pScrn->AdjustFrame   = NEOAdjustFrame;
638692f60a7Smrg		    pScrn->EnterVT       = NEOEnterVT;
639692f60a7Smrg		    pScrn->LeaveVT       = NEOLeaveVT;
640692f60a7Smrg		    pScrn->FreeScreen    = NEOFreeScreen;
641692f60a7Smrg		    pScrn->ValidMode     = NEOValidMode;
642692f60a7Smrg		    foundScreen = TRUE;
643692f60a7Smrg		}
644692f60a7Smrg	    }
645692f60a7Smrg	    xfree(usedChips);
646692f60a7Smrg	}
647692f60a7Smrg    }
648692f60a7Smrg
649692f60a7Smrg    /* Isa Bus */
650692f60a7Smrg
651692f60a7Smrg    numUsed = xf86MatchIsaInstances(NEO_NAME,NEOChipsets,NEOISAchipsets,
652692f60a7Smrg				     drv,neoFindIsaDevice,devSections,
653692f60a7Smrg				     numDevSections,&usedChips);
654692f60a7Smrg    if (numUsed > 0) {
655692f60a7Smrg      if (flags & PROBE_DETECT)
656692f60a7Smrg	foundScreen = TRUE;
657692f60a7Smrg      else for (i = 0; i < numUsed; i++) {
658692f60a7Smrg	ScrnInfoPtr pScrn = NULL;
659692f60a7Smrg	if ((pScrn = xf86ConfigIsaEntity(pScrn, 0, usedChips[i],
660692f60a7Smrg					 NEOISAchipsets, NULL, NULL,
661692f60a7Smrg					 NULL, NULL, NULL))) {
662692f60a7Smrg	    pScrn->driverVersion = NEO_VERSION;
663692f60a7Smrg	    pScrn->driverName    = NEO_DRIVER_NAME;
664692f60a7Smrg	    pScrn->name          = NEO_NAME;
665692f60a7Smrg	    pScrn->Probe         = NEOProbe;
666692f60a7Smrg	    pScrn->PreInit       = NEOPreInit;
667692f60a7Smrg	    pScrn->ScreenInit    = NEOScreenInit;
668692f60a7Smrg	    pScrn->SwitchMode    = NEOSwitchMode;
669692f60a7Smrg	    pScrn->AdjustFrame   = NEOAdjustFrame;
670692f60a7Smrg	    pScrn->EnterVT       = NEOEnterVT;
671692f60a7Smrg	    pScrn->LeaveVT       = NEOLeaveVT;
672692f60a7Smrg	    pScrn->FreeScreen    = NEOFreeScreen;
673692f60a7Smrg	    pScrn->ValidMode     = NEOValidMode;
674692f60a7Smrg	    foundScreen = TRUE;
675692f60a7Smrg	}
676692f60a7Smrg      }
677692f60a7Smrg      xfree(usedChips);
678692f60a7Smrg    }
679692f60a7Smrg
680692f60a7Smrg    xfree(devSections);
681692f60a7Smrg    return foundScreen;
682692f60a7Smrg}
683692f60a7Smrg
684692f60a7Smrgstatic int
685692f60a7SmrgneoFindIsaDevice(GDevPtr dev)
686692f60a7Smrg{
687692f60a7Smrg    unsigned int vgaIOBase;
688692f60a7Smrg    unsigned char id;
689692f60a7Smrg
690692f60a7Smrg    vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
691692f60a7Smrg    /* §§§ Too intrusive ? */
692692f60a7Smrg    outw(GRAX, 0x2609); /* Unlock NeoMagic registers */
693692f60a7Smrg
694692f60a7Smrg    outb(vgaIOBase + 4, 0x1A);
695692f60a7Smrg    id = inb(vgaIOBase + 5);
696692f60a7Smrg
697692f60a7Smrg    outw(GRAX, 0x0009); /* Lock NeoMagic registers */
698692f60a7Smrg
699692f60a7Smrg    switch (id) {
700692f60a7Smrg    case PROBED_NM2070 :
701692f60a7Smrg	return NM2070;
702692f60a7Smrg    case PROBED_NM2090 :
703692f60a7Smrg	return NM2090;
704692f60a7Smrg    case PROBED_NM2093 :
705692f60a7Smrg	return NM2093;
706692f60a7Smrg    default :
707692f60a7Smrg	return -1;
708692f60a7Smrg    }
709692f60a7Smrg}
710692f60a7Smrg
711692f60a7Smrg
712692f60a7Smrg/* Mandatory */
713692f60a7SmrgBool
714692f60a7SmrgNEOPreInit(ScrnInfoPtr pScrn, int flags)
715692f60a7Smrg{
716692f60a7Smrg    ClockRangePtr clockRanges;
717692f60a7Smrg    int i;
718692f60a7Smrg    NEOPtr nPtr;
719692f60a7Smrg    vgaHWPtr hwp;
720692f60a7Smrg    int bppSupport = NoDepth24Support;
721692f60a7Smrg    int videoRam = 896;
722692f60a7Smrg    int maxClock = 65000;
723692f60a7Smrg    int CursorMem = 1024;
724692f60a7Smrg    int CursorOff = 0x100;
725692f60a7Smrg    int linearSize = 1024;
726692f60a7Smrg    int maxWidth = 1024;
727692f60a7Smrg    int maxHeight = 1024;
728692f60a7Smrg    unsigned char type, dpy;
729692f60a7Smrg    int w;
730692f60a7Smrg    int apertureSize;
731692f60a7Smrg    Bool height_480 = FALSE;
732692f60a7Smrg    Bool lcdCenterOptSet = FALSE;
733692f60a7Smrg    char *s;
734692f60a7Smrg
735692f60a7Smrg    if (flags & PROBE_DETECT)  {
736692f60a7Smrg	neoProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
737692f60a7Smrg	return TRUE;
738692f60a7Smrg    }
739692f60a7Smrg
740692f60a7Smrg    /* The vgahw module should be loaded here when needed */
741692f60a7Smrg    if (!xf86LoadSubModule(pScrn, "vgahw"))
742692f60a7Smrg	return FALSE;
743692f60a7Smrg
744692f60a7Smrg    xf86LoaderReqSymLists(vgahwSymbols, NULL);
745692f60a7Smrg
746692f60a7Smrg    /*
747692f60a7Smrg     * Allocate a vgaHWRec.
748692f60a7Smrg     */
749692f60a7Smrg    if (!vgaHWGetHWRec(pScrn))
750692f60a7Smrg	return FALSE;
751692f60a7Smrg    hwp = VGAHWPTR(pScrn);
752692f60a7Smrg
753692f60a7Smrg    /* Allocate the NeoRec driverPrivate */
754692f60a7Smrg    if (!NEOGetRec(pScrn)) {
755692f60a7Smrg	return FALSE;
756692f60a7Smrg    }
757692f60a7Smrg# define RETURN \
758692f60a7Smrg    { NEOFreeRec(pScrn);\
759692f60a7Smrg			    return FALSE;\
760692f60a7Smrg					     }
761692f60a7Smrg
762692f60a7Smrg    nPtr = NEOPTR(pScrn);
763692f60a7Smrg
764692f60a7Smrg    /* Since, the capabilities are determined by the chipset the very
765692f60a7Smrg     * first thing to do is, figure out the chipset and its capabilities
766692f60a7Smrg     */
767692f60a7Smrg    /* This driver doesn't expect more than one entity per screen */
768692f60a7Smrg    if (pScrn->numEntities > 1)
769692f60a7Smrg	RETURN;
770692f60a7Smrg
771692f60a7Smrg    /* This is the general case */
772692f60a7Smrg    for (i = 0; i<pScrn->numEntities; i++) {
773692f60a7Smrg	nPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
774692f60a7Smrg	if (nPtr->pEnt->resources) return FALSE;
775692f60a7Smrg	nPtr->NeoChipset = nPtr->pEnt->chipset;
776692f60a7Smrg	pScrn->chipset = (char *)xf86TokenToString(NEOChipsets,
777692f60a7Smrg						   nPtr->pEnt->chipset);
778692f60a7Smrg	/* This driver can handle ISA and PCI buses */
779692f60a7Smrg	if (nPtr->pEnt->location.type == BUS_PCI) {
780692f60a7Smrg	    nPtr->PciInfo = xf86GetPciInfoForEntity(nPtr->pEnt->index);
781692f60a7Smrg	    nPtr->PciTag = pciTag(nPtr->PciInfo->bus,
782692f60a7Smrg				  nPtr->PciInfo->device,
783692f60a7Smrg				  nPtr->PciInfo->func);
784692f60a7Smrg	}
785692f60a7Smrg    }
786692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Chipset is a ");
787692f60a7Smrg    switch(nPtr->NeoChipset){
788692f60a7Smrg    case NM2070:
789692f60a7Smrg	xf86ErrorF("MagicGraph 128 (NM2070)");
790692f60a7Smrg	break;
791692f60a7Smrg    case NM2090 :
792692f60a7Smrg	xf86ErrorF("MagicGraph 128V (NM2090)");
793692f60a7Smrg	break;
794692f60a7Smrg    case NM2093 :
795692f60a7Smrg	xf86ErrorF("MagicGraph 128ZV (NM2093)");
796692f60a7Smrg	break;
797692f60a7Smrg    case NM2097 :
798692f60a7Smrg	xf86ErrorF("MagicGraph 128ZV+ (NM2097)");
799692f60a7Smrg	break;
800692f60a7Smrg    case NM2160 :
801692f60a7Smrg	xf86ErrorF("MagicGraph 128XD (NM2160)");
802692f60a7Smrg	break;
803692f60a7Smrg    case NM2200 :
804692f60a7Smrg        xf86ErrorF("MagicMedia 256AV (NM2200)");
805692f60a7Smrg	break;
806692f60a7Smrg    case NM2230 :
807692f60a7Smrg        xf86ErrorF("MagicMedia 256AV+ (NM2230)");
808692f60a7Smrg	break;
809692f60a7Smrg    case NM2360 :
810692f60a7Smrg        xf86ErrorF("MagicMedia 256ZX (NM2360)");
811692f60a7Smrg	break;
812692f60a7Smrg    case NM2380 :
813692f60a7Smrg        xf86ErrorF("MagicMedia 256XL+ (NM2380)");
814692f60a7Smrg	break;
815692f60a7Smrg    }
816692f60a7Smrg    xf86ErrorF("\n");
817692f60a7Smrg
818692f60a7Smrg    vgaHWGetIOBase(hwp);
819692f60a7Smrg    nPtr->vgaIOBase = hwp->IOBase;
820692f60a7Smrg    vgaHWSetStdFuncs(hwp);
821692f60a7Smrg
822692f60a7Smrg    /* Determine the panel type */
823692f60a7Smrg    VGAwGR(0x09,0x26);
824692f60a7Smrg    type = VGArGR(0x21);
825692f60a7Smrg    dpy = VGArGR(0x20);
826692f60a7Smrg
827692f60a7Smrg    /* Determine panel width -- used in NeoValidMode. */
828692f60a7Smrg    w = VGArGR(0x20);
829692f60a7Smrg    VGAwGR(0x09,0x00);
830692f60a7Smrg    switch ((w & 0x18) >> 3) {
831692f60a7Smrg    case 0x00 :
832692f60a7Smrg	nPtr->NeoPanelWidth  = 640;
833692f60a7Smrg	nPtr->NeoPanelHeight = 480;
834692f60a7Smrg	break;
835692f60a7Smrg    case 0x01 :
836692f60a7Smrg	nPtr->NeoPanelWidth  = 800;
837692f60a7Smrg	nPtr->NeoPanelHeight = 600;
838692f60a7Smrg	break;
839692f60a7Smrg    case 0x02 :
840692f60a7Smrg	nPtr->NeoPanelWidth  = 1024;
841692f60a7Smrg	nPtr->NeoPanelHeight = 768;
842692f60a7Smrg	break;
843692f60a7Smrg    case 0x03 :
844692f60a7Smrg        /* 1280x1024 panel support needs to be added */
845692f60a7Smrg#ifdef NOT_DONE
846692f60a7Smrg	nPtr->NeoPanelWidth  = 1280;
847692f60a7Smrg	nPtr->NeoPanelHeight = 1024;
848692f60a7Smrg	break;
849692f60a7Smrg#else
850692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
851692f60a7Smrg		     "Only 640x480,\n"
852692f60a7Smrg                     "     800x600,\n"
853692f60a7Smrg                     " and 1024x768 panels are currently supported\n");
854692f60a7Smrg	return FALSE;
855692f60a7Smrg#endif
856692f60a7Smrg    default :
857692f60a7Smrg	nPtr->NeoPanelWidth  = 640;
858692f60a7Smrg	nPtr->NeoPanelHeight = 480;
859692f60a7Smrg	break;
860692f60a7Smrg    }
861692f60a7Smrg
862692f60a7Smrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel is a %dx%d %s %s display\n",
863692f60a7Smrg	       nPtr->NeoPanelWidth,
864692f60a7Smrg	       nPtr->NeoPanelHeight,
865692f60a7Smrg	       (type & 0x02) ? "color" : "monochrome",
866692f60a7Smrg	       (type & 0x10) ? "TFT" : "dual scan");
867692f60a7Smrg
868692f60a7Smrg
869692f60a7Smrg    switch (nPtr->NeoChipset){
870692f60a7Smrg    case NM2070:
871692f60a7Smrg	bppSupport = NoDepth24Support;
872692f60a7Smrg	videoRam   = 896;
873692f60a7Smrg	maxClock   = 65000;
874692f60a7Smrg	CursorMem  = 2048;
875692f60a7Smrg	CursorOff  = 0x100;
876692f60a7Smrg	linearSize = 1024;
877692f60a7Smrg	maxWidth   = 1024;
878692f60a7Smrg	maxHeight  = 1024;
879692f60a7Smrg	break;
880692f60a7Smrg    case NM2090:
881692f60a7Smrg    case NM2093:
882692f60a7Smrg	bppSupport = Support24bppFb | Support32bppFb |
883692f60a7Smrg	    SupportConvert32to24 | PreferConvert32to24;
884692f60a7Smrg	videoRam   = 1152;
885692f60a7Smrg	maxClock   = 80000;
886692f60a7Smrg	CursorMem  = 2048;
887692f60a7Smrg	CursorOff  = 0x100;
888692f60a7Smrg	linearSize = 2048;
889692f60a7Smrg	maxWidth   = 1024;
890692f60a7Smrg	maxHeight  = 1024;
891692f60a7Smrg	break;
892692f60a7Smrg    case NM2097:
893692f60a7Smrg	bppSupport = Support24bppFb | Support32bppFb |
894692f60a7Smrg	  SupportConvert32to24 | PreferConvert32to24;
895692f60a7Smrg	videoRam   = 1152;
896692f60a7Smrg	maxClock   = 80000;
897692f60a7Smrg	CursorMem  = 1024;
898692f60a7Smrg	CursorOff  = 0x100;
899692f60a7Smrg	linearSize = 2048;
900692f60a7Smrg	maxWidth   = 1024;
901692f60a7Smrg	maxHeight  = 1024;
902692f60a7Smrg	break;
903692f60a7Smrg    case NM2160:
904692f60a7Smrg	bppSupport = Support24bppFb | Support32bppFb |
905692f60a7Smrg	    SupportConvert32to24 | PreferConvert32to24;
906692f60a7Smrg	videoRam   = 2048;
907692f60a7Smrg	maxClock   = 90000;
908692f60a7Smrg	CursorMem  = 1024;
909692f60a7Smrg	CursorOff  = 0x100;
910692f60a7Smrg	linearSize = 2048;
911692f60a7Smrg	maxWidth   = 1024;
912692f60a7Smrg	maxHeight  = 1024;
913692f60a7Smrg	break;
914692f60a7Smrg    case NM2200:
915692f60a7Smrg	bppSupport = Support24bppFb | Support32bppFb |
916692f60a7Smrg	    SupportConvert32to24 | PreferConvert32to24;
917692f60a7Smrg	videoRam   = 2560;
918692f60a7Smrg	maxClock   = 110000;
919692f60a7Smrg	CursorMem  = 1024;
920692f60a7Smrg	CursorOff  = 0x1000;
921692f60a7Smrg	linearSize = 4096;
922692f60a7Smrg	maxWidth   = 1280;
923692f60a7Smrg	maxHeight  = 1024;  /* ???? */
924692f60a7Smrg	break;
925692f60a7Smrg    case NM2230:
926692f60a7Smrg	bppSupport = Support24bppFb | Support32bppFb |
927692f60a7Smrg	    SupportConvert32to24 | PreferConvert32to24;
928692f60a7Smrg	videoRam   = 3008;
929692f60a7Smrg	maxClock   = 110000;
930692f60a7Smrg	CursorMem  = 1024;
931692f60a7Smrg	CursorOff  = 0x1000;
932692f60a7Smrg	linearSize = 4096;
933692f60a7Smrg	maxWidth   = 1280;
934692f60a7Smrg	maxHeight  = 1024;  /* ???? */
935692f60a7Smrg	break;
936692f60a7Smrg    case NM2360:
937692f60a7Smrg	bppSupport = Support24bppFb | Support32bppFb |
938692f60a7Smrg	    SupportConvert32to24 | PreferConvert32to24;
939692f60a7Smrg	videoRam   = 4096;
940692f60a7Smrg	maxClock   = 110000;
941692f60a7Smrg	CursorMem  = 1024;
942692f60a7Smrg	CursorOff  = 0x1000;
943692f60a7Smrg	linearSize = 4096;
944692f60a7Smrg	maxWidth   = 1280;
945692f60a7Smrg	maxHeight  = 1024;  /* ???? */
946692f60a7Smrg	break;
947692f60a7Smrg    case NM2380:
948692f60a7Smrg	bppSupport = Support24bppFb | Support32bppFb |
949692f60a7Smrg	    SupportConvert32to24 | PreferConvert32to24;
950692f60a7Smrg	videoRam   = 6144;
951692f60a7Smrg	maxClock   = 110000;
952692f60a7Smrg	CursorMem  = 1024;
953692f60a7Smrg	CursorOff  = 0x1000;
954692f60a7Smrg	linearSize = 8192;
955692f60a7Smrg	maxWidth   = 1280;
956692f60a7Smrg	maxHeight  = 1024;  /* ???? */
957692f60a7Smrg	break;
958692f60a7Smrg    }
959692f60a7Smrg
960692f60a7Smrg    pScrn->monitor = pScrn->confScreen->monitor;
961692f60a7Smrg
962692f60a7Smrg    if (xf86LoadSubModule(pScrn, "ddc")) {
963692f60a7Smrg        xf86LoaderReqSymLists(ddcSymbols, NULL);
964692f60a7Smrg#if 1 /* for DDC1 testing */
965692f60a7Smrg	if (!neoDoDDCVBE(pScrn))
966692f60a7Smrg	  if (!neoDoDDC2(pScrn))
967692f60a7Smrg#endif
968692f60a7Smrg	      neoDoDDC1(pScrn);
969692f60a7Smrg    }
970692f60a7Smrg
971692f60a7Smrg    if (!xf86SetDepthBpp(pScrn, 16, 0, 0, bppSupport ))
972692f60a7Smrg	return FALSE;
973692f60a7Smrg    else {
974692f60a7Smrg	/* Check that the returned depth is one we support */
975692f60a7Smrg	switch (pScrn->depth) {
976692f60a7Smrg	case 8:
977692f60a7Smrg	case 15:
978692f60a7Smrg	case 16:
979692f60a7Smrg	    break;
980692f60a7Smrg	case 24:
981692f60a7Smrg	    if (nPtr->NeoChipset != NM2070)
982692f60a7Smrg		break;
983692f60a7Smrg	default:
984692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
985692f60a7Smrg		       "Given depth (%d) is not supported by this driver\n",
986692f60a7Smrg		       pScrn->depth);
987692f60a7Smrg	    return FALSE;
988692f60a7Smrg	}
989692f60a7Smrg    }
990692f60a7Smrg    xf86PrintDepthBpp(pScrn);
991692f60a7Smrg    if (pScrn->depth == 8)
992692f60a7Smrg	pScrn->rgbBits = 6;
993692f60a7Smrg
994692f60a7Smrg    /* Get the depth24 pixmap format */
995692f60a7Smrg    if (pScrn->depth == 24 && pix24bpp == 0)
996692f60a7Smrg	pix24bpp = xf86GetBppFromDepth(pScrn, 24);
997692f60a7Smrg
998692f60a7Smrg    /*
999692f60a7Smrg     * This must happen after pScrn->display has been set because
1000692f60a7Smrg     * xf86SetWeight references it.
1001692f60a7Smrg     */
1002692f60a7Smrg    if (pScrn->depth > 8) {
1003692f60a7Smrg	/* The defaults are OK for us */
1004692f60a7Smrg	rgb zeros = {0, 0, 0};
1005692f60a7Smrg
1006692f60a7Smrg	if (!xf86SetWeight(pScrn, zeros, zeros)) {
1007692f60a7Smrg	    return FALSE;
1008692f60a7Smrg	} else {
1009692f60a7Smrg	    /* XXX check that weight returned is supported */
1010692f60a7Smrg	    ;
1011692f60a7Smrg	}
1012692f60a7Smrg    }
1013692f60a7Smrg
1014692f60a7Smrg    if (!xf86SetDefaultVisual(pScrn, -1))
1015692f60a7Smrg	return FALSE;
1016692f60a7Smrg
1017692f60a7Smrg    if (pScrn->depth > 1) {
1018692f60a7Smrg	Gamma zeros = {0.0, 0.0, 0.0};
1019692f60a7Smrg
1020692f60a7Smrg	if (!xf86SetGamma(pScrn, zeros))
1021692f60a7Smrg	    return FALSE;
1022692f60a7Smrg    }
1023692f60a7Smrg
1024692f60a7Smrg    nPtr->strangeLockups = TRUE;
1025692f60a7Smrg
1026692f60a7Smrg    /* Collect all of the relevant option flags (fill in pScrn->options) */
1027692f60a7Smrg    xf86CollectOptions(pScrn, NULL);
1028692f60a7Smrg    /* Process the options */
1029692f60a7Smrg    if (nPtr->NeoChipset == NM2070) {
1030692f60a7Smrg	if (!(nPtr->Options = xalloc(sizeof(NEO_2070_Options))))
1031692f60a7Smrg	    return FALSE;
1032692f60a7Smrg	memcpy(nPtr->Options, NEO_2070_Options, sizeof(NEO_2070_Options));
1033692f60a7Smrg    } else {
1034692f60a7Smrg	if (!(nPtr->Options = xalloc(sizeof(NEOOptions))))
1035692f60a7Smrg	    return FALSE;
1036692f60a7Smrg	memcpy(nPtr->Options, NEOOptions, sizeof(NEOOptions));
1037692f60a7Smrg    }
1038692f60a7Smrg
1039692f60a7Smrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, nPtr->Options);
1040692f60a7Smrg
1041692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_NOLINEAR_MODE,&nPtr->noLinear);
1042692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_SW_CURSOR,&nPtr->swCursor);
1043692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_NO_MMIO,&nPtr->noMMIO);
1044692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_INTERN_DISP,&nPtr->internDisp);
1045692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_EXTERN_DISP,&nPtr->externDisp);
1046692f60a7Smrg    if (xf86GetOptValBool(nPtr->Options, OPTION_LCD_CENTER,&nPtr->lcdCenter))
1047692f60a7Smrg	lcdCenterOptSet = TRUE;
1048692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_LCD_STRETCH,&nPtr->noLcdStretch);
1049692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_SHADOW_FB,&nPtr->shadowFB);
1050692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_SHOWCACHE,&nPtr->showcache);
1051692f60a7Smrg    nPtr->onPciBurst = TRUE;
1052692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_PCI_BURST,&nPtr->onPciBurst);
1053692f60a7Smrg    xf86GetOptValBool(nPtr->Options,
1054692f60a7Smrg		      OPTION_PROG_LCD_MODE_REGS,&nPtr->progLcdRegs);
1055692f60a7Smrg    if (xf86GetOptValBool(nPtr->Options,
1056692f60a7Smrg		      OPTION_PROG_LCD_MODE_STRETCH,&nPtr->progLcdStretch))
1057692f60a7Smrg	nPtr->progLcdStretchOpt = TRUE;
1058692f60a7Smrg    xf86GetOptValBool(nPtr->Options,
1059692f60a7Smrg		      OPTION_OVERRIDE_VALIDATE_MODE, &nPtr->overrideValidate);
1060692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_DISPLAY_HEIGHT_480,&height_480);
1061692f60a7Smrg    xf86GetOptValBool(nPtr->Options, OPTION_STRANGE_LOCKUPS,
1062692f60a7Smrg		      &nPtr->strangeLockups);
1063692f60a7Smrg    nPtr->noAccelSet =
1064692f60a7Smrg	xf86GetOptValBool(nPtr->Options, OPTION_NOACCEL,&nPtr->noAccel);
1065692f60a7Smrg
1066692f60a7Smrg    nPtr->rotate = 0;
1067692f60a7Smrg    if ((s = xf86GetOptValString(nPtr->Options, OPTION_ROTATE))) {
1068692f60a7Smrg	if(!xf86NameCmp(s, "CW")) {
1069692f60a7Smrg	    /* accel is disabled below for shadowFB */
1070692f60a7Smrg	    nPtr->shadowFB = TRUE;
1071692f60a7Smrg	    nPtr->swCursor = TRUE;
1072692f60a7Smrg	    nPtr->rotate = 1;
1073692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1074692f60a7Smrg		       "Rotating screen clockwise - acceleration disabled\n");
1075692f60a7Smrg	} else if(!xf86NameCmp(s, "CCW")) {
1076692f60a7Smrg	    nPtr->shadowFB = TRUE;
1077692f60a7Smrg	    nPtr->swCursor = TRUE;
1078692f60a7Smrg	    nPtr->rotate = -1;
1079692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
1080692f60a7Smrg		       "counter clockwise - acceleration disabled\n");
1081692f60a7Smrg	} else {
1082692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
1083692f60a7Smrg		       "value for Option \"Rotate\"\n", s);
1084692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1085692f60a7Smrg		       "Valid options are \"CW\" or \"CCW\"\n");
1086692f60a7Smrg      }
1087692f60a7Smrg    }
1088692f60a7Smrg
1089692f60a7Smrg    if(xf86GetOptValInteger(nPtr->Options,
1090692f60a7Smrg			    OPTION_VIDEO_KEY, &(nPtr->videoKey))) {
1091692f60a7Smrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
1092692f60a7Smrg		   nPtr->videoKey);
1093692f60a7Smrg    } else {
1094692f60a7Smrg        nPtr->videoKey = (1 << pScrn->offset.red) |
1095692f60a7Smrg	    (1 << pScrn->offset.green) |
1096692f60a7Smrg	    (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
1097692f60a7Smrg	     << pScrn->offset.blue);
1098692f60a7Smrg    }
1099692f60a7Smrg    if(xf86GetOptValInteger(nPtr->Options, OPTION_OVERLAYMEM,
1100692f60a7Smrg			    &(nPtr->overlay))) {
1101692f60a7Smrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1102692f60a7Smrg		   "reserve %d bytes for overlay.\n", nPtr->overlay);
1103692f60a7Smrg    } else {
1104692f60a7Smrg	nPtr->overlay = 0;
1105692f60a7Smrg    }
1106692f60a7Smrg    nPtr->interlace = 0;
1107692f60a7Smrg    if(xf86GetOptValInteger(nPtr->Options, OPTION_VIDEO_INTERLACE,
1108692f60a7Smrg			    &(nPtr->interlace))) {
1109692f60a7Smrg	if (nPtr->interlace >= 0  &&  nPtr->interlace <= 2){
1110692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "interlace flag = %d\n",
1111692f60a7Smrg		       nPtr->interlace);
1112692f60a7Smrg	} else {
1113692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1114692f60a7Smrg		       "\"%s\" is not a valid value for "
1115692f60a7Smrg		       "Option \"Interlaced\"\n", s);
1116692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are  0..2\n");
1117692f60a7Smrg        }
1118692f60a7Smrg    }
1119692f60a7Smrg
1120692f60a7Smrg    if (height_480
1121692f60a7Smrg	&& (nPtr->NeoPanelWidth == 800 || nPtr->NeoPanelWidth == 1024)) {
1122692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1123692f60a7Smrg		   "Overriding Panel height: Set to 480\n");
1124692f60a7Smrg	nPtr->NeoPanelHeight = 480;
1125692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1126692f60a7Smrg		   "Disabling LCD stretching for panel height 480\n");
1127692f60a7Smrg	nPtr->noLcdStretch = TRUE;
1128692f60a7Smrg	if (!lcdCenterOptSet)
1129692f60a7Smrg	    nPtr->lcdCenter = TRUE;
1130692f60a7Smrg    }
1131692f60a7Smrg
1132692f60a7Smrg    if (nPtr->internDisp && nPtr->externDisp)
1133692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1134692f60a7Smrg		   "Simultaneous LCD/CRT display mode\n");
1135692f60a7Smrg    else if (nPtr->externDisp)
1136692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1137692f60a7Smrg		   "External CRT only display mode\n");
1138692f60a7Smrg    else  if (nPtr->internDisp)
1139692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1140692f60a7Smrg		   "Internal LCD only display mode\n");
1141692f60a7Smrg    else {
1142692f60a7Smrg	nPtr->internDisp = ((dpy & 0x02) == 0x02);
1143692f60a7Smrg    	nPtr->externDisp = ((dpy & 0x01) == 0x01);
1144692f60a7Smrg	if (nPtr->internDisp && nPtr->externDisp)
1145692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1146692f60a7Smrg		       "Simultaneous LCD/CRT display mode\n");
1147692f60a7Smrg	else if (nPtr->externDisp)
1148692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1149692f60a7Smrg		       "External CRT only display mode\n");
1150692f60a7Smrg	else if (nPtr->internDisp)
1151692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1152692f60a7Smrg		       "Internal LCD only display mode\n");
1153692f60a7Smrg	else {
1154692f60a7Smrg	    /* this is a fallback if probed values are bogus */
1155692f60a7Smrg	    nPtr->internDisp = TRUE;
1156692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex,X_DEFAULT,
1157692f60a7Smrg		       "Internal LCD only display mode\n");
1158692f60a7Smrg	}
1159692f60a7Smrg    }
1160692f60a7Smrg
1161692f60a7Smrg    if (nPtr->noLcdStretch)
1162692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1163692f60a7Smrg		   "Low resolution video modes are not stretched\n");
1164692f60a7Smrg    if (nPtr->lcdCenter)
1165692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1166692f60a7Smrg		   "Video modes are centered on the display\n");
1167692f60a7Smrg    if (nPtr->noLinear)
1168692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using nonlinear mode\n");
1169692f60a7Smrg    else
1170692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_DEFAULT, "using linear mode\n");
1171692f60a7Smrg    if (nPtr->swCursor)
1172692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using sofware cursor\n");
1173692f60a7Smrg    if (nPtr->noMMIO)
1174692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "MMIO mode disabled\n");
1175692f60a7Smrg    if (nPtr->onPciBurst)
1176692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using PCI Burst mode\n");
1177692f60a7Smrg    if (nPtr->strangeLockups)
1178692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1179692f60a7Smrg		   "Option StrangeLockups set: disabling some acceleration\n");
1180692f60a7Smrg    if (nPtr->showcache)
1181692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1182692f60a7Smrg		   "Show chache for debugging\n");
1183692f60a7Smrg    if (nPtr->shadowFB) {
1184692f60a7Smrg	if (nPtr->noLinear) {
1185692f60a7Smrg    	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1186692f60a7Smrg		       "Option \"ShadowFB\" ignored. Not supported without"
1187692f60a7Smrg		       " linear addressing\n");
1188692f60a7Smrg	    nPtr->shadowFB = FALSE;
1189692f60a7Smrg	    nPtr->rotate = 0;
1190692f60a7Smrg	} else {
1191692f60a7Smrg	    nPtr->noAccel = TRUE;
1192692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1193692f60a7Smrg		    "Using \"Shadow Framebuffer\" - acceleration disabled\n");
1194692f60a7Smrg	}
1195692f60a7Smrg    }
1196692f60a7Smrg
1197692f60a7Smrg    nPtr->NeoFbMapSize = linearSize * 1024;
1198692f60a7Smrg    nPtr->NeoCursorOffset = CursorOff;
1199692f60a7Smrg
1200692f60a7Smrg    if (nPtr->pEnt->device->MemBase) {
1201692f60a7Smrg	/* XXX Check this matches a PCI base address */
1202692f60a7Smrg	nPtr->NeoLinearAddr = nPtr->pEnt->device->MemBase;
1203692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1204692f60a7Smrg		   "FB base address is set at 0x%lX.\n",
1205692f60a7Smrg		   nPtr->NeoLinearAddr);
1206692f60a7Smrg    } else {
1207692f60a7Smrg	nPtr->NeoLinearAddr = 0;
1208692f60a7Smrg    }
1209692f60a7Smrg
1210692f60a7Smrg    nPtr->NeoMMIOAddr2 = 0;
1211692f60a7Smrg    nPtr->NeoMMIOBase2 = NULL;
1212692f60a7Smrg    if (nPtr->pEnt->device->IOBase && !nPtr->noMMIO) {
1213692f60a7Smrg	/* XXX Check this matches a PCI base address */
1214692f60a7Smrg	nPtr->NeoMMIOAddr = nPtr->pEnt->device->IOBase;
1215692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1216692f60a7Smrg		   "MMIO base address is set at 0x%lX.\n",
1217692f60a7Smrg		   nPtr->NeoMMIOAddr);
1218692f60a7Smrg    } else {
1219692f60a7Smrg	nPtr->NeoMMIOAddr = 0;
1220692f60a7Smrg    }
1221692f60a7Smrg
1222692f60a7Smrg    if (nPtr->pEnt->location.type == BUS_PCI) {
1223692f60a7Smrg	if (!nPtr->NeoLinearAddr) {
1224692f60a7Smrg	    nPtr->NeoLinearAddr = nPtr->PciInfo->memBase[0];
1225692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1226692f60a7Smrg		       "FB base address is set at 0x%lX.\n",
1227692f60a7Smrg		       nPtr->NeoLinearAddr);
1228692f60a7Smrg	}
1229692f60a7Smrg	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
1230692f60a7Smrg	    switch (nPtr->NeoChipset) {
1231692f60a7Smrg	    case NM2070 :
1232692f60a7Smrg		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
1233692f60a7Smrg		break;
1234692f60a7Smrg	    case NM2090:
1235692f60a7Smrg	    case NM2093:
1236692f60a7Smrg		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x200000;
1237692f60a7Smrg		break;
1238692f60a7Smrg	    case NM2160:
1239692f60a7Smrg	    case NM2097:
1240692f60a7Smrg	    case NM2200:
1241692f60a7Smrg	    case NM2230:
1242692f60a7Smrg	    case NM2360:
1243692f60a7Smrg	    case NM2380:
1244692f60a7Smrg		nPtr->NeoMMIOAddr = nPtr->PciInfo->memBase[1];
1245692f60a7Smrg		nPtr->NeoMMIOAddr2 = nPtr->PciInfo->memBase[2];
1246692f60a7Smrg		break;
1247692f60a7Smrg	    }
1248692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1249692f60a7Smrg		       "MMIO base address is set at 0x%lX.\n",
1250692f60a7Smrg		       nPtr->NeoMMIOAddr);
1251692f60a7Smrg	    if (nPtr->NeoMMIOAddr2 != 0){
1252692f60a7Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1253692f60a7Smrg		           "MMIO base address2 is set at 0x%lX.\n",
1254692f60a7Smrg		           nPtr->NeoMMIOAddr2);
1255692f60a7Smrg	    }
1256692f60a7Smrg	}
1257692f60a7Smrg	/* XXX What about VGA resources in OPERATING mode? */
1258692f60a7Smrg	if (xf86RegisterResources(nPtr->pEnt->index, NULL, ResExclusive))
1259692f60a7Smrg	    RETURN;
1260692f60a7Smrg
1261692f60a7Smrg    } else if (nPtr->pEnt->location.type == BUS_ISA) {
1262692f60a7Smrg	unsigned int addr;
1263692f60a7Smrg	resRange linearRes[] = { {ResExcMemBlock|ResBios|ResBus,0,0},_END };
1264692f60a7Smrg
1265692f60a7Smrg	if (!nPtr->NeoLinearAddr) {
1266692f60a7Smrg	    VGAwGR(0x09,0x26);
1267692f60a7Smrg	    addr = VGArGR(0x13);
1268692f60a7Smrg	    VGAwGR(0x09,0x00);
1269692f60a7Smrg	    nPtr->NeoLinearAddr = addr << 20;
1270692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1271692f60a7Smrg		       "FB base address is set at 0x%lX.\n",
1272692f60a7Smrg		       nPtr->NeoLinearAddr);
1273692f60a7Smrg	}
1274692f60a7Smrg	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
1275692f60a7Smrg	    nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
1276692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1277692f60a7Smrg		       "MMIO base address is set at 0x%lX.\n",
1278692f60a7Smrg		       nPtr->NeoMMIOAddr);
1279692f60a7Smrg	}
1280692f60a7Smrg	linearRes[0].rBegin = nPtr->NeoLinearAddr;
1281692f60a7Smrg	linearRes[1].rEnd = nPtr->NeoLinearAddr + nPtr->NeoFbMapSize - 1;
1282692f60a7Smrg	if (xf86RegisterResources(nPtr->pEnt->index,linearRes,ResNone)) {
1283692f60a7Smrg	    nPtr->noLinear = TRUE; /* XXX */
1284692f60a7Smrg	}
1285692f60a7Smrg    } else
1286692f60a7Smrg	RETURN;
1287692f60a7Smrg
1288692f60a7Smrg    if (nPtr->pEnt->device->videoRam != 0) {
1289692f60a7Smrg	pScrn->videoRam = nPtr->pEnt->device->videoRam;
1290692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VideoRAM: %d kByte\n",
1291692f60a7Smrg		   pScrn->videoRam);
1292692f60a7Smrg    } else {
1293692f60a7Smrg	pScrn->videoRam = videoRam;
1294692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VideoRAM: %d kByte\n",
1295692f60a7Smrg		   pScrn->videoRam);
1296692f60a7Smrg    }
1297692f60a7Smrg
1298692f60a7Smrg    if (nPtr->pEnt->device->dacSpeeds[0] != 0) {
1299692f60a7Smrg	maxClock = nPtr->pEnt->device->dacSpeeds[0];
1300692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Max Clock: %d kHz\n",
1301692f60a7Smrg		   maxClock);
1302692f60a7Smrg    } else {
1303692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Max Clock: %d kHz\n",
1304692f60a7Smrg		   maxClock);
1305692f60a7Smrg    }
1306692f60a7Smrg
1307692f60a7Smrg    pScrn->progClock = TRUE;
1308692f60a7Smrg    /*
1309692f60a7Smrg     * Setup the ClockRanges, which describe what clock ranges are available,
1310692f60a7Smrg     * and what sort of modes they can be used for.
1311692f60a7Smrg     */
1312692f60a7Smrg    clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
1313692f60a7Smrg    clockRanges->next = NULL;
1314692f60a7Smrg    clockRanges->ClockMulFactor = 1;
1315692f60a7Smrg    clockRanges->minClock = 11000;   /* guessed §§§ */
1316692f60a7Smrg    clockRanges->maxClock = maxClock;
1317692f60a7Smrg    clockRanges->clockIndex = -1;		/* programmable */
1318692f60a7Smrg	clockRanges->interlaceAllowed = FALSE;
1319692f60a7Smrg    clockRanges->doubleScanAllowed = TRUE;
1320692f60a7Smrg
1321692f60a7Smrg    /* Subtract memory for HW cursor */
1322692f60a7Smrg    if (!nPtr->swCursor)
1323692f60a7Smrg	nPtr->NeoCursorMem = CursorMem;
1324692f60a7Smrg    else
1325692f60a7Smrg	nPtr->NeoCursorMem = 0;
1326692f60a7Smrg    apertureSize = (pScrn->videoRam * 1024) - nPtr->NeoCursorMem;
1327692f60a7Smrg
1328692f60a7Smrg    if ((nPtr->NeoPanelWidth == 800) && (nPtr->NeoPanelHeight == 480)) {
1329692f60a7Smrg	neo800x480Mode.next = pScrn->monitor->Modes;
1330692f60a7Smrg	pScrn->monitor->Modes = &neo800x480Mode;
1331692f60a7Smrg    }
1332692f60a7Smrg    if ((nPtr->NeoPanelWidth == 1024) && (nPtr->NeoPanelHeight == 480)) {
1333692f60a7Smrg	neo1024x480Mode.next = pScrn->monitor->Modes;
1334692f60a7Smrg	pScrn->monitor->Modes = &neo1024x480Mode;
1335692f60a7Smrg    }
1336692f60a7Smrg
1337692f60a7Smrg    if (!pScrn->monitor->DDC) {
1338692f60a7Smrg	/*
1339692f60a7Smrg	 * If the monitor parameters are not specified explicitly, set them
1340692f60a7Smrg	 * so that 60Hz modes up to the panel size are allowed.
1341692f60a7Smrg	 */
1342692f60a7Smrg	if (pScrn->monitor->nHsync == 0) {
1343692f60a7Smrg	    pScrn->monitor->nHsync = 1;
1344692f60a7Smrg	    pScrn->monitor->hsync[0].lo = 28;
1345692f60a7Smrg	    pScrn->monitor->hsync[0].hi =
1346692f60a7Smrg				60.0 * 1.07 * nPtr->NeoPanelHeight / 1000.0;
1347692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1348692f60a7Smrg		       "Using hsync range matching panel size: %.2f-%.2f kHz\n",
1349692f60a7Smrg		       pScrn->monitor->hsync[0].lo,
1350692f60a7Smrg		       pScrn->monitor->hsync[0].hi);
1351692f60a7Smrg	}
1352692f60a7Smrg	if (pScrn->monitor->nVrefresh == 0) {
1353692f60a7Smrg	    pScrn->monitor->nVrefresh = 1;
1354692f60a7Smrg	    pScrn->monitor->vrefresh[0].lo = 55.0;
1355692f60a7Smrg	    pScrn->monitor->vrefresh[0].hi = 65.0;
1356692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1357692f60a7Smrg		       "Using vsync range for panel: %.2f-%.2f kHz\n",
1358692f60a7Smrg		       pScrn->monitor->vrefresh[0].lo,
1359692f60a7Smrg		       pScrn->monitor->vrefresh[0].hi);
1360692f60a7Smrg	}
1361692f60a7Smrg    }
1362692f60a7Smrg
1363692f60a7Smrg    /*
1364692f60a7Smrg     * For external displays, limit the width to 1024 pixels or less.
1365692f60a7Smrg     */
1366692f60a7Smrg    {
1367692f60a7Smrg       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
1368692f60a7Smrg			  pScrn->display->modes, clockRanges,
1369692f60a7Smrg			  NULL, 256, maxWidth,(8 * pScrn->bitsPerPixel),/*§§§*/
1370692f60a7Smrg			  128, maxHeight, pScrn->display->virtualX,
1371692f60a7Smrg			  pScrn->display->virtualY, apertureSize,
1372692f60a7Smrg			  LOOKUP_BEST_REFRESH);
1373692f60a7Smrg
1374692f60a7Smrg       if (i == -1)
1375692f60a7Smrg           RETURN;
1376692f60a7Smrg    }
1377692f60a7Smrg
1378692f60a7Smrg    /* Prune the modes marked as invalid */
1379692f60a7Smrg    xf86PruneDriverModes(pScrn);
1380692f60a7Smrg
1381692f60a7Smrg    if (i == 0 || pScrn->modes == NULL) {
1382692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1383692f60a7Smrg	RETURN;
1384692f60a7Smrg    }
1385692f60a7Smrg
1386692f60a7Smrg    /*
1387692f60a7Smrg     * Set the CRTC parameters for all of the modes based on the type
1388692f60a7Smrg     * of mode, and the chipset's interlace requirements.
1389692f60a7Smrg     *
1390692f60a7Smrg     * Calling this is required if the mode->Crtc* values are used by the
1391692f60a7Smrg     * driver and if the driver doesn't provide code to set them.  They
1392692f60a7Smrg     * are not pre-initialised at all.
1393692f60a7Smrg     */
1394692f60a7Smrg    xf86SetCrtcForModes(pScrn, 0);
1395692f60a7Smrg
1396692f60a7Smrg    /* Set the current mode to the first in the list */
1397692f60a7Smrg    pScrn->currentMode = pScrn->modes;
1398692f60a7Smrg
1399692f60a7Smrg    /* Print the list of modes being used */
1400692f60a7Smrg    xf86PrintModes(pScrn);
1401692f60a7Smrg
1402692f60a7Smrg    /* If monitor resolution is set on the command line, use it */
1403692f60a7Smrg    xf86SetDpi(pScrn, 0, 0);
1404692f60a7Smrg
1405692f60a7Smrg    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
1406692f60a7Smrg	RETURN;
1407692f60a7Smrg    }
1408692f60a7Smrg
1409692f60a7Smrg    xf86LoaderReqSymLists(fbSymbols, NULL);
1410692f60a7Smrg
1411692f60a7Smrg    if (!nPtr->noLinear) {
1412692f60a7Smrg	if (!xf86LoadSubModule(pScrn, "xaa"))
1413692f60a7Smrg	    RETURN;
1414692f60a7Smrg	xf86LoaderReqSymLists(xaaSymbols, NULL);
1415692f60a7Smrg    }
1416692f60a7Smrg
1417692f60a7Smrg    if (nPtr->shadowFB) {
1418692f60a7Smrg	if (!xf86LoadSubModule(pScrn, "shadow")) {
1419692f60a7Smrg	    RETURN;
1420692f60a7Smrg	}
1421692f60a7Smrg	xf86LoaderReqSymLists(shadowSymbols, NULL);
1422692f60a7Smrg    }
1423692f60a7Smrg
1424692f60a7Smrg    if (!nPtr->swCursor) {
1425692f60a7Smrg	if (!xf86LoadSubModule(pScrn, "ramdac"))
1426692f60a7Smrg	    RETURN;
1427692f60a7Smrg	xf86LoaderReqSymLists(ramdacSymbols, NULL);
1428692f60a7Smrg    }
1429692f60a7Smrg    return TRUE;
1430692f60a7Smrg}
1431692f60a7Smrg#undef RETURN
1432692f60a7Smrg
1433692f60a7Smrg/* Mandatory */
1434692f60a7Smrgstatic Bool
1435692f60a7SmrgNEOEnterVT(int scrnIndex, int flags)
1436692f60a7Smrg{
1437692f60a7Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1438692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
1439692f60a7Smrg
1440692f60a7Smrg    /* Should we re-save the text mode on each VT enter? */
1441692f60a7Smrg    if(!neoModeInit(pScrn, pScrn->currentMode))
1442692f60a7Smrg      return FALSE;
1443692f60a7Smrg
1444692f60a7Smrg    if (nPtr->video)
1445692f60a7Smrg	NEOResetVideo(pScrn);
1446692f60a7Smrg
1447692f60a7Smrg    if (nPtr->NeoHWCursorShown)
1448692f60a7Smrg	NeoShowCursor(pScrn);
1449692f60a7Smrg    NEOAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1450692f60a7Smrg
1451692f60a7Smrg    return TRUE;
1452692f60a7Smrg}
1453692f60a7Smrg
1454692f60a7Smrg/* Mandatory */
1455692f60a7Smrgstatic void
1456692f60a7SmrgNEOLeaveVT(int scrnIndex, int flags)
1457692f60a7Smrg{
1458692f60a7Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1459692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
1460692f60a7Smrg
1461692f60a7Smrg    /* Invalidate the cached acceleration registers */
1462692f60a7Smrg    if (nPtr->NeoHWCursorShown)
1463692f60a7Smrg	NeoHideCursor(pScrn);
1464692f60a7Smrg    neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
1465692f60a7Smrg    neoLock(pScrn);
1466692f60a7Smrg
1467692f60a7Smrg}
1468692f60a7Smrg
1469692f60a7Smrgstatic void
1470692f60a7SmrgNEOLoadPalette(
1471692f60a7Smrg   ScrnInfoPtr pScrn,
1472692f60a7Smrg   int numColors,
1473692f60a7Smrg   int *indices,
1474692f60a7Smrg   LOCO *colors,
1475692f60a7Smrg   VisualPtr pVisual
1476692f60a7Smrg){
1477692f60a7Smrg   int i, index, shift, Gshift;
1478692f60a7Smrg   vgaHWPtr hwp = VGAHWPTR(pScrn);
1479692f60a7Smrg
1480692f60a7Smrg   switch(pScrn->depth) {
1481692f60a7Smrg   case 15:
1482692f60a7Smrg	shift = Gshift = 1;
1483692f60a7Smrg	break;
1484692f60a7Smrg   case 16:
1485692f60a7Smrg	shift = 0;
1486692f60a7Smrg        Gshift = 0;
1487692f60a7Smrg	break;
1488692f60a7Smrg   default:
1489692f60a7Smrg	shift = Gshift = 0;
1490692f60a7Smrg	break;
1491692f60a7Smrg   }
1492692f60a7Smrg
1493692f60a7Smrg   for(i = 0; i < numColors; i++) {
1494692f60a7Smrg        index = indices[i];
1495692f60a7Smrg        hwp->writeDacWriteAddr(hwp, index);
1496692f60a7Smrg	DACDelay(hwp);
1497692f60a7Smrg        hwp->writeDacData(hwp, colors[index].red << shift);
1498692f60a7Smrg	DACDelay(hwp);
1499692f60a7Smrg        hwp->writeDacData(hwp, colors[index].green << Gshift);
1500692f60a7Smrg	DACDelay(hwp);
1501692f60a7Smrg        hwp->writeDacData(hwp, colors[index].blue << shift);
1502692f60a7Smrg	DACDelay(hwp);
1503692f60a7Smrg   }
1504692f60a7Smrg}
1505692f60a7Smrg
1506692f60a7Smrg/* Mandatory */
1507692f60a7Smrgstatic Bool
1508692f60a7SmrgNEOScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
1509692f60a7Smrg{
1510692f60a7Smrg    ScrnInfoPtr pScrn;
1511692f60a7Smrg    vgaHWPtr hwp;
1512692f60a7Smrg    NEOPtr nPtr;
1513692f60a7Smrg    NEOACLPtr nAcl;
1514692f60a7Smrg    int ret;
1515692f60a7Smrg    VisualPtr visual;
1516692f60a7Smrg    int allocatebase, freespace, currentaddr;
1517692f60a7Smrg    unsigned int racflag = RAC_FB;
1518692f60a7Smrg    unsigned char *FBStart;
1519692f60a7Smrg    int height, width, displayWidth;
1520692f60a7Smrg
1521692f60a7Smrg    /*
1522692f60a7Smrg     * we need to get the ScrnInfoRec for this screen, so let's allocate
1523692f60a7Smrg     * one first thing
1524692f60a7Smrg     */
1525692f60a7Smrg    pScrn = xf86Screens[pScreen->myNum];
1526692f60a7Smrg    nPtr = NEOPTR(pScrn);
1527692f60a7Smrg    nAcl = NEOACLPTR(pScrn);
1528692f60a7Smrg
1529692f60a7Smrg    hwp = VGAHWPTR(pScrn);
1530692f60a7Smrg    hwp->MapSize = 0x10000;		/* Standard 64k VGA window */
1531692f60a7Smrg    /* Map the VGA memory */
1532692f60a7Smrg    if (!vgaHWMapMem(pScrn))
1533692f60a7Smrg	return FALSE;
1534692f60a7Smrg
1535692f60a7Smrg    /* Map the Neo memory and possible MMIO areas */
1536692f60a7Smrg    if (!neoMapMem(pScrn))
1537692f60a7Smrg	return FALSE;
1538692f60a7Smrg
1539692f60a7Smrg    /*
1540692f60a7Smrg     * next we save the current state and setup the first mode
1541692f60a7Smrg     */
1542692f60a7Smrg    neoSave(pScrn);
1543692f60a7Smrg
1544692f60a7Smrg    if (!neoModeInit(pScrn,pScrn->currentMode))
1545692f60a7Smrg	return FALSE;
1546692f60a7Smrg    vgaHWSaveScreen(pScreen,SCREEN_SAVER_ON);
1547692f60a7Smrg    NEOAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1548692f60a7Smrg
1549692f60a7Smrg    /*
1550692f60a7Smrg     * Reset visual list.
1551692f60a7Smrg     */
1552692f60a7Smrg    miClearVisualTypes();
1553692f60a7Smrg
1554692f60a7Smrg    /* Setup the visuals we support. */
1555692f60a7Smrg#if 0
1556692f60a7Smrg    if (!miSetVisualTypes(pScrn->depth,
1557692f60a7Smrg      		      miGetDefaultVisualMask(pScrn->depth),
1558692f60a7Smrg		      pScrn->rgbBits, pScrn->defaultVisual))
1559692f60a7Smrg         return FALSE;
1560692f60a7Smrg#else
1561692f60a7Smrg    if (!miSetVisualTypes(pScrn->depth,
1562692f60a7Smrg      		      miGetDefaultVisualMask(pScrn->depth),
1563692f60a7Smrg		      pScrn->rgbBits, pScrn->defaultVisual))
1564692f60a7Smrg         return FALSE;
1565692f60a7Smrg    if (pScrn->depth > 8) {
1566692f60a7Smrg	if (!miSetVisualTypes(8, miGetDefaultVisualMask(8), 6,
1567692f60a7Smrg			      pScrn->defaultVisual))
1568692f60a7Smrg	    return FALSE;
1569692f60a7Smrg    }
1570692f60a7Smrg#endif
1571692f60a7Smrg    if (!miSetPixmapDepths ()) return FALSE;
1572692f60a7Smrg
1573692f60a7Smrg    /*
1574692f60a7Smrg     * Call the framebuffer layer's ScreenInit function, and fill in other
1575692f60a7Smrg     * pScreen fields.
1576692f60a7Smrg     */
1577692f60a7Smrg    displayWidth = pScrn->displayWidth;
1578692f60a7Smrg    if (nPtr->rotate) {
1579692f60a7Smrg	height = pScrn->virtualX;
1580692f60a7Smrg	width = pScrn->virtualY;
1581692f60a7Smrg    } else {
1582692f60a7Smrg	width = pScrn->virtualX;
1583692f60a7Smrg	height = pScrn->virtualY;
1584692f60a7Smrg    }
1585692f60a7Smrg
1586692f60a7Smrg    if(nPtr->shadowFB) {
1587692f60a7Smrg	nPtr->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
1588692f60a7Smrg	nPtr->ShadowPtr = xalloc(nPtr->ShadowPitch * height);
1589692f60a7Smrg	displayWidth = nPtr->ShadowPitch / (pScrn->bitsPerPixel >> 3);
1590692f60a7Smrg	FBStart = nPtr->ShadowPtr;
1591692f60a7Smrg    } else {
1592692f60a7Smrg	nPtr->ShadowPtr = NULL;
1593692f60a7Smrg	FBStart = nPtr->NeoFbBase;
1594692f60a7Smrg    }
1595692f60a7Smrg
1596692f60a7Smrg    ret = fbScreenInit(pScreen, FBStart,
1597692f60a7Smrg			    width, height,
1598692f60a7Smrg			    pScrn->xDpi, pScrn->yDpi,
1599692f60a7Smrg			    displayWidth, pScrn->bitsPerPixel);
1600692f60a7Smrg    if (!ret)
1601692f60a7Smrg	return FALSE;
1602692f60a7Smrg    if (pScrn->depth > 8) {
1603692f60a7Smrg        /* Fixup RGB ordering */
1604692f60a7Smrg        visual = pScreen->visuals + pScreen->numVisuals;
1605692f60a7Smrg        while (--visual >= pScreen->visuals) {
1606692f60a7Smrg	    if ((visual->class | DynamicClass) == DirectColor
1607692f60a7Smrg		&& visual->nplanes > 8) {
1608692f60a7Smrg		visual->offsetRed = pScrn->offset.red;
1609692f60a7Smrg		visual->offsetGreen = pScrn->offset.green;
1610692f60a7Smrg		visual->offsetBlue = pScrn->offset.blue;
1611692f60a7Smrg		visual->redMask = pScrn->mask.red;
1612692f60a7Smrg		visual->greenMask = pScrn->mask.green;
1613692f60a7Smrg		visual->blueMask = pScrn->mask.blue;
1614692f60a7Smrg	    }
1615692f60a7Smrg	}
1616692f60a7Smrg    }
1617692f60a7Smrg
1618692f60a7Smrg    /* must be after RGB ordering fixed */
1619692f60a7Smrg    fbPictureInit(pScreen, 0, 0);
1620692f60a7Smrg
1621692f60a7Smrg    xf86SetBlackWhitePixels(pScreen);
1622692f60a7Smrg
1623692f60a7Smrg    if (!nPtr->shadowFB)
1624692f60a7Smrg	NEODGAInit(pScreen);
1625692f60a7Smrg
1626692f60a7Smrg    nPtr->NeoHWCursorShown = FALSE;
1627692f60a7Smrg    nPtr->NeoHWCursorInitialized = FALSE;
1628692f60a7Smrg    nAcl->UseHWCursor = FALSE;
1629692f60a7Smrg    nAcl->CursorAddress = -1;
1630692f60a7Smrg
1631692f60a7Smrg    if (nPtr->noLinear) {
1632692f60a7Smrg	miBankInfoPtr pBankInfo;
1633692f60a7Smrg
1634692f60a7Smrg	/* Setup the vga banking variables */
1635692f60a7Smrg	pBankInfo = (miBankInfoPtr)xnfcalloc(sizeof(miBankInfoRec),1);
1636692f60a7Smrg	if (pBankInfo == NULL)
1637692f60a7Smrg	    return FALSE;
1638692f60a7Smrg
1639692f60a7Smrg	pBankInfo->pBankA = hwp->Base;
1640692f60a7Smrg	pBankInfo->pBankB = (unsigned char *)hwp->Base;
1641692f60a7Smrg	pBankInfo->BankSize = 0x10000;
1642692f60a7Smrg	pBankInfo->nBankDepth = pScrn->depth;
1643692f60a7Smrg
1644692f60a7Smrg	pBankInfo->SetSourceBank = (miBankProcPtr)NEOSetRead;
1645692f60a7Smrg	pBankInfo->SetDestinationBank =
1646692f60a7Smrg	    (miBankProcPtr)NEOSetWrite;
1647692f60a7Smrg	pBankInfo->SetSourceAndDestinationBanks =
1648692f60a7Smrg	    (miBankProcPtr)NEOSetReadWrite;
1649692f60a7Smrg	if (!miInitializeBanking(pScreen, pScrn->virtualX, pScrn->virtualY,
1650692f60a7Smrg				 pScrn->displayWidth, pBankInfo)) {
1651692f60a7Smrg	    xfree(pBankInfo);
1652692f60a7Smrg	    pBankInfo = NULL;
1653692f60a7Smrg	    return FALSE;
1654692f60a7Smrg	}
1655692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Using nonlinear mode\n");
1656692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Using software cursor in "
1657692f60a7Smrg		   "nonlinear mode\n");
1658692f60a7Smrg    } else {
1659692f60a7Smrg	nAcl->cacheStart = -1;
1660692f60a7Smrg	nAcl->cacheEnd = -1;
1661692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1662692f60a7Smrg		   "Using linear framebuffer at: 0x%08lX\n",
1663692f60a7Smrg		   nPtr->NeoLinearAddr);
1664692f60a7Smrg	/* Setup pointers to free space in video ram */
1665692f60a7Smrg	allocatebase = (pScrn->videoRam << 10);
1666692f60a7Smrg	freespace = allocatebase - pScrn->displayWidth *
1667692f60a7Smrg	    pScrn->virtualY * (pScrn->bitsPerPixel >> 3);
1668692f60a7Smrg	currentaddr = allocatebase;
1669692f60a7Smrg	xf86DrvMsg(scrnIndex, X_PROBED,
1670692f60a7Smrg		   "%d bytes off-screen memory available\n", freespace);
1671692f60a7Smrg
1672692f60a7Smrg	if (nPtr->swCursor || !nPtr->NeoMMIOBase) {
1673692f60a7Smrg	    xf86DrvMsg(scrnIndex, X_CONFIG,
1674692f60a7Smrg		       "Using Software Cursor.\n");
1675692f60a7Smrg	} else if (nPtr->NeoCursorMem <= freespace) {
1676692f60a7Smrg	    currentaddr -= nPtr->NeoCursorMem;
1677692f60a7Smrg	    freespace  -= nPtr->NeoCursorMem;
1678692f60a7Smrg	    /* alignment */
1679692f60a7Smrg	    freespace  -= currentaddr & 0x3FF;
1680692f60a7Smrg	    currentaddr &= 0xfffffc00;
1681692f60a7Smrg	    nAcl->CursorAddress = currentaddr;
1682692f60a7Smrg	    xf86DrvMsg(scrnIndex, X_INFO,
1683692f60a7Smrg		       "Using H/W Cursor.\n");
1684692f60a7Smrg	} else {
1685692f60a7Smrg	    xf86DrvMsg(scrnIndex, X_ERROR,
1686692f60a7Smrg		       "Too little space for H/W cursor.\n");
1687692f60a7Smrg	}
1688692f60a7Smrg
1689692f60a7Smrg	if (!nPtr->noAccel && !nPtr->NeoMMIOBase)
1690692f60a7Smrg	  xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1691692f60a7Smrg		     "Acceleration disabled when not using MMIO\n");
1692692f60a7Smrg
1693692f60a7Smrg	if (nPtr->overlay > 0){
1694692f60a7Smrg	    if (nPtr->overlay > freespace){
1695692f60a7Smrg		xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1696692f60a7Smrg			   "Can not reserve %d bytes for overlay. "
1697692f60a7Smrg			   "Resize to %d bytes.\n",
1698692f60a7Smrg			   nPtr->overlay, freespace);
1699692f60a7Smrg		nPtr->overlay = freespace;
1700692f60a7Smrg	    }
1701692f60a7Smrg	    currentaddr -= nPtr->overlay;
1702692f60a7Smrg	    freespace -= nPtr->overlay;
1703692f60a7Smrg	    nPtr->overlay_offset = currentaddr;
1704692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Overlay at 0x%x\n",
1705692f60a7Smrg		       nPtr->overlay_offset);
1706692f60a7Smrg	}
1707692f60a7Smrg
1708692f60a7Smrg	nAcl->cacheStart = currentaddr - freespace;
1709692f60a7Smrg	nAcl->cacheEnd = currentaddr;
1710692f60a7Smrg	freespace = 0;
1711692f60a7Smrg	if (nAcl->cacheStart < nAcl->cacheEnd) {
1712692f60a7Smrg	    BoxRec AvailFBArea;
1713692f60a7Smrg	    int lines = nAcl->cacheEnd /
1714692f60a7Smrg		(pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
1715692f60a7Smrg	    if (!nPtr->noAccel && nPtr->NeoMMIOBase && lines > 1024)
1716692f60a7Smrg		lines = 1024;
1717692f60a7Smrg	    AvailFBArea.x1 = 0;
1718692f60a7Smrg	    AvailFBArea.y1 = 0;
1719692f60a7Smrg	    AvailFBArea.x2 = pScrn->displayWidth;
1720692f60a7Smrg	    AvailFBArea.y2 = lines;
1721692f60a7Smrg	    xf86InitFBManager(pScreen, &AvailFBArea);
1722692f60a7Smrg
1723692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1724692f60a7Smrg		       "Using %i scanlines of offscreen memory \n",
1725692f60a7Smrg		       lines - pScrn->virtualY);
1726692f60a7Smrg	}
1727692f60a7Smrg
1728692f60a7Smrg	/* Setup the acceleration primitives */
1729692f60a7Smrg	if (!nPtr->noAccel && nPtr->NeoMMIOBase) {
1730692f60a7Smrg	    Bool ret = FALSE;
1731692f60a7Smrg	    if (nAcl->cacheStart >= nAcl->cacheEnd) {
1732692f60a7Smrg		xf86DrvMsg(scrnIndex, X_ERROR,
1733692f60a7Smrg			   "Too little space for pixmap cache.\n");
1734692f60a7Smrg	    }
1735692f60a7Smrg	    switch(nPtr->NeoChipset) {
1736692f60a7Smrg	    case NM2070 :
1737692f60a7Smrg		ret = Neo2070AccelInit(pScreen);
1738692f60a7Smrg		break;
1739692f60a7Smrg	    case NM2090 :
1740692f60a7Smrg	    case NM2093 :
1741692f60a7Smrg		ret = Neo2090AccelInit(pScreen);
1742692f60a7Smrg		break;
1743692f60a7Smrg	    case NM2097 :
1744692f60a7Smrg	    case NM2160 :
1745692f60a7Smrg		ret = Neo2097AccelInit(pScreen);
1746692f60a7Smrg		break;
1747692f60a7Smrg	    case NM2200 :
1748692f60a7Smrg	    case NM2230 :
1749692f60a7Smrg	    case NM2360 :
1750692f60a7Smrg	    case NM2380 :
1751692f60a7Smrg	        ret = Neo2200AccelInit(pScreen);
1752692f60a7Smrg		break;
1753692f60a7Smrg	    }
1754692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1755692f60a7Smrg		       "Acceleration %s Initialized\n",ret ? "" : "not");
1756692f60a7Smrg	}
1757692f60a7Smrg
1758692f60a7Smrg    }
1759692f60a7Smrg    miInitializeBackingStore(pScreen);
1760692f60a7Smrg    xf86SetBackingStore(pScreen);
1761692f60a7Smrg    xf86SetSilkenMouse(pScreen);
1762692f60a7Smrg
1763692f60a7Smrg    /* Initialise cursor functions */
1764692f60a7Smrg    miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
1765692f60a7Smrg
1766692f60a7Smrg    if (nAcl->CursorAddress != -1) {
1767692f60a7Smrg      /* HW cursor functions */
1768692f60a7Smrg      if (!NeoCursorInit(pScreen)) {
1769692f60a7Smrg	xf86DrvMsg(scrnIndex, X_ERROR,
1770692f60a7Smrg		   "Hardware cursor initialization failed\n");
1771692f60a7Smrg	return FALSE;
1772692f60a7Smrg      }
1773692f60a7Smrg      nAcl->UseHWCursor = TRUE;
1774692f60a7Smrg      nPtr->NeoHWCursorInitialized = TRUE;
1775692f60a7Smrg    } else
1776692f60a7Smrg      nAcl->UseHWCursor = FALSE;
1777692f60a7Smrg
1778692f60a7Smrg    if (nPtr->shadowFB) {
1779692f60a7Smrg        nPtr->refreshArea = neoRefreshArea;
1780692f60a7Smrg
1781692f60a7Smrg	if(nPtr->rotate) {
1782692f60a7Smrg	    if (!nPtr->PointerMoved) {
1783692f60a7Smrg		nPtr->PointerMoved = pScrn->PointerMoved;
1784692f60a7Smrg		pScrn->PointerMoved = neoPointerMoved;
1785692f60a7Smrg	    }
1786692f60a7Smrg	    switch(pScrn->bitsPerPixel) {
1787692f60a7Smrg	    case 8:	nPtr->refreshArea = neoRefreshArea8;	break;
1788692f60a7Smrg	    case 16:	nPtr->refreshArea = neoRefreshArea16;	break;
1789692f60a7Smrg	    case 24:	nPtr->refreshArea = neoRefreshArea24;	break;
1790692f60a7Smrg	    case 32:	nPtr->refreshArea = neoRefreshArea32;	break;
1791692f60a7Smrg	    }
1792692f60a7Smrg	}
1793692f60a7Smrg#if 0
1794692f60a7Smrg	ShadowFBInit(pScreen, nPtr->refreshArea);
1795692f60a7Smrg#else
1796692f60a7Smrg	shadowInit (pScreen, neoShadowUpdate, 0);
1797692f60a7Smrg#endif
1798692f60a7Smrg    }
1799692f60a7Smrg
1800692f60a7Smrg    /* Initialise default colourmap */
1801692f60a7Smrg    if(!miCreateDefColormap(pScreen))
1802692f60a7Smrg	return FALSE;
1803692f60a7Smrg
1804692f60a7Smrg    if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits,
1805692f60a7Smrg                         NEOLoadPalette, NULL,
1806692f60a7Smrg                         CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH))
1807692f60a7Smrg	return FALSE;
1808692f60a7Smrg
1809692f60a7Smrg	if (pScrn->depth == 16)
1810692f60a7Smrg	    xxSetup(pScreen,8, pScrn->depth, NULL, nPtr->accelSync); /*@!@*/
1811692f60a7Smrg
1812692f60a7Smrg    racflag |= RAC_COLORMAP;
1813692f60a7Smrg    if (nPtr->NeoHWCursorInitialized)
1814692f60a7Smrg        racflag |= RAC_CURSOR;
1815692f60a7Smrg
1816692f60a7Smrg    pScrn->racIoFlags = pScrn->racMemFlags = racflag;
1817692f60a7Smrg
1818692f60a7Smrg    NEOInitVideo(pScreen);
1819692f60a7Smrg
1820692f60a7Smrg    pScreen->SaveScreen = vgaHWSaveScreenWeak();
1821692f60a7Smrg
1822692f60a7Smrg    /* Setup DPMS mode */
1823692f60a7Smrg    if (nPtr->NeoChipset != NM2070)
1824692f60a7Smrg	xf86DPMSInit(pScreen, (DPMSSetProcPtr)NeoDisplayPowerManagementSet,
1825692f60a7Smrg		     0);
1826692f60a7Smrg
1827692f60a7Smrg    if (!nPtr->noLinear) {
1828692f60a7Smrg	pScrn->memPhysBase = (unsigned long)nPtr->NeoLinearAddr;
1829692f60a7Smrg	pScrn->fbOffset = 0;
1830692f60a7Smrg    }
1831692f60a7Smrg
1832692f60a7Smrg    /* Wrap the current CloseScreen function */
1833692f60a7Smrg    nPtr->CloseScreen = pScreen->CloseScreen;
1834692f60a7Smrg    pScreen->CloseScreen = NEOCloseScreen;
1835692f60a7Smrg
1836692f60a7Smrg    /* Report any unused options (only for the first generation) */
1837692f60a7Smrg    if (serverGeneration == 1) {
1838692f60a7Smrg	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1839692f60a7Smrg    }
1840692f60a7Smrg
1841692f60a7Smrg    return TRUE;
1842692f60a7Smrg}
1843692f60a7Smrg
1844692f60a7Smrg/* Mandatory */
1845692f60a7SmrgBool
1846692f60a7SmrgNEOSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
1847692f60a7Smrg{
1848692f60a7Smrg    return neoModeInit(xf86Screens[scrnIndex], mode);
1849692f60a7Smrg}
1850692f60a7Smrg
1851692f60a7Smrg/* Mandatory */
1852692f60a7Smrgvoid
1853692f60a7SmrgNEOAdjustFrame(int scrnIndex, int x, int y, int flags)
1854692f60a7Smrg{
1855692f60a7Smrg    ScrnInfoPtr pScrn;
1856692f60a7Smrg    NEOPtr nPtr;
1857692f60a7Smrg    vgaHWPtr hwp;
1858692f60a7Smrg    int oldExtCRTDispAddr;
1859692f60a7Smrg    int Base;
1860692f60a7Smrg
1861692f60a7Smrg    pScrn = xf86Screens[scrnIndex];
1862692f60a7Smrg    hwp = VGAHWPTR(pScrn);
1863692f60a7Smrg    nPtr = NEOPTR(pScrn);
1864692f60a7Smrg
1865692f60a7Smrg    if (nPtr->showcache && y) {
1866692f60a7Smrg	int lastline = nPtr->NeoFbMapSize /
1867692f60a7Smrg	    ((pScrn->displayWidth * pScrn->bitsPerPixel) / 8);
1868692f60a7Smrg
1869692f60a7Smrg	lastline -= pScrn->currentMode->VDisplay;
1870692f60a7Smrg	y += pScrn->virtualY - 1;
1871692f60a7Smrg        if (y > lastline) y = lastline;
1872692f60a7Smrg    }
1873692f60a7Smrg
1874692f60a7Smrg    Base = (y * pScrn->displayWidth + x) >> 2;
1875692f60a7Smrg
1876692f60a7Smrg    /* Scale Base by the number of bytes per pixel. */
1877692f60a7Smrg    switch (pScrn->depth) {
1878692f60a7Smrg    case  8 :
1879692f60a7Smrg	break;
1880692f60a7Smrg    case 15 :
1881692f60a7Smrg    case 16 :
1882692f60a7Smrg	Base *= 2;
1883692f60a7Smrg	break;
1884692f60a7Smrg    case 24 :
1885692f60a7Smrg	Base *= 3;
1886692f60a7Smrg	break;
1887692f60a7Smrg    default :
1888692f60a7Smrg	break;
1889692f60a7Smrg    }
1890692f60a7Smrg    /*
1891692f60a7Smrg     * These are the generic starting address registers.
1892692f60a7Smrg     */
1893692f60a7Smrg    VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
1894692f60a7Smrg    VGAwCR(0x0D, (Base & 0x00FF));
1895692f60a7Smrg
1896692f60a7Smrg    /*
1897692f60a7Smrg     * Make sure we don't clobber some other bits that might already
1898692f60a7Smrg     * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
1899692f60a7Smrg     * be needed.
1900692f60a7Smrg     */
1901692f60a7Smrg    oldExtCRTDispAddr = VGArGR(0x0E);
1902692f60a7Smrg    VGAwGR(0x0E,(((Base >> 16) & 0x07) | (oldExtCRTDispAddr & 0xf8)));
1903692f60a7Smrg#if 0
1904692f60a7Smrg    /*
1905692f60a7Smrg     * This is a workaround for a higher level bug that causes the cursor
1906692f60a7Smrg     * to be at the wrong position after a virtual screen resolution change
1907692f60a7Smrg     */
1908692f60a7Smrg    if (nPtr->NeoHWCursorInitialized) { /*§§§ do we still need this?*/
1909692f60a7Smrg	NeoRepositionCursor();
1910692f60a7Smrg    }
1911692f60a7Smrg#endif
1912692f60a7Smrg}
1913692f60a7Smrg
1914692f60a7Smrg/* Mandatory */
1915692f60a7Smrgstatic Bool
1916692f60a7SmrgNEOCloseScreen(int scrnIndex, ScreenPtr pScreen)
1917692f60a7Smrg{
1918692f60a7Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1919692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
1920692f60a7Smrg
1921692f60a7Smrg    if(pScrn->vtSema){
1922692f60a7Smrg	if (nPtr->NeoHWCursorShown)
1923692f60a7Smrg	    NeoHideCursor(pScrn);
1924692f60a7Smrg	neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
1925692f60a7Smrg
1926692f60a7Smrg	neoLock(pScrn);
1927692f60a7Smrg	neoUnmapMem(pScrn);
1928692f60a7Smrg    }
1929692f60a7Smrg    if (nPtr->AccelInfoRec)
1930692f60a7Smrg	XAADestroyInfoRec(nPtr->AccelInfoRec);
1931692f60a7Smrg    if (nPtr->CursorInfo)
1932692f60a7Smrg	xf86DestroyCursorInfoRec(nPtr->CursorInfo);
1933692f60a7Smrg    if (nPtr->ShadowPtr)
1934692f60a7Smrg	xfree(nPtr->ShadowPtr);
1935692f60a7Smrg
1936692f60a7Smrg    pScrn->vtSema = FALSE;
1937692f60a7Smrg    pScreen->CloseScreen = nPtr->CloseScreen;
1938692f60a7Smrg    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
1939692f60a7Smrg}
1940692f60a7Smrg
1941692f60a7Smrg/* Optional */
1942692f60a7Smrgstatic void
1943692f60a7SmrgNEOFreeScreen(int scrnIndex, int flags)
1944692f60a7Smrg{
1945692f60a7Smrg    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
1946692f60a7Smrg	vgaHWFreeHWRec(xf86Screens[scrnIndex]);
1947692f60a7Smrg    NEOFreeRec(xf86Screens[scrnIndex]);
1948692f60a7Smrg}
1949692f60a7Smrg
1950692f60a7Smrg/* Optional */
1951692f60a7Smrgstatic ModeStatus
1952692f60a7SmrgNEOValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
1953692f60a7Smrg{
1954692f60a7Smrg    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1955692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
1956692f60a7Smrg    int vDisplay = mode->VDisplay * ((mode->Flags & V_DBLSCAN) ? 2 : 1);
1957692f60a7Smrg
1958692f60a7Smrg    /*
1959692f60a7Smrg     * Is there any LineCompare Bit 10? Where?
1960692f60a7Smrg     * The 9 well known VGA bits give us a maximum height of 1024
1961692f60a7Smrg     */
1962692f60a7Smrg    if (vDisplay > 1024)
1963692f60a7Smrg	return MODE_BAD;
1964692f60a7Smrg
1965692f60a7Smrg    /*
1966692f60a7Smrg     * Limit the modes to just those allowed by the various NeoMagic
1967692f60a7Smrg     * chips.
1968692f60a7Smrg     */
1969692f60a7Smrg
1970692f60a7Smrg    if (nPtr->overrideValidate) {
1971692f60a7Smrg	xf86DrvMsg(scrnIndex, X_WARNING, "display mode validation disabled\n");
1972692f60a7Smrg    } else {
1973692f60a7Smrg	/*
1974692f60a7Smrg	 * When the LCD is active, only allow modes that are (1) equal to
1975692f60a7Smrg	 * or smaller than the size of the panel and (2) are one of the
1976692f60a7Smrg	 * following sizes: 1024x768, 800x600, 640x480.
1977692f60a7Smrg	 */
1978692f60a7Smrg	if (nPtr->internDisp || !nPtr->externDisp) {
1979692f60a7Smrg	    /* Is the mode larger than the LCD panel? */
1980692f60a7Smrg	    if ((mode->HDisplay > nPtr->NeoPanelWidth) ||
1981692f60a7Smrg		(vDisplay > nPtr->NeoPanelHeight)) {
1982692f60a7Smrg		xf86DrvMsg(scrnIndex,X_INFO, "Removing mode (%dx%d) "
1983692f60a7Smrg			   "larger than the LCD panel (%dx%d)\n",
1984692f60a7Smrg			   mode->HDisplay,
1985692f60a7Smrg			   mode->VDisplay,
1986692f60a7Smrg			   nPtr->NeoPanelWidth,
1987692f60a7Smrg			   nPtr->NeoPanelHeight);
1988692f60a7Smrg		return(MODE_BAD);
1989692f60a7Smrg	    }
1990692f60a7Smrg
1991692f60a7Smrg	    /* Is the mode one of the acceptable sizes? */
1992692f60a7Smrg	    switch (mode->HDisplay) {
1993692f60a7Smrg	    case 1280:
1994692f60a7Smrg		if (mode->VDisplay == 1024)
1995692f60a7Smrg		    return(MODE_OK);
1996692f60a7Smrg		break;
1997692f60a7Smrg	    case 1024 :
1998692f60a7Smrg		if (mode->VDisplay == 768)
1999692f60a7Smrg		    return(MODE_OK);
2000692f60a7Smrg		if ((mode->VDisplay == 480) && (nPtr->NeoPanelHeight == 480))
2001692f60a7Smrg		    return(MODE_OK);
2002692f60a7Smrg		break;
2003692f60a7Smrg	    case  800 :
2004692f60a7Smrg		if (mode->VDisplay == 600)
2005692f60a7Smrg		    return(MODE_OK);
2006692f60a7Smrg		if ((mode->VDisplay == 480) && (nPtr->NeoPanelHeight == 480))
2007692f60a7Smrg		    return(MODE_OK);
2008692f60a7Smrg		break;
2009692f60a7Smrg	    case  640 :
2010692f60a7Smrg		if (mode->VDisplay == 480)
2011692f60a7Smrg		    return(MODE_OK);
2012692f60a7Smrg		break;
2013692f60a7Smrg#if 1
2014692f60a7Smrg	    case 320:
2015692f60a7Smrg		if (mode->VDisplay == 240)
2016692f60a7Smrg		    return(MODE_OK);
2017692f60a7Smrg		break;
2018692f60a7Smrg#endif
2019692f60a7Smrg	    default:
2020692f60a7Smrg		break;
2021692f60a7Smrg	    }
2022692f60a7Smrg
2023692f60a7Smrg	    xf86DrvMsg(scrnIndex, X_INFO, "Removing mode (%dx%d) that won't "
2024692f60a7Smrg		       "display properly on LCD\n",
2025692f60a7Smrg		       mode->HDisplay,
2026692f60a7Smrg		       mode->VDisplay);
2027692f60a7Smrg	    return(MODE_BAD);
2028692f60a7Smrg	}
2029692f60a7Smrg    }
2030692f60a7Smrg    return(MODE_OK);
2031692f60a7Smrg}
2032692f60a7Smrg
2033692f60a7Smrgstatic void
2034692f60a7SmrgneoLock(ScrnInfoPtr pScrn)
2035692f60a7Smrg{
2036692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2037692f60a7Smrg
2038692f60a7Smrg    VGAwGR(0x09,0x00);
2039692f60a7Smrg    vgaHWLock(hwp);
2040692f60a7Smrg}
2041692f60a7Smrg
2042692f60a7Smrgstatic void
2043692f60a7SmrgneoUnlock(ScrnInfoPtr pScrn)
2044692f60a7Smrg{
2045692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2046692f60a7Smrg
2047692f60a7Smrg    vgaHWUnlock(hwp);
2048692f60a7Smrg    VGAwGR(0x09,0x26);
2049692f60a7Smrg}
2050692f60a7Smrg
2051692f60a7Smrgstatic Bool
2052692f60a7SmrgneoMapMem(ScrnInfoPtr pScrn)
2053692f60a7Smrg{
2054692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
2055692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2056692f60a7Smrg
2057692f60a7Smrg    if (!nPtr->noLinear) {
2058692f60a7Smrg	if (!nPtr->noMMIO) {
2059692f60a7Smrg	    if (nPtr->pEnt->location.type == BUS_PCI){
2060692f60a7Smrg		nPtr->NeoMMIOBase =
2061692f60a7Smrg		    xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
2062692f60a7Smrg				  nPtr->PciTag, nPtr->NeoMMIOAddr,
2063692f60a7Smrg				  0x200000L);
2064692f60a7Smrg		if (nPtr->NeoMMIOAddr2 != 0){
2065692f60a7Smrg		    nPtr->NeoMMIOBase2 =
2066692f60a7Smrg		        xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
2067692f60a7Smrg				      nPtr->PciTag, nPtr->NeoMMIOAddr2,
2068692f60a7Smrg				      0x100000L);
2069692f60a7Smrg		}
2070692f60a7Smrg	    } else
2071692f60a7Smrg		nPtr->NeoMMIOBase =
2072692f60a7Smrg		    xf86MapVidMem(pScrn->scrnIndex,
2073692f60a7Smrg				  VIDMEM_MMIO, nPtr->NeoMMIOAddr,
2074692f60a7Smrg				  0x200000L);
2075692f60a7Smrg	    if (nPtr->NeoMMIOBase == NULL)
2076692f60a7Smrg	        return FALSE;
2077692f60a7Smrg	}
2078692f60a7Smrg
2079692f60a7Smrg	if (nPtr->pEnt->location.type == BUS_PCI)
2080692f60a7Smrg	    nPtr->NeoFbBase =
2081692f60a7Smrg		xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2082692f60a7Smrg			      nPtr->PciTag,
2083692f60a7Smrg			      (unsigned long)nPtr->NeoLinearAddr,
2084692f60a7Smrg			      nPtr->NeoFbMapSize);
2085692f60a7Smrg	else
2086692f60a7Smrg	    nPtr->NeoFbBase =
2087692f60a7Smrg		xf86MapVidMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2088692f60a7Smrg			      (unsigned long)nPtr->NeoLinearAddr,
2089692f60a7Smrg			      nPtr->NeoFbMapSize);
2090692f60a7Smrg	if (nPtr->NeoFbBase == NULL)
2091692f60a7Smrg	    return FALSE;
2092692f60a7Smrg    } else {
2093692f60a7Smrg	/* In paged mode Base is the VGA window at 0xA0000 */
2094692f60a7Smrg	nPtr->NeoFbBase = hwp->Base;
2095692f60a7Smrg    }
2096692f60a7Smrg    return TRUE;
2097692f60a7Smrg}
2098692f60a7Smrg
2099692f60a7Smrg/*
2100692f60a7Smrg * Unmap the framebuffer and MMIO memory.
2101692f60a7Smrg */
2102692f60a7Smrg
2103692f60a7Smrgstatic Bool
2104692f60a7SmrgneoUnmapMem(ScrnInfoPtr pScrn)
2105692f60a7Smrg{
2106692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
2107692f60a7Smrg
2108692f60a7Smrg    if (!nPtr->noLinear) {
2109692f60a7Smrg      if (nPtr->NeoMMIOBase)
2110692f60a7Smrg	  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase,
2111692f60a7Smrg			  0x200000L);
2112692f60a7Smrg      nPtr->NeoMMIOBase = NULL;
2113692f60a7Smrg      if (nPtr->NeoMMIOBase2)
2114692f60a7Smrg	  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase2,
2115692f60a7Smrg			  0x100000L);
2116692f60a7Smrg      nPtr->NeoMMIOBase2 = NULL;
2117692f60a7Smrg      xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoFbBase,
2118692f60a7Smrg		    nPtr->NeoFbMapSize);
2119692f60a7Smrg    }
2120692f60a7Smrg    nPtr->NeoFbBase = NULL;
2121692f60a7Smrg
2122692f60a7Smrg    return TRUE;
2123692f60a7Smrg}
2124692f60a7Smrg
2125692f60a7Smrgstatic void
2126692f60a7SmrgneoSave(ScrnInfoPtr pScrn)
2127692f60a7Smrg{
2128692f60a7Smrg    vgaRegPtr VgaSave = &VGAHWPTR(pScrn)->SavedReg;
2129692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2130692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
2131692f60a7Smrg    NeoRegPtr save;
2132692f60a7Smrg    int i;
2133692f60a7Smrg
2134692f60a7Smrg    save = &nPtr->NeoSavedReg;
2135692f60a7Smrg
2136692f60a7Smrg    VGAwGR(0x09,0x26);
2137692f60a7Smrg    /*
2138692f60a7Smrg     * Whatever code is needed to get back to bank zero goes here.
2139692f60a7Smrg     */
2140692f60a7Smrg    VGAwGR(0x15,0x00);
2141692f60a7Smrg
2142692f60a7Smrg    /* get generic registers */
2143692f60a7Smrg    vgaHWSave(pScrn, VgaSave, VGA_SR_ALL);
2144692f60a7Smrg
2145692f60a7Smrg    /*
2146692f60a7Smrg     * The port I/O code necessary to read in the extended registers
2147692f60a7Smrg     * into the fields of the vgaNeoRec structure goes here.
2148692f60a7Smrg     */
2149692f60a7Smrg
2150692f60a7Smrg    save->GeneralLockReg = VGArGR(0x0A);
2151692f60a7Smrg
2152692f60a7Smrg    save->ExtCRTDispAddr = VGArGR(0x0E);
2153692f60a7Smrg    if (nPtr->NeoChipset != NM2070) {
2154692f60a7Smrg	save->ExtCRTOffset = VGArGR(0x0F);
2155692f60a7Smrg    }
2156692f60a7Smrg    save->SysIfaceCntl1 = VGArGR(0x10);
2157692f60a7Smrg    save->SysIfaceCntl2 = VGArGR(0x11);
2158692f60a7Smrg    save->SingleAddrPage = VGArGR(0x15);
2159692f60a7Smrg    save->DualAddrPage = VGArGR(0x16);
2160692f60a7Smrg    save->PanelDispCntlReg1 = VGArGR(0x20);
2161692f60a7Smrg    save->PanelDispCntlReg2 = VGArGR(0x25);
2162692f60a7Smrg    save->PanelDispCntlReg3 = VGArGR(0x30);
2163692f60a7Smrg    save->PanelVertCenterReg1 = VGArGR(0x28);
2164692f60a7Smrg    save->PanelVertCenterReg2 = VGArGR(0x29);
2165692f60a7Smrg    save->PanelVertCenterReg3 = VGArGR(0x2A);
2166692f60a7Smrg    if (nPtr->NeoChipset != NM2070) {
2167692f60a7Smrg        save->PanelVertCenterReg4 = VGArGR(0x32);
2168692f60a7Smrg	save->PanelHorizCenterReg1 = VGArGR(0x33);
2169692f60a7Smrg	save->PanelHorizCenterReg2 = VGArGR(0x34);
2170692f60a7Smrg	save->PanelHorizCenterReg3 = VGArGR(0x35);
2171692f60a7Smrg    }
2172692f60a7Smrg    if (nPtr->NeoChipset == NM2160) {
2173692f60a7Smrg        save->PanelHorizCenterReg4 = VGArGR(0x36);
2174692f60a7Smrg    }
2175692f60a7Smrg    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2176692f60a7Smrg	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2177692f60a7Smrg	save->PanelHorizCenterReg4 = VGArGR(0x36);
2178692f60a7Smrg	save->PanelVertCenterReg5  = VGArGR(0x37);
2179692f60a7Smrg	save->PanelHorizCenterReg5 = VGArGR(0x38);
2180692f60a7Smrg    }
2181692f60a7Smrg    save->ExtColorModeSelect = VGArGR(0x90);
2182692f60a7Smrg    save->VCLK3NumeratorLow = VGArGR(0x9B);
2183692f60a7Smrg    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2184692f60a7Smrg	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380)
2185692f60a7Smrg	save->VCLK3NumeratorHigh = VGArGR(0x8F);
2186692f60a7Smrg    save->VCLK3Denominator = VGArGR(0x9F);
2187692f60a7Smrg    save->ProgramVCLK = TRUE;
2188692f60a7Smrg
2189692f60a7Smrg    if (save->reg == NULL)
2190692f60a7Smrg        save->reg = (regSavePtr)xnfcalloc(sizeof(regSaveRec), 1);
2191692f60a7Smrg    else
2192692f60a7Smrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2193692f60a7Smrg		   "Non-NULL reg in NeoSave: reg=%p\n", (void *)save->reg);
2194692f60a7Smrg
2195692f60a7Smrg    save->reg->CR[0x23] = VGArCR(0x23);
2196692f60a7Smrg    save->reg->CR[0x25] = VGArCR(0x25);
2197692f60a7Smrg    save->reg->CR[0x2F] = VGArCR(0x2F);
2198692f60a7Smrg    for (i = 0x40; i <= 0x59; i++) {
2199692f60a7Smrg	save->reg->CR[i] = VGArCR(i);
2200692f60a7Smrg    }
2201692f60a7Smrg    for (i = 0x60; i <= 0x69; i++) {
2202692f60a7Smrg	save->reg->CR[i] = VGArCR(i);
2203692f60a7Smrg    }
2204692f60a7Smrg    for (i = 0x70; i <= NEO_EXT_CR_MAX; i++) {
2205692f60a7Smrg	save->reg->CR[i] = VGArCR(i);
2206692f60a7Smrg    }
2207692f60a7Smrg
2208692f60a7Smrg    for (i = 0x0A; i <= NEO_EXT_GR_MAX; i++) {
2209692f60a7Smrg        save->reg->GR[i] = VGArGR(i);
2210692f60a7Smrg    }
2211692f60a7Smrg}
2212692f60a7Smrg
2213692f60a7Smrg/*
2214692f60a7Smrg * neoProgramShadowRegs
2215692f60a7Smrg *
2216692f60a7Smrg * Setup the shadow registers to their default values.  The NeoSave
2217692f60a7Smrg * routines will restore the proper values on server exit.
2218692f60a7Smrg */
2219692f60a7Smrgstatic void
2220692f60a7SmrgneoProgramShadowRegs(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, NeoRegPtr restore)
2221692f60a7Smrg{
2222692f60a7Smrg    int i;
2223692f60a7Smrg    Bool noProgramShadowRegs;
2224692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2225692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
2226692f60a7Smrg    Bool prog_lcd;
2227692f60a7Smrg
2228692f60a7Smrg    /*
2229692f60a7Smrg     * If display is external only and we want internal
2230692f60a7Smrg     * we need to program the shadow registers.
2231692f60a7Smrg     */
2232692f60a7Smrg    prog_lcd = (((VGArGR(0x20) & 0x3) == 0x1) && nPtr->internDisp);
2233692f60a7Smrg
2234692f60a7Smrg
2235692f60a7Smrg    /*
2236692f60a7Smrg     * Convoluted logic for shadow register programming.
2237692f60a7Smrg     *
2238692f60a7Smrg     * As far as we know, shadow programming is needed for the 2070,
2239692f60a7Smrg     * but not in stretched modes.  Special case this code.
2240692f60a7Smrg     */
2241692f60a7Smrg    switch (nPtr->NeoChipset) {
2242692f60a7Smrg    case NM2070:
2243692f60a7Smrg	/* Program the shadow regs by default */
2244692f60a7Smrg	noProgramShadowRegs = FALSE;
2245692f60a7Smrg	if (!nPtr->progLcdRegs && !prog_lcd)
2246692f60a7Smrg	    noProgramShadowRegs = TRUE;
2247692f60a7Smrg
2248692f60a7Smrg	if (restore->PanelDispCntlReg2 & 0x84) {
2249692f60a7Smrg	    /* Don't program by default if in stretch mode */
2250692f60a7Smrg	    noProgramShadowRegs = TRUE;
2251692f60a7Smrg	    if (nPtr->progLcdStretch)
2252692f60a7Smrg		noProgramShadowRegs = FALSE;
2253692f60a7Smrg	}
2254692f60a7Smrg	break;
2255692f60a7Smrg    case NM2090:
2256692f60a7Smrg    case NM2093:
2257692f60a7Smrg    case NM2097:
2258692f60a7Smrg    case NM2160:
2259692f60a7Smrg    case NM2200:
2260692f60a7Smrg    case NM2230:
2261692f60a7Smrg    case NM2360:
2262692f60a7Smrg    case NM2380:
2263692f60a7Smrg    default:
2264692f60a7Smrg	/* Don't program the shadow regs by default */
2265692f60a7Smrg	noProgramShadowRegs = TRUE;
2266692f60a7Smrg	if (nPtr->progLcdRegs || prog_lcd)
2267692f60a7Smrg	    noProgramShadowRegs = FALSE;
2268692f60a7Smrg
2269692f60a7Smrg	if (restore->PanelDispCntlReg2 & 0x84) {
2270692f60a7Smrg	    /* Only change the behavior if an option is set */
2271692f60a7Smrg	    if (nPtr->progLcdStretchOpt)
2272692f60a7Smrg		noProgramShadowRegs = !nPtr->progLcdStretch;
2273692f60a7Smrg	}
2274692f60a7Smrg	break;
2275692f60a7Smrg    }
2276692f60a7Smrg
2277692f60a7Smrg    if (noProgramShadowRegs) {
2278692f60a7Smrg	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,5,"Not programming shadow registers\n");
2279692f60a7Smrg	if (nPtr->NeoSavedReg.reg){
2280692f60a7Smrg	    for (i = 0x40; i <= 0x59; i++) {
2281692f60a7Smrg		VGAwCR(i, nPtr->NeoSavedReg.reg->CR[i]);
2282692f60a7Smrg	    }
2283692f60a7Smrg	    for (i = 0x60; i <= 0x64; i++) {
2284692f60a7Smrg		VGAwCR(i, nPtr->NeoSavedReg.reg->CR[i]);
2285692f60a7Smrg	    }
2286692f60a7Smrg	}
2287692f60a7Smrg    } else {
2288692f60a7Smrg	/*
2289692f60a7Smrg	 * Program the shadow regs based on the panel width.  This works
2290692f60a7Smrg	 * fine for normal sized panels, but what about the odd ones like
2291692f60a7Smrg	 * the Libretto 100 which has an 800x480 panel???
2292692f60a7Smrg	 */
2293692f60a7Smrg	switch (nPtr->NeoPanelWidth) {
2294692f60a7Smrg	case 640 :
2295692f60a7Smrg	    VGAwCR(0x40,0x5F);
2296692f60a7Smrg	    VGAwCR(0x41,0x50);
2297692f60a7Smrg	    VGAwCR(0x42,0x02);
2298692f60a7Smrg	    VGAwCR(0x43,0x55);
2299692f60a7Smrg	    VGAwCR(0x44,0x81);
2300692f60a7Smrg	    VGAwCR(0x45,0x0B);
2301692f60a7Smrg	    VGAwCR(0x46,0x2E);
2302692f60a7Smrg	    VGAwCR(0x47,0xEA);
2303692f60a7Smrg	    VGAwCR(0x48,0x0C);
2304692f60a7Smrg	    VGAwCR(0x49,0xE7);
2305692f60a7Smrg	    VGAwCR(0x4A,0x04);
2306692f60a7Smrg	    VGAwCR(0x4B,0x2D);
2307692f60a7Smrg	    VGAwCR(0x4C,0x28);
2308692f60a7Smrg	    VGAwCR(0x4D,0x90);
2309692f60a7Smrg	    VGAwCR(0x4E,0x2B);
2310692f60a7Smrg	    VGAwCR(0x4F,0xA0);
2311692f60a7Smrg	    break;
2312692f60a7Smrg	case 800 :
2313692f60a7Smrg	    switch (nPtr->NeoPanelHeight) {
2314692f60a7Smrg	    case 600:
2315692f60a7Smrg		VGAwCR(0x40,0x7F);
2316692f60a7Smrg		VGAwCR(0x41,0x63);
2317692f60a7Smrg		VGAwCR(0x42,0x02);
2318692f60a7Smrg		VGAwCR(0x43,0x6C);
2319692f60a7Smrg		VGAwCR(0x44,0x1C);
2320692f60a7Smrg		VGAwCR(0x45,0x72);
2321692f60a7Smrg		VGAwCR(0x46,0xE0);
2322692f60a7Smrg		VGAwCR(0x47,0x58);
2323692f60a7Smrg		VGAwCR(0x48,0x0C);
2324692f60a7Smrg		VGAwCR(0x49,0x57);
2325692f60a7Smrg		VGAwCR(0x4A,0x73);
2326692f60a7Smrg		VGAwCR(0x4B,0x3D);
2327692f60a7Smrg		VGAwCR(0x4C,0x31);
2328692f60a7Smrg		VGAwCR(0x4D,0x01);
2329692f60a7Smrg		VGAwCR(0x4E,0x36);
2330692f60a7Smrg		VGAwCR(0x4F,0x1E);
2331692f60a7Smrg		if (nPtr->NeoChipset != NM2070) {
2332692f60a7Smrg		    VGAwCR(0x50,0x6B);
2333692f60a7Smrg		    VGAwCR(0x51,0x4F);
2334692f60a7Smrg		    VGAwCR(0x52,0x0E);
2335692f60a7Smrg		    VGAwCR(0x53,0x58);
2336692f60a7Smrg		    VGAwCR(0x54,0x88);
2337692f60a7Smrg		    VGAwCR(0x55,0x33);
2338692f60a7Smrg		    VGAwCR(0x56,0x27);
2339692f60a7Smrg		    VGAwCR(0x57,0x16);
2340692f60a7Smrg		    VGAwCR(0x58,0x2C);
2341692f60a7Smrg		    VGAwCR(0x59,0x94);
2342692f60a7Smrg		}
2343692f60a7Smrg		break;
2344692f60a7Smrg	    case 480:
2345692f60a7Smrg		VGAwCR(0x40,0x7F);
2346692f60a7Smrg		VGAwCR(0x41,0x63);
2347692f60a7Smrg		VGAwCR(0x42,0x02);
2348692f60a7Smrg		VGAwCR(0x43,0x6B);
2349692f60a7Smrg		VGAwCR(0x44,0x1B);
2350692f60a7Smrg		VGAwCR(0x45,0x72);
2351692f60a7Smrg		VGAwCR(0x46,0xE0);
2352692f60a7Smrg		VGAwCR(0x47,0x1C);
2353692f60a7Smrg		VGAwCR(0x48,0x00);
2354692f60a7Smrg		VGAwCR(0x49,0x57);
2355692f60a7Smrg		VGAwCR(0x4A,0x73);
2356692f60a7Smrg		VGAwCR(0x4B,0x3E);
2357692f60a7Smrg		VGAwCR(0x4C,0x31);
2358692f60a7Smrg		VGAwCR(0x4D,0x01);
2359692f60a7Smrg		VGAwCR(0x4E,0x36);
2360692f60a7Smrg		VGAwCR(0x4F,0x1E);
2361692f60a7Smrg		VGAwCR(0x50,0x6B);
2362692f60a7Smrg		VGAwCR(0x51,0x4F);
2363692f60a7Smrg		VGAwCR(0x52,0x0E);
2364692f60a7Smrg		VGAwCR(0x53,0x57);
2365692f60a7Smrg		VGAwCR(0x54,0x87);
2366692f60a7Smrg		VGAwCR(0x55,0x33);
2367692f60a7Smrg		VGAwCR(0x56,0x27);
2368692f60a7Smrg		VGAwCR(0x57,0x16);
2369692f60a7Smrg		VGAwCR(0x58,0x2C);
2370692f60a7Smrg		VGAwCR(0x59,0x94);
2371692f60a7Smrg		break;
2372692f60a7Smrg		break;
2373692f60a7Smrg		/* Not done */
2374692f60a7Smrg	    }
2375692f60a7Smrg	    break;
2376692f60a7Smrg	case 1024 :
2377692f60a7Smrg	    switch (nPtr->NeoPanelHeight) {
2378692f60a7Smrg	    case 768:
2379692f60a7Smrg		VGAwCR(0x40,0xA3);
2380692f60a7Smrg		VGAwCR(0x41,0x7F);
2381692f60a7Smrg		VGAwCR(0x42,0x06);
2382692f60a7Smrg		VGAwCR(0x43,0x85);
2383692f60a7Smrg		VGAwCR(0x44,0x96);
2384692f60a7Smrg		VGAwCR(0x45,0x24);
2385692f60a7Smrg		VGAwCR(0x46,0xE5);
2386692f60a7Smrg		VGAwCR(0x47,0x02);
2387692f60a7Smrg		VGAwCR(0x48,0x08);
2388692f60a7Smrg		VGAwCR(0x49,0xFF);
2389692f60a7Smrg		VGAwCR(0x4A,0x25);
2390692f60a7Smrg		VGAwCR(0x4B,0x4F);
2391692f60a7Smrg		VGAwCR(0x4C,0x40);
2392692f60a7Smrg		VGAwCR(0x4D,0x00);
2393692f60a7Smrg		VGAwCR(0x4E,0x44);
2394692f60a7Smrg		VGAwCR(0x4F,0x0C);
2395692f60a7Smrg		VGAwCR(0x50,0x7A);
2396692f60a7Smrg		VGAwCR(0x51,0x56);
2397692f60a7Smrg		VGAwCR(0x52,0x00);
2398692f60a7Smrg		VGAwCR(0x53,0x5D);
2399692f60a7Smrg		VGAwCR(0x54,0x0E);
2400692f60a7Smrg		VGAwCR(0x55,0x3B);
2401692f60a7Smrg		VGAwCR(0x56,0x2B);
2402692f60a7Smrg		VGAwCR(0x57,0x00);
2403692f60a7Smrg		VGAwCR(0x58,0x2F);
2404692f60a7Smrg		VGAwCR(0x59,0x18);
2405692f60a7Smrg		VGAwCR(0x60,0x88);
2406692f60a7Smrg		VGAwCR(0x61,0x63);
2407692f60a7Smrg		VGAwCR(0x62,0x0B);
2408692f60a7Smrg		VGAwCR(0x63,0x69);
2409692f60a7Smrg		VGAwCR(0x64,0x1A);
2410692f60a7Smrg		break;
2411692f60a7Smrg	    case 480:
2412692f60a7Smrg		VGAwCR(0x40,0xA3);
2413692f60a7Smrg		VGAwCR(0x41,0x7F);
2414692f60a7Smrg		VGAwCR(0x42,0x1B);
2415692f60a7Smrg		VGAwCR(0x43,0x89);
2416692f60a7Smrg		VGAwCR(0x44,0x16);
2417692f60a7Smrg		VGAwCR(0x45,0x0B);
2418692f60a7Smrg		VGAwCR(0x46,0x2C);
2419692f60a7Smrg		VGAwCR(0x47,0xE8);
2420692f60a7Smrg		VGAwCR(0x48,0x0C);
2421692f60a7Smrg		VGAwCR(0x49,0xE7);
2422692f60a7Smrg		VGAwCR(0x4A,0x09);
2423692f60a7Smrg		VGAwCR(0x4B,0x4F);
2424692f60a7Smrg		VGAwCR(0x4C,0x40);
2425692f60a7Smrg		VGAwCR(0x4D,0x00);
2426692f60a7Smrg		VGAwCR(0x4E,0x44);
2427692f60a7Smrg		VGAwCR(0x4F,0x0C);
2428692f60a7Smrg		VGAwCR(0x50,0x7A);
2429692f60a7Smrg		VGAwCR(0x51,0x56);
2430692f60a7Smrg		VGAwCR(0x52,0x00);
2431692f60a7Smrg		VGAwCR(0x53,0x5D);
2432692f60a7Smrg		VGAwCR(0x54,0x0E);
2433692f60a7Smrg		VGAwCR(0x55,0x3B);
2434692f60a7Smrg		VGAwCR(0x56,0x2A);
2435692f60a7Smrg		VGAwCR(0x57,0x00);
2436692f60a7Smrg		VGAwCR(0x58,0x2F);
2437692f60a7Smrg		VGAwCR(0x59,0x18);
2438692f60a7Smrg		VGAwCR(0x60,0x88);
2439692f60a7Smrg		VGAwCR(0x61,0x63);
2440692f60a7Smrg		VGAwCR(0x62,0x0B);
2441692f60a7Smrg		VGAwCR(0x63,0x69);
2442692f60a7Smrg		VGAwCR(0x64,0x1A);
2443692f60a7Smrg		break;
2444692f60a7Smrg	    }
2445692f60a7Smrg	    break;
2446692f60a7Smrg	case 1280:
2447692f60a7Smrg#ifdef NOT_DONE
2448692f60a7Smrg	    VGAwCR(0x40,0x?? );
2449692f60a7Smrg            .
2450692f60a7Smrg		.
2451692f60a7Smrg		.
2452692f60a7Smrg		VGAwCR(0x64,0x?? );
2453692f60a7Smrg		break;
2454692f60a7Smrg#else
2455692f60a7Smrg		/* Probe should prevent this case for now */
2456692f60a7Smrg		FatalError("1280 panel support incomplete\n");
2457692f60a7Smrg#endif
2458692f60a7Smrg	}
2459692f60a7Smrg    }
2460692f60a7Smrg}
2461692f60a7Smrg
2462692f60a7Smrgstatic void
2463692f60a7SmrgneoRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, NeoRegPtr restore,
2464692f60a7Smrg	     Bool restoreText)
2465692f60a7Smrg{
2466692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
2467692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2468692f60a7Smrg    unsigned char temp;
2469692f60a7Smrg    int i;
2470692f60a7Smrg    Bool clock_hi = FALSE;
2471692f60a7Smrg
2472692f60a7Smrg    vgaHWProtect(pScrn,TRUE);		/* Blank the screen */
2473692f60a7Smrg
2474692f60a7Smrg    VGAwGR(0x09,0x26);
2475692f60a7Smrg
2476692f60a7Smrg    /* Init the shadow registers if necessary */
2477692f60a7Smrg    neoProgramShadowRegs(pScrn, VgaReg, restore);
2478692f60a7Smrg
2479692f60a7Smrg    VGAwGR(0x15,0x00);
2480692f60a7Smrg
2481692f60a7Smrg    VGAwGR(0x0A,restore->GeneralLockReg);
2482692f60a7Smrg
2483692f60a7Smrg    /*
2484692f60a7Smrg     * The color mode needs to be set before calling vgaHWRestore
2485692f60a7Smrg     * to ensure the DAC is initialized properly.
2486692f60a7Smrg     *
2487692f60a7Smrg     * NOTE: Make sure we don't change bits make sure we don't change
2488692f60a7Smrg     * any reserved bits.
2489692f60a7Smrg     */
2490692f60a7Smrg    temp = VGArGR(0x90);
2491692f60a7Smrg
2492692f60a7Smrg    switch (nPtr->NeoChipset) {
2493692f60a7Smrg    case NM2070 :
2494692f60a7Smrg	temp &= 0xF0; /* Save bits 7:4 */
2495692f60a7Smrg	temp |= (restore->ExtColorModeSelect & ~0xF0);
2496692f60a7Smrg	break;
2497692f60a7Smrg    case NM2090 :
2498692f60a7Smrg    case NM2093 :
2499692f60a7Smrg    case NM2097 :
2500692f60a7Smrg    case NM2160 :
2501692f60a7Smrg    case NM2200 :
2502692f60a7Smrg    case NM2230 :
2503692f60a7Smrg    case NM2360 :
2504692f60a7Smrg    case NM2380 :
2505692f60a7Smrg	temp &= 0x70; /* Save bits 6:4 */
2506692f60a7Smrg	temp |= (restore->ExtColorModeSelect & ~0x70);
2507692f60a7Smrg	break;
2508692f60a7Smrg    }
2509692f60a7Smrg    VGAwGR(0x90,temp);
2510692f60a7Smrg
2511692f60a7Smrg    /*
2512692f60a7Smrg     * In some rare cases a lockup might occur if we don't delay
2513692f60a7Smrg     * here. (Reported by Miles Lane)
2514692f60a7Smrg     */
2515692f60a7Smrg    xf86UDelay(200000);
2516692f60a7Smrg    /*
2517692f60a7Smrg     * Disable horizontal and vertical graphics and text expansions so
2518692f60a7Smrg     * that vgaHWRestore works properly.
2519692f60a7Smrg     */
2520692f60a7Smrg    temp = VGArGR(0x25);
2521692f60a7Smrg    temp &= 0x39;
2522692f60a7Smrg    VGAwGR(0x25, temp);
2523692f60a7Smrg
2524692f60a7Smrg    /*
2525692f60a7Smrg     * Sleep for 200ms to make sure that the two operations above have
2526692f60a7Smrg     * had time to take effect.
2527692f60a7Smrg     */
2528692f60a7Smrg    xf86UDelay(200000);
2529692f60a7Smrg    /*
2530692f60a7Smrg     * This function handles restoring the generic VGA registers.  */
2531692f60a7Smrg    vgaHWRestore(pScrn, VgaReg,
2532692f60a7Smrg		 VGA_SR_MODE
2533692f60a7Smrg		 | (restoreText ? (VGA_SR_FONTS | VGA_SR_CMAP) : 0));
2534692f60a7Smrg
2535692f60a7Smrg    VGAwGR(0x0E, restore->ExtCRTDispAddr);
2536692f60a7Smrg    VGAwGR(0x0F, restore->ExtCRTOffset);
2537692f60a7Smrg    temp = VGArGR(0x10);
2538692f60a7Smrg    temp &= 0x0F; /* Save bits 3:0 */
2539692f60a7Smrg    temp |= (restore->SysIfaceCntl1 & ~0x0F);
2540692f60a7Smrg    VGAwGR(0x10, temp);
2541692f60a7Smrg
2542692f60a7Smrg    VGAwGR(0x11, restore->SysIfaceCntl2);
2543692f60a7Smrg    VGAwGR(0x15, restore->SingleAddrPage);
2544692f60a7Smrg    VGAwGR(0x16, restore->DualAddrPage);
2545692f60a7Smrg
2546692f60a7Smrg    temp = VGArGR(0x20);
2547692f60a7Smrg    switch (nPtr->NeoChipset) {
2548692f60a7Smrg    case NM2070 :
2549692f60a7Smrg	temp &= 0xFC; /* Save bits 7:2 */
2550692f60a7Smrg	temp |= (restore->PanelDispCntlReg1 & ~0xFC);
2551692f60a7Smrg	break;
2552692f60a7Smrg    case NM2090 :
2553692f60a7Smrg    case NM2093 :
2554692f60a7Smrg    case NM2097 :
2555692f60a7Smrg    case NM2160 :
2556692f60a7Smrg	temp &= 0xDC; /* Save bits 7:6,4:2 */
2557692f60a7Smrg	temp |= (restore->PanelDispCntlReg1 & ~0xDC);
2558692f60a7Smrg	break;
2559692f60a7Smrg    case NM2200 :
2560692f60a7Smrg    case NM2230 :
2561692f60a7Smrg    case NM2360 :
2562692f60a7Smrg    case NM2380 :
2563692f60a7Smrg	temp &= 0x98; /* Save bits 7,4:3 */
2564692f60a7Smrg	temp |= (restore->PanelDispCntlReg1 & ~0x98);
2565692f60a7Smrg	break;
2566692f60a7Smrg    }
2567692f60a7Smrg    VGAwGR(0x20, temp);
2568692f60a7Smrg
2569692f60a7Smrg    temp = VGArGR(0x25);
2570692f60a7Smrg    temp &= 0x38; /* Save bits 5:3 */
2571692f60a7Smrg    temp |= (restore->PanelDispCntlReg2 & ~0x38);
2572692f60a7Smrg    VGAwGR(0x25, temp);
2573692f60a7Smrg
2574692f60a7Smrg    if (nPtr->NeoChipset != NM2070) {
2575692f60a7Smrg	temp = VGArGR(0x30);
2576692f60a7Smrg	temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
2577692f60a7Smrg	temp |= (restore->PanelDispCntlReg3 & ~0xEF);
2578692f60a7Smrg	VGAwGR(0x30, temp);
2579692f60a7Smrg    }
2580692f60a7Smrg
2581692f60a7Smrg    VGAwGR(0x28, restore->PanelVertCenterReg1);
2582692f60a7Smrg    VGAwGR(0x29, restore->PanelVertCenterReg2);
2583692f60a7Smrg    VGAwGR(0x2a, restore->PanelVertCenterReg3);
2584692f60a7Smrg
2585692f60a7Smrg    if (nPtr->NeoChipset != NM2070) {
2586692f60a7Smrg	VGAwGR(0x32, restore->PanelVertCenterReg4);
2587692f60a7Smrg	VGAwGR(0x33, restore->PanelHorizCenterReg1);
2588692f60a7Smrg	VGAwGR(0x34, restore->PanelHorizCenterReg2);
2589692f60a7Smrg	VGAwGR(0x35, restore->PanelHorizCenterReg3);
2590692f60a7Smrg    }
2591692f60a7Smrg
2592692f60a7Smrg    if (nPtr->NeoChipset == NM2160) {
2593692f60a7Smrg	VGAwGR(0x36, restore->PanelHorizCenterReg4);
2594692f60a7Smrg    }
2595692f60a7Smrg
2596692f60a7Smrg    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2597692f60a7Smrg	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2598692f60a7Smrg        VGAwGR(0x36, restore->PanelHorizCenterReg4);
2599692f60a7Smrg        VGAwGR(0x37, restore->PanelVertCenterReg5);
2600692f60a7Smrg        VGAwGR(0x38, restore->PanelHorizCenterReg5);
2601692f60a7Smrg    }
2602692f60a7Smrg    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2603692f60a7Smrg	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380)
2604692f60a7Smrg	clock_hi = TRUE;
2605692f60a7Smrg
2606692f60a7Smrg    /* Program VCLK3 if needed. */
2607692f60a7Smrg    if (restore->ProgramVCLK
2608692f60a7Smrg	 && ((VGArGR(0x9B) != restore->VCLK3NumeratorLow)
2609692f60a7Smrg	    || (VGArGR(0x9F) !=  restore->VCLK3Denominator)
2610692f60a7Smrg	    || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
2611692f60a7Smrg			     != (restore->VCLK3NumeratorHigh & ~0x0F))))) {
2612692f60a7Smrg	VGAwGR(0x9B, restore->VCLK3NumeratorLow);
2613692f60a7Smrg	if (clock_hi) {
2614692f60a7Smrg	    temp = VGArGR(0x8F);
2615692f60a7Smrg	    temp &= 0x0F; /* Save bits 3:0 */
2616692f60a7Smrg	    temp |= (restore->VCLK3NumeratorHigh & ~0x0F);
2617692f60a7Smrg	    VGAwGR(0x8F, temp);
2618692f60a7Smrg	}
2619692f60a7Smrg	VGAwGR(0x9F, restore->VCLK3Denominator);
2620692f60a7Smrg    }
2621692f60a7Smrg    if (restore->biosMode)
2622692f60a7Smrg	VGAwCR(0x23,restore->biosMode);
2623692f60a7Smrg
2624692f60a7Smrg    if (restore->reg) {
2625692f60a7Smrg	VGAwCR(0x23,restore->reg->CR[0x23]);
2626692f60a7Smrg	VGAwCR(0x25,restore->reg->CR[0x25]);
2627692f60a7Smrg	VGAwCR(0x2F,restore->reg->CR[0x2F]);
2628692f60a7Smrg	for (i = 0x40; i <= 0x59; i++) {
2629692f60a7Smrg	    VGAwCR(i, restore->reg->CR[i]);
2630692f60a7Smrg	}
2631692f60a7Smrg	for (i = 0x60; i <= 0x69; i++) {
2632692f60a7Smrg	    VGAwCR(i, restore->reg->CR[i]);
2633692f60a7Smrg	}
2634692f60a7Smrg	for (i = 0x70; i <= NEO_EXT_CR_MAX; i++) {
2635692f60a7Smrg	    VGAwCR(i, restore->reg->CR[i]);
2636692f60a7Smrg	}
2637692f60a7Smrg
2638692f60a7Smrg	for (i = 0x0a; i <= 0x3f; i++) {
2639692f60a7Smrg	    VGAwGR(i, restore->reg->GR[i]);
2640692f60a7Smrg	}
2641692f60a7Smrg	for (i = 0x90; i <= NEO_EXT_GR_MAX; i++) {
2642692f60a7Smrg	    VGAwGR(i, restore->reg->GR[i]);
2643692f60a7Smrg	}
2644692f60a7Smrg    }
2645692f60a7Smrg
2646692f60a7Smrg    VGAwGR (0x93, 0xc0); /* Gives faster framebuffer writes */
2647692f60a7Smrg
2648692f60a7Smrg    /* Program vertical extension register */
2649692f60a7Smrg    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2650692f60a7Smrg	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2651692f60a7Smrg	VGAwCR(0x70, restore->VerticalExt);
2652692f60a7Smrg    }
2653692f60a7Smrg
2654692f60a7Smrg    vgaHWProtect(pScrn, FALSE);		/* Turn on screen */
2655692f60a7Smrg}
2656692f60a7Smrg
2657692f60a7Smrgstatic Bool
2658692f60a7SmrgneoModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
2659692f60a7Smrg{
2660692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
2661692f60a7Smrg    NEOACLPtr nAcl = NEOACLPTR(pScrn);
2662692f60a7Smrg    int hoffset, voffset;
2663692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2664692f60a7Smrg    NeoRegPtr NeoNew = &nPtr->NeoModeReg;
2665692f60a7Smrg    vgaRegPtr NeoStd = &hwp->ModeReg;
2666692f60a7Smrg    Bool noLcdStretch = nPtr->noLcdStretch;
2667692f60a7Smrg    int clockMul = 1;
2668692f60a7Smrg
2669692f60a7Smrg    neoUnlock(pScrn);
2670692f60a7Smrg
2671692f60a7Smrg    /*
2672692f60a7Smrg     * This will allocate the datastructure and initialize all of the
2673692f60a7Smrg     * generic VGA registers.
2674692f60a7Smrg     */
2675692f60a7Smrg
2676692f60a7Smrg    if (!vgaHWInit(pScrn, mode))
2677692f60a7Smrg	return(FALSE);
2678692f60a7Smrg
2679692f60a7Smrg    /*
2680692f60a7Smrg     * Several registers need to be corrected from the default values
2681692f60a7Smrg     * assigned by vgaHWinit().
2682692f60a7Smrg     */
2683692f60a7Smrg    pScrn->vtSema = TRUE;
2684692f60a7Smrg
2685692f60a7Smrg    /*
2686692f60a7Smrg     * The default value assigned by vgaHW.c is 0x41, but this does
2687692f60a7Smrg     * not work for NeoMagic.
2688692f60a7Smrg     */
2689692f60a7Smrg    NeoStd->Attribute[16] = 0x01;
2690692f60a7Smrg
2691692f60a7Smrg    switch (pScrn->depth) { /*@!@*/
2692692f60a7Smrg    case  8 :
2693692f60a7Smrg	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 3;
2694692f60a7Smrg	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 11;
2695692f60a7Smrg	NeoNew->ExtColorModeSelect = 0x11;
2696692f60a7Smrg	break;
2697692f60a7Smrg    case 15 :
2698692f60a7Smrg        NeoNew->ExtColorModeSelect = 0x12;
2699692f60a7Smrg	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 2;
2700692f60a7Smrg	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 10;
2701692f60a7Smrg        break;
2702692f60a7Smrg    case 16 :
2703692f60a7Smrg        NeoNew->ExtColorModeSelect = 0x13;
2704692f60a7Smrg	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 2;
2705692f60a7Smrg	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 10;
2706692f60a7Smrg	break;
2707692f60a7Smrg    case 24 :
2708692f60a7Smrg	NeoStd->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3;
2709692f60a7Smrg	NeoNew->ExtCRTOffset   = (pScrn->displayWidth * 3) >> 11;
2710692f60a7Smrg	NeoNew->ExtColorModeSelect = 0x14;
2711692f60a7Smrg	break;
2712692f60a7Smrg    default :
2713692f60a7Smrg	break;
2714692f60a7Smrg    }
2715692f60a7Smrg
2716692f60a7Smrg    NeoNew->ExtCRTDispAddr = 0x10;
2717692f60a7Smrg
2718692f60a7Smrg    /* Vertical Extension */
2719692f60a7Smrg    NeoNew->VerticalExt = (((mode->CrtcVTotal -2) & 0x400) >> 10 )
2720692f60a7Smrg      | (((mode->CrtcVDisplay -1) & 0x400) >> 9 )
2721692f60a7Smrg        | (((mode->CrtcVSyncStart) & 0x400) >> 8 )
2722692f60a7Smrg          | (((mode->CrtcVBlankStart - 1) & 0x400) >> 7 );
2723692f60a7Smrg
2724692f60a7Smrg    /* Fast write bursts on unless disabled. */
2725692f60a7Smrg    if (nPtr->onPciBurst) {
2726692f60a7Smrg	NeoNew->SysIfaceCntl1 = 0x30;
2727692f60a7Smrg    } else {
2728692f60a7Smrg	NeoNew->SysIfaceCntl1 = 0x00;
2729692f60a7Smrg    }
2730692f60a7Smrg
2731692f60a7Smrg    /* If they are used, enable linear addressing and/or enable MMIO. */
2732692f60a7Smrg    NeoNew->SysIfaceCntl2 = 0x00;
2733692f60a7Smrg    if (!nPtr->noLinear)
2734692f60a7Smrg	NeoNew->SysIfaceCntl2 |= 0x80;
2735692f60a7Smrg    if (!nPtr->noMMIO)
2736692f60a7Smrg	NeoNew->SysIfaceCntl2 |= 0x40;
2737692f60a7Smrg
2738692f60a7Smrg    /* Enable any user specified display devices. */
2739692f60a7Smrg    NeoNew->PanelDispCntlReg1 = 0x00;
2740692f60a7Smrg    if (nPtr->internDisp) {
2741692f60a7Smrg	NeoNew->PanelDispCntlReg1 |= 0x02;
2742692f60a7Smrg    }
2743692f60a7Smrg    if (nPtr->externDisp) {
2744692f60a7Smrg	NeoNew->PanelDispCntlReg1 |= 0x01;
2745692f60a7Smrg    }
2746692f60a7Smrg
2747692f60a7Smrg#if 0
2748692f60a7Smrg    /*
2749692f60a7Smrg     * This was replaced: if no devices are specified take the
2750692f60a7Smrg     * probed settings. If the probed settings are bogus fallback
2751692f60a7Smrg     * to internal only.
2752692f60a7Smrg     */
2753692f60a7Smrg    /* If the user did not specify any display devices, then... */
2754692f60a7Smrg    if (NeoNew->PanelDispCntlReg1 == 0x00) {
2755692f60a7Smrg	/* Default to internal (i.e., LCD) only. */
2756692f60a7Smrg	NeoNew->PanelDispCntlReg1 |= 0x02;
2757692f60a7Smrg    }
2758692f60a7Smrg#endif
2759692f60a7Smrg    /* If we are using a fixed mode, then tell the chip we are. */
2760692f60a7Smrg    switch (mode->HDisplay) {
2761692f60a7Smrg    case 1280:
2762692f60a7Smrg	NeoNew->PanelDispCntlReg1 |= 0x60;
2763692f60a7Smrg        break;
2764692f60a7Smrg    case 1024:
2765692f60a7Smrg	NeoNew->PanelDispCntlReg1 |= 0x40;
2766692f60a7Smrg        break;
2767692f60a7Smrg    case 800:
2768692f60a7Smrg	NeoNew->PanelDispCntlReg1 |= 0x20;
2769692f60a7Smrg        break;
2770692f60a7Smrg    case 640:
2771692f60a7Smrg    default:
2772692f60a7Smrg        break;
2773692f60a7Smrg    }
2774692f60a7Smrg
2775692f60a7Smrg    /* Setup shadow register locking. */
2776692f60a7Smrg    switch (NeoNew->PanelDispCntlReg1 & 0x03) {
2777692f60a7Smrg    case 0x01 : /* External CRT only mode: */
2778692f60a7Smrg	NeoNew->GeneralLockReg = 0x00;
2779692f60a7Smrg	/* We need to program the VCLK for external display only mode. */
2780692f60a7Smrg	NeoNew->ProgramVCLK = TRUE;
2781692f60a7Smrg	break;
2782692f60a7Smrg    case 0x02 : /* Internal LCD only mode: */
2783692f60a7Smrg    case 0x03 : /* Simultaneous internal/external (LCD/CRT) mode: */
2784692f60a7Smrg	NeoNew->GeneralLockReg = 0x01;
2785692f60a7Smrg	/* Don't program the VCLK when using the LCD. */
2786692f60a7Smrg	NeoNew->ProgramVCLK = FALSE;
2787692f60a7Smrg	break;
2788692f60a7Smrg    }
2789692f60a7Smrg
2790692f60a7Smrg    /*
2791692f60a7Smrg     * If the screen is to be stretched, turn on stretching for the
2792692f60a7Smrg     * various modes.
2793692f60a7Smrg     *
2794692f60a7Smrg     * OPTION_LCD_STRETCH means stretching should be turned off!
2795692f60a7Smrg     */
2796692f60a7Smrg    NeoNew->PanelDispCntlReg2 = 0x00;
2797692f60a7Smrg    NeoNew->PanelDispCntlReg3 = 0x00;
2798692f60a7Smrg    nAcl->NoCursorMode = FALSE;
2799692f60a7Smrg
2800692f60a7Smrg    if ((!noLcdStretch) &&
2801692f60a7Smrg	(NeoNew->PanelDispCntlReg1 & 0x02)) {
2802692f60a7Smrg	if (mode->HDisplay == nPtr->NeoPanelWidth) {
2803692f60a7Smrg	    /*
2804692f60a7Smrg	     * Don't disable the flag.  It will be needed if another mode
2805692f60a7Smrg	     * is selected.
2806692f60a7Smrg	     */
2807692f60a7Smrg	    /*
2808692f60a7Smrg	     * No stretching required when the requested display width
2809692f60a7Smrg	     * equals the panel width.
2810692f60a7Smrg	     */
2811692f60a7Smrg	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Stretching disabled\n");
2812692f60a7Smrg	        noLcdStretch = TRUE;
2813692f60a7Smrg	} else {
2814692f60a7Smrg
2815692f60a7Smrg	    switch (mode->HDisplay) {
2816692f60a7Smrg	    case  320 : /* Needs testing.  KEM -- 24 May 98 */
2817692f60a7Smrg	    case  400 : /* Needs testing.  KEM -- 24 May 98 */
2818692f60a7Smrg	    case  640 :
2819692f60a7Smrg	    case  800 :
2820692f60a7Smrg	    case 1024 :
2821692f60a7Smrg		NeoNew->PanelDispCntlReg2 |= 0xC6;
2822692f60a7Smrg		nAcl->NoCursorMode = TRUE;
2823692f60a7Smrg		break;
2824692f60a7Smrg	    default   :
2825692f60a7Smrg		/* No stretching in these modes. */
2826692f60a7Smrg		xf86DrvMsg(pScrn->scrnIndex,X_INFO,
2827692f60a7Smrg			   "Stretching disabled not supported in this mode\n");
2828692f60a7Smrg		noLcdStretch = TRUE;
2829692f60a7Smrg		break;
2830692f60a7Smrg	    }
2831692f60a7Smrg	}
2832692f60a7Smrg    } else if (mode->Flags & V_DBLSCAN) {
2833692f60a7Smrg	nAcl->NoCursorMode = TRUE;
2834692f60a7Smrg    }
2835692f60a7Smrg
2836692f60a7Smrg    /*
2837692f60a7Smrg     * If the screen is to be centerd, turn on the centering for the
2838692f60a7Smrg     * various modes.
2839692f60a7Smrg     */
2840692f60a7Smrg    NeoNew->PanelVertCenterReg1  = 0x00;
2841692f60a7Smrg    NeoNew->PanelVertCenterReg2  = 0x00;
2842692f60a7Smrg    NeoNew->PanelVertCenterReg3  = 0x00;
2843692f60a7Smrg    NeoNew->PanelVertCenterReg4  = 0x00;
2844692f60a7Smrg    NeoNew->PanelVertCenterReg5  = 0x00;
2845692f60a7Smrg    NeoNew->PanelHorizCenterReg1 = 0x00;
2846692f60a7Smrg    NeoNew->PanelHorizCenterReg2 = 0x00;
2847692f60a7Smrg    NeoNew->PanelHorizCenterReg3 = 0x00;
2848692f60a7Smrg    NeoNew->PanelHorizCenterReg4 = 0x00;
2849692f60a7Smrg    NeoNew->PanelHorizCenterReg5 = 0x00;
2850692f60a7Smrg
2851692f60a7Smrg    if (nPtr->lcdCenter &&
2852692f60a7Smrg	(NeoNew->PanelDispCntlReg1 & 0x02)) {
2853692f60a7Smrg	Bool doCenter = FALSE;
2854692f60a7Smrg
2855692f60a7Smrg	hoffset = 0;
2856692f60a7Smrg	voffset = 0;
2857692f60a7Smrg	if (mode->HDisplay == nPtr->NeoPanelWidth) {
2858692f60a7Smrg	    /*
2859692f60a7Smrg	     * No centering required when the requested display width
2860692f60a7Smrg	     * equals the panel width.
2861692f60a7Smrg	     */
2862692f60a7Smrg	} else {
2863692f60a7Smrg	    NeoNew->PanelDispCntlReg3 |= 0x10;
2864692f60a7Smrg	    if (noLcdStretch) {
2865692f60a7Smrg		/* Calculate the horizontal offsets. */
2866692f60a7Smrg		int HDisplay = mode->HDisplay
2867692f60a7Smrg		    << ((mode->VDisplay < 480) ? 1 : 0);
2868692f60a7Smrg		hoffset = ((nPtr->NeoPanelWidth - HDisplay) >> 4) - 1;
2869692f60a7Smrg		if (mode->VDisplay < 480)
2870692f60a7Smrg		    hoffset >>= 1;
2871692f60a7Smrg		doCenter = TRUE;
2872692f60a7Smrg	    } else {
2873692f60a7Smrg		/* Stretched modes cannot be centered. */
2874692f60a7Smrg		hoffset = 0;
2875692f60a7Smrg	    }
2876692f60a7Smrg	}
2877692f60a7Smrg	if (mode->VDisplay == nPtr->NeoPanelHeight) {
2878692f60a7Smrg	    /*
2879692f60a7Smrg	     * No centering required when the requested display width
2880692f60a7Smrg	     * equals the panel width.
2881692f60a7Smrg	     */
2882692f60a7Smrg	} else {
2883692f60a7Smrg	    NeoNew->PanelDispCntlReg2 |= 0x01;
2884692f60a7Smrg	    if (noLcdStretch) {
2885692f60a7Smrg		/* Calculate the vertical offsets. */
2886692f60a7Smrg		int VDisplay = mode->VDisplay
2887692f60a7Smrg		    << ((mode->Flags & V_DBLSCAN) ? 1 : 0);
2888692f60a7Smrg		voffset = ((nPtr->NeoPanelHeight - VDisplay) >> 1) - 2;
2889692f60a7Smrg		doCenter = TRUE;
2890692f60a7Smrg	    } else {
2891692f60a7Smrg		/* Stretched modes cannot be centered. */
2892692f60a7Smrg		voffset = 0;
2893692f60a7Smrg	    }
2894692f60a7Smrg	}
2895692f60a7Smrg
2896692f60a7Smrg	if (doCenter) {
2897692f60a7Smrg	    switch (mode->HDisplay) {
2898692f60a7Smrg	    case  320 : /* Needs testing.  KEM -- 24 May 98 */
2899692f60a7Smrg  		NeoNew->PanelHorizCenterReg3 = hoffset;
2900692f60a7Smrg		NeoNew->PanelVertCenterReg3  = voffset;
2901692f60a7Smrg		break;
2902692f60a7Smrg	    case  400 : /* Needs testing.  KEM -- 24 May 98 */
2903692f60a7Smrg		NeoNew->PanelHorizCenterReg4 = hoffset;
2904692f60a7Smrg		NeoNew->PanelVertCenterReg1  = voffset;
2905692f60a7Smrg		break;
2906692f60a7Smrg	    case  640 :
2907692f60a7Smrg		NeoNew->PanelHorizCenterReg1 = hoffset;
2908692f60a7Smrg		NeoNew->PanelVertCenterReg3  = voffset;
2909692f60a7Smrg		break;
2910692f60a7Smrg	    case  800 :
2911692f60a7Smrg		NeoNew->PanelHorizCenterReg2 = hoffset;
2912692f60a7Smrg		switch (mode->VDisplay) {
2913692f60a7Smrg		case 600:
2914692f60a7Smrg		    NeoNew->PanelVertCenterReg4  = voffset;
2915692f60a7Smrg		    break;
2916692f60a7Smrg		case 480:
2917692f60a7Smrg		    /* Not sure if this is correct */
2918692f60a7Smrg		    NeoNew->PanelVertCenterReg3  = voffset;
2919692f60a7Smrg		    break;
2920692f60a7Smrg		}
2921692f60a7Smrg		break;
2922692f60a7Smrg	    case 1024 :
2923692f60a7Smrg		NeoNew->PanelHorizCenterReg5 = hoffset;
2924692f60a7Smrg		NeoNew->PanelVertCenterReg5  = voffset;
2925692f60a7Smrg		break;
2926692f60a7Smrg	    case 1280 :
2927692f60a7Smrg	    default   :
2928692f60a7Smrg		/* No centering in these modes. */
2929692f60a7Smrg		break;
2930692f60a7Smrg	    }
2931692f60a7Smrg	}
2932692f60a7Smrg    }
2933692f60a7Smrg
2934692f60a7Smrg    if (!noLcdStretch &&
2935692f60a7Smrg	(NeoNew->PanelDispCntlReg1 & 0x02))  {
2936692f60a7Smrg	if (mode->HDisplay != nPtr->NeoPanelWidth)
2937692f60a7Smrg	    nPtr->videoHZoom = (double)nPtr->NeoPanelWidth/mode->HDisplay;
2938692f60a7Smrg	if (mode->VDisplay != nPtr->NeoPanelHeight)
2939692f60a7Smrg	    nPtr->videoVZoom = (double)nPtr->NeoPanelHeight/mode->VDisplay;
2940692f60a7Smrg    } else {
2941692f60a7Smrg	nPtr->videoHZoom = 1.0;
2942692f60a7Smrg	nPtr->videoVZoom = 1.0;
2943692f60a7Smrg    }
2944692f60a7Smrg    /* Do double scan */
2945692f60a7Smrg    if (mode->VDisplay < 480) {
2946692f60a7Smrg	NeoStd->Sequencer[1] |= 0x8;
2947692f60a7Smrg	clockMul = 2;
2948692f60a7Smrg    }
2949692f60a7Smrg
2950692f60a7Smrg    NeoNew->biosMode = neoFindMode(mode->HDisplay,mode->VDisplay,pScrn->depth);
2951692f60a7Smrg
2952692f60a7Smrg    /*
2953692f60a7Smrg     * New->reg should be empty.  Just in
2954692f60a7Smrg     * case it isn't, warn us and clear it anyway.
2955692f60a7Smrg     */
2956692f60a7Smrg    if (NeoNew->reg) {
2957692f60a7Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2958692f60a7Smrg		   "Non-NULL reg in NeoInit: reg=%p\n", (void *)NeoNew->reg);
2959692f60a7Smrg	xfree(NeoNew->reg);
2960692f60a7Smrg	NeoNew->reg = NULL;
2961692f60a7Smrg    }
2962692f60a7Smrg
2963692f60a7Smrg    /*
2964692f60a7Smrg     * Calculate the VCLK that most closely matches the requested dot
2965692f60a7Smrg     * clock.
2966692f60a7Smrg     */
2967692f60a7Smrg    neoCalcVCLK(pScrn, mode->SynthClock*clockMul);
2968692f60a7Smrg
2969692f60a7Smrg    /* Since we program the clocks ourselves, always use VCLK3. */
2970692f60a7Smrg    NeoStd->MiscOutReg |= 0x0C;
2971692f60a7Smrg
2972692f60a7Smrg    neoRestore(pScrn, NeoStd, NeoNew, FALSE);
2973692f60a7Smrg
2974692f60a7Smrg    return(TRUE);
2975692f60a7Smrg}
2976692f60a7Smrg
2977692f60a7Smrg/*
2978692f60a7Smrg * neoCalcVCLK --
2979692f60a7Smrg *
2980692f60a7Smrg * Determine the closest clock frequency to the one requested.
2981692f60a7Smrg */
2982692f60a7Smrg#define REF_FREQ 14.31818
2983692f60a7Smrg#define MAX_N 127
2984692f60a7Smrg#define MAX_D 31
2985692f60a7Smrg#define MAX_F 1
2986692f60a7Smrg
2987692f60a7Smrgstatic void
2988692f60a7SmrgneoCalcVCLK(ScrnInfoPtr pScrn, long freq)
2989692f60a7Smrg{
2990692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
2991692f60a7Smrg
2992692f60a7Smrg    int n, d, f;
2993692f60a7Smrg    double f_out;
2994692f60a7Smrg    double f_diff;
2995692f60a7Smrg    int n_best = 0, d_best = 1, f_best = 0;
2996692f60a7Smrg    double f_best_diff = 999999.0;
2997692f60a7Smrg    double f_target = freq/1000.0;
2998692f60a7Smrg
2999692f60a7Smrg    for (f = 0; f <= MAX_F; f++)
3000692f60a7Smrg	for (n = 0; n <= MAX_N; n++)
3001692f60a7Smrg	    for (d = 1; d <= MAX_D; d++) {
3002692f60a7Smrg		f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
3003692f60a7Smrg		f_diff = abs(f_out-f_target);
3004692f60a7Smrg		if (f_diff < f_best_diff) {
3005692f60a7Smrg		    f_best_diff = f_diff;
3006692f60a7Smrg		    n_best = n;
3007692f60a7Smrg		    d_best = d;
3008692f60a7Smrg		    f_best = f;
3009692f60a7Smrg		}
3010692f60a7Smrg	    }
3011692f60a7Smrg
3012692f60a7Smrg    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
3013692f60a7Smrg	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
3014692f60a7Smrg        /* NOT_DONE:  We are trying the full range of the 2200 clock.
3015692f60a7Smrg           We should be able to try n up to 2047 */
3016692f60a7Smrg	nPtr->NeoModeReg.VCLK3NumeratorLow  = n_best;
3017692f60a7Smrg	nPtr->NeoModeReg.VCLK3NumeratorHigh = (f_best << 7);
3018692f60a7Smrg    }
3019692f60a7Smrg    else {
3020692f60a7Smrg	nPtr->NeoModeReg.VCLK3NumeratorLow  = n_best | (f_best << 7);
3021692f60a7Smrg    }
3022692f60a7Smrg    nPtr->NeoModeReg.VCLK3Denominator = d_best;
3023692f60a7Smrg#ifdef DEBUG
3024692f60a7Smrg    ErrorF("neoVCLK: f:%f NumLow=%i NumHi=%i Den=%i Df=%f\n",
3025692f60a7Smrg	   f_target,
3026692f60a7Smrg	   nPtr->NeoModeReg.VCLK3NumeratorLow,
3027692f60a7Smrg	   nPtr->NeoModeReg.VCLK3NumeratorHigh,
3028692f60a7Smrg	   nPtr->NeoModeReg.VCLK3Denominator,
3029692f60a7Smrg	   f_best_diff);
3030692f60a7Smrg#endif
3031692f60a7Smrg}
3032692f60a7Smrg
3033692f60a7Smrg/*
3034692f60a7Smrg * NeoDisplayPowerManagementSet --
3035692f60a7Smrg *
3036692f60a7Smrg * Sets VESA Display Power Management Signaling (DPMS) Mode.
3037692f60a7Smrg */
3038692f60a7Smrgstatic void
3039692f60a7SmrgNeoDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
3040692f60a7Smrg			     int flags)
3041692f60a7Smrg{
3042692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
3043692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
3044692f60a7Smrg    unsigned char SEQ01 = 0;
3045692f60a7Smrg    unsigned char LogicPowerMgmt = 0;
3046692f60a7Smrg    unsigned char LCD_on = 0;
3047692f60a7Smrg
3048692f60a7Smrg    if (!pScrn->vtSema)
3049692f60a7Smrg	return;
3050692f60a7Smrg
3051692f60a7Smrg    switch (PowerManagementMode) {
3052692f60a7Smrg    case DPMSModeOn:
3053692f60a7Smrg	/* Screen: On; HSync: On, VSync: On */
3054692f60a7Smrg	SEQ01 = 0x00;
3055692f60a7Smrg	LogicPowerMgmt = 0x00;
3056692f60a7Smrg	if (nPtr->internDisp || ! nPtr->externDisp)
3057692f60a7Smrg	    LCD_on = 0x02;
3058692f60a7Smrg	else
3059692f60a7Smrg	    LCD_on = 0x00;
3060692f60a7Smrg	break;
3061692f60a7Smrg    case DPMSModeStandby:
3062692f60a7Smrg	/* Screen: Off; HSync: Off, VSync: On */
3063692f60a7Smrg	SEQ01 = 0x20;
3064692f60a7Smrg	LogicPowerMgmt = 0x10;
3065692f60a7Smrg	LCD_on = 0x00;
3066692f60a7Smrg	break;
3067692f60a7Smrg    case DPMSModeSuspend:
3068692f60a7Smrg	/* Screen: Off; HSync: On, VSync: Off */
3069692f60a7Smrg	SEQ01 = 0x20;
3070692f60a7Smrg	LogicPowerMgmt = 0x20;
3071692f60a7Smrg	LCD_on = 0x00;
3072692f60a7Smrg	break;
3073692f60a7Smrg    case DPMSModeOff:
3074692f60a7Smrg	/* Screen: Off; HSync: Off, VSync: Off */
3075692f60a7Smrg	SEQ01 = 0x20;
3076692f60a7Smrg	LogicPowerMgmt = 0x30;
3077692f60a7Smrg	LCD_on = 0x00;
3078692f60a7Smrg	break;
3079692f60a7Smrg    }
3080692f60a7Smrg
3081692f60a7Smrg    /* Turn the screen on/off */
3082692f60a7Smrg    SEQ01 |= VGArSR(0x01) & ~0x20;
3083692f60a7Smrg    VGAwSR(0x01, SEQ01);
3084692f60a7Smrg
3085692f60a7Smrg    /* Turn the LCD on/off */
3086692f60a7Smrg    LCD_on |= VGArGR(0x20) & ~0x02;
3087692f60a7Smrg    VGAwGR(0x20, LCD_on);
3088692f60a7Smrg
3089692f60a7Smrg    /* Set the DPMS mode */
3090692f60a7Smrg    LogicPowerMgmt |= 0x80;
3091692f60a7Smrg    LogicPowerMgmt |= VGArGR(0x01) & ~0xF0;
3092692f60a7Smrg    VGAwGR(0x01,LogicPowerMgmt);
3093692f60a7Smrg}
3094692f60a7Smrg
3095692f60a7Smrgstatic unsigned int
3096692f60a7Smrgneo_ddc1Read(ScrnInfoPtr pScrn)
3097692f60a7Smrg{
3098692f60a7Smrg    register vgaHWPtr hwp = VGAHWPTR(pScrn);
3099692f60a7Smrg    register unsigned int tmp;
3100692f60a7Smrg
3101692f60a7Smrg    /* This needs to be investigated: we may have to swap this around */
3102692f60a7Smrg    while (!(hwp->readST01(hwp)&0x8)) {};
3103692f60a7Smrg    while (hwp->readST01(hwp)&0x8) {};
3104692f60a7Smrg
3105692f60a7Smrg    tmp = (VGArGR(0xA1) & 0x08);
3106692f60a7Smrg
3107692f60a7Smrg    return (tmp);
3108692f60a7Smrg}
3109692f60a7Smrg
3110692f60a7Smrgstatic xf86MonPtr
3111692f60a7Smrgneo_ddc1(int scrnIndex)
3112692f60a7Smrg{
3113692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(xf86Screens[scrnIndex]);
3114692f60a7Smrg    unsigned int reg1, reg2, reg3;
3115692f60a7Smrg    xf86MonPtr ret;
3116692f60a7Smrg
3117692f60a7Smrg    /* initialize chipset */
3118692f60a7Smrg    reg1 = VGArCR(0x21);
3119692f60a7Smrg    reg2 = VGArCR(0x1D);
3120692f60a7Smrg    reg3 = VGArCR(0xA1);
3121692f60a7Smrg    VGAwCR(0x21,0x00);
3122692f60a7Smrg    VGAwCR(0x1D,0x01);  /* some Voodoo */
3123692f60a7Smrg    VGAwGR(0xA1,0x2F);
3124692f60a7Smrg    ret =  xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),neo_ddc1Read);
3125692f60a7Smrg    /* undo initialization */
3126692f60a7Smrg    VGAwCR(0x21,reg1);
3127692f60a7Smrg    VGAwCR(0x1D,reg2);
3128692f60a7Smrg    VGAwGR(0xA1,reg3);
3129692f60a7Smrg    return ret;
3130692f60a7Smrg}
3131692f60a7Smrg
3132692f60a7Smrgstatic Bool
3133692f60a7SmrgneoDoDDC1(ScrnInfoPtr pScrn)
3134692f60a7Smrg{
3135692f60a7Smrg    Bool ret = FALSE;
3136692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
3137692f60a7Smrg
3138692f60a7Smrg    VGAwGR(0x09,0x26);
3139692f60a7Smrg    ret = xf86SetDDCproperties(pScrn,
3140692f60a7Smrg				xf86PrintEDID(neo_ddc1(pScrn->scrnIndex)));
3141692f60a7Smrg    VGAwGR(0x09,0x00);
3142692f60a7Smrg
3143692f60a7Smrg    return ret;
3144692f60a7Smrg}
3145692f60a7Smrg
3146692f60a7Smrgstatic Bool
3147692f60a7SmrgneoDoDDC2(ScrnInfoPtr pScrn)
3148692f60a7Smrg{
3149692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
3150692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
3151692f60a7Smrg    Bool ret = FALSE;
3152692f60a7Smrg
3153692f60a7Smrg    VGAwGR(0x09,0x26);
3154692f60a7Smrg    if (xf86LoadSubModule(pScrn, "i2c")) {
3155692f60a7Smrg        xf86LoaderReqSymLists(i2cSymbols, NULL);
3156692f60a7Smrg	if (neo_I2CInit(pScrn)) {
3157692f60a7Smrg	    ret = xf86SetDDCproperties(pScrn,xf86PrintEDID(xf86DoEDID_DDC2(
3158692f60a7Smrg					      pScrn->scrnIndex,nPtr->I2C)));
3159692f60a7Smrg	}
3160692f60a7Smrg    }
3161692f60a7Smrg    VGAwGR(0x09,0x00);
3162692f60a7Smrg
3163692f60a7Smrg    return ret;
3164692f60a7Smrg}
3165692f60a7Smrg
3166692f60a7Smrgstatic Bool
3167692f60a7SmrgneoDoDDCVBE(ScrnInfoPtr pScrn)
3168692f60a7Smrg{
3169692f60a7Smrg    NEOPtr nPtr = NEOPTR(pScrn);
3170692f60a7Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
3171692f60a7Smrg    vbeInfoPtr pVbe;
3172692f60a7Smrg    Bool ret = FALSE;
3173692f60a7Smrg
3174692f60a7Smrg    VGAwGR(0x09,0x26);
3175692f60a7Smrg    if (xf86LoadSubModule(pScrn, "vbe")) {
3176692f60a7Smrg	xf86LoaderReqSymLists(vbeSymbols, NULL);
3177692f60a7Smrg        if ((pVbe = VBEInit(NULL,nPtr->pEnt->index))) {
3178692f60a7Smrg	  ret = xf86SetDDCproperties(
3179692f60a7Smrg				     pScrn,xf86PrintEDID(vbeDoEDID(pVbe,NULL)));
3180692f60a7Smrg	  vbeFree(pVbe);
3181692f60a7Smrg	}
3182692f60a7Smrg    }
3183692f60a7Smrg    VGAwGR(0x09,0x00);
3184692f60a7Smrg    return ret;
3185692f60a7Smrg}
3186692f60a7Smrg
3187692f60a7Smrgstatic int
3188692f60a7SmrgneoFindMode(int xres, int yres, int depth)
3189692f60a7Smrg{
3190692f60a7Smrg    int xres_s;
3191692f60a7Smrg    int i, size;
3192692f60a7Smrg    biosMode *mode;
3193692f60a7Smrg
3194692f60a7Smrg    switch (depth) {
3195692f60a7Smrg    case 8:
3196692f60a7Smrg	size = sizeof(bios8) / sizeof(biosMode);
3197692f60a7Smrg	mode = bios8;
3198692f60a7Smrg	break;
3199692f60a7Smrg    case 15:
3200692f60a7Smrg	size = sizeof(bios15) / sizeof(biosMode);
3201692f60a7Smrg	mode = bios15;
3202692f60a7Smrg	break;
3203692f60a7Smrg    case 16:
3204692f60a7Smrg	size = sizeof(bios16) / sizeof(biosMode);
3205692f60a7Smrg	mode = bios16;
3206692f60a7Smrg	break;
3207692f60a7Smrg    case 24:
3208692f60a7Smrg	size = sizeof(bios24) / sizeof(biosMode);
3209692f60a7Smrg	mode = bios24;
3210692f60a7Smrg	break;
3211692f60a7Smrg    default:
3212692f60a7Smrg	return 0;
3213692f60a7Smrg    }
3214692f60a7Smrg
3215692f60a7Smrg    for (i = 0; i < size; i++) {
3216692f60a7Smrg	if (xres <= mode[i].x_res) {
3217692f60a7Smrg	    xres_s = mode[i].x_res;
3218692f60a7Smrg	    for (; i < size; i++) {
3219692f60a7Smrg		if (mode[i].x_res != xres_s)
3220692f60a7Smrg		    return mode[i-1].mode;
3221692f60a7Smrg		if (yres <= mode[i].y_res)
3222692f60a7Smrg		    return mode[i].mode;
3223692f60a7Smrg	    }
3224692f60a7Smrg	}
3225692f60a7Smrg    }
3226692f60a7Smrg    return mode[size - 1].mode;
3227692f60a7Smrg
3228692f60a7Smrg}
3229692f60a7Smrg
3230692f60a7Smrgstatic void
3231692f60a7SmrgneoProbeDDC(ScrnInfoPtr pScrn, int index)
3232692f60a7Smrg{
3233692f60a7Smrg    vbeInfoPtr pVbe;
3234692f60a7Smrg
3235692f60a7Smrg    if (xf86LoadSubModule(pScrn, "vbe")) {
3236692f60a7Smrg        if ((pVbe = VBEInit(NULL,index))) {
3237692f60a7Smrg	    ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3238692f60a7Smrg	    vbeFree(pVbe);
3239692f60a7Smrg	}
3240692f60a7Smrg    }
3241692f60a7Smrg}
3242