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