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