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