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