neo_driver.c revision 54569438
1/**********************************************************************
2Copyright 1998, 1999 by Precision Insight, Inc., Cedar Park, Texas.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, distribute, and sell this software and
7its documentation for any purpose is hereby granted without fee,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Precision Insight not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.  Precision Insight
13and its suppliers make no representations about the suitability of this
14software for any purpose.  It is provided "as is" without express or
15implied warranty.
16
17PRECISION INSIGHT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY
20SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
22CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24**********************************************************************/
25
26/*
27 * Copyright 1998, 1999 Egbert Eich
28 * Copyright 2000, 2001 SuSE GmbH, Author: Egbert Eich
29 * Copyright 2002 SuSE Linux AG, Author: Egbert Eich
30 * Copyright 2002 Shigehiro Nomura
31 */
32
33
34/*
35 * The original Precision Insight driver for
36 * XFree86 v.3.3 has been sponsored by Red Hat.
37 *
38 * Authors:
39 *   Jens Owen (jens@tungstengraphics.com)
40 *   Kevin E. Martin (kevin@precisioninsight.com)
41 *
42 * Port to Xfree86 v.4.0
43 *   1998, 1999 by Egbert Eich (Egbert.Eich@Physik.TU-Darmstadt.DE)
44 */
45
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50/* All drivers should typically include these */
51#include "xf86.h"
52#include "xf86_OSproc.h"
53
54/* Everything using inb/outb, etc needs "compiler.h" */
55#include "compiler.h"
56
57#include "xf86Resources.h"
58
59/* Drivers for PCI hardware need this */
60#include "xf86PciInfo.h"
61
62/* Drivers that need to access the PCI config space directly need this */
63#include "xf86Pci.h"
64
65/* All drivers using the vgahw module need this */
66#include "vgaHW.h"
67
68/* All drivers initialising the SW cursor need this */
69#include "mipointer.h"
70
71/* All drivers implementing backing store need this */
72#include "mibstore.h"
73
74/* All drivers using the mi banking wrapper need this */
75#include "mibank.h"
76
77/* All drivers using the mi colormap manipulation need this */
78#include "micmap.h"
79
80#include "xf86cmap.h"
81
82#include "fb.h"
83
84/* Needed by Resources Access Control (RAC) */
85#include "xf86RAC.h"
86
87/* int10 */
88#include "xf86int10.h"
89#include "vbe.h"
90
91/* Needed for Device Data Channel (DDC) support */
92#include "xf86DDC.h"
93
94#include "picturestr.h"
95
96#include "xf86xv.h"
97#include <X11/extensions/Xv.h>
98
99/*
100 * Driver data structures.
101 */
102#include "neo.h"
103#include "neo_reg.h"
104#include "neo_macros.h"
105
106/* These need to be checked */
107#include <X11/X.h>
108#include <X11/Xproto.h>
109#include "scrnintstr.h"
110#include "servermd.h"
111#ifdef XFreeXDGA
112#define _XF86DGA_SERVER_
113#include <X11/extensions/xf86dgastr.h>
114#endif
115
116/* Mandatory functions */
117static const OptionInfoRec *	NEOAvailableOptions(int chipid, int busid);
118static void     NEOIdentify(int flags);
119static Bool     NEOProbe(DriverPtr drv, int flags);
120static Bool     NEOPreInit(ScrnInfoPtr pScrn, int flags);
121static Bool     NEOScreenInit(int Index, ScreenPtr pScreen, int argc,
122                                  char **argv);
123static Bool     NEOEnterVT(int scrnIndex, int flags);
124static void     NEOLeaveVT(int scrnIndex, int flags);
125static Bool     NEOCloseScreen(int scrnIndex, ScreenPtr pScreen);
126static void     NEOFreeScreen(int scrnIndex, int flags);
127static ModeStatus NEOValidMode(int scrnIndex, DisplayModePtr mode,
128                               Bool verbose, int flags);
129
130/* Internally used functions */
131static int      neoFindIsaDevice(GDevPtr dev);
132static Bool     neoModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
133static void     neoSave(ScrnInfoPtr pScrn);
134static void     neoRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
135				 NeoRegPtr NeoReg, Bool restoreText);
136static void     neoLock(ScrnInfoPtr pScrn);
137static void     neoUnlock(ScrnInfoPtr pScrn);
138static Bool	neoMapMem(ScrnInfoPtr pScrn);
139static Bool	neoUnmapMem(ScrnInfoPtr pScrn);
140static void     neoProgramShadowRegs(ScrnInfoPtr pScrn, vgaRegPtr VgaReg,
141				     NeoRegPtr restore);
142static void     neoCalcVCLK(ScrnInfoPtr pScrn, long freq);
143static xf86MonPtr  neo_ddc1(int scrnIndex);
144static Bool     neoDoDDC1(ScrnInfoPtr pScrn);
145static Bool     neoDoDDC2(ScrnInfoPtr pScrn);
146static Bool     neoDoDDCVBE(ScrnInfoPtr pScrn);
147static void     neoProbeDDC(ScrnInfoPtr pScrn, int index);
148static void     NeoDisplayPowerManagementSet(ScrnInfoPtr pScrn,
149				int PowerManagementMode, int flags);
150static int      neoFindMode(int xres, int yres, int depth);
151
152#define NEO_VERSION 4000
153#define NEO_NAME "NEOMAGIC"
154#define NEO_DRIVER_NAME "neomagic"
155
156#define NEO_MAJOR_VERSION PACKAGE_VERSION_MAJOR
157#define NEO_MINOR_VERSION PACKAGE_VERSION_MINOR
158#define NEO_PATCHLEVEL PACKAGE_VERSION_PATCHLEVEL
159
160/*
161 * This is intentionally screen-independent.  It indicates the binding
162 * choice made in the first PreInit.
163 */
164static int pix24bpp = 0;
165
166
167static biosMode bios8[] = {
168    { 320, 240, 0x40 },
169    { 300, 400, 0x42 },
170    { 640, 400, 0x20 },
171    { 640, 480, 0x21 },
172    { 800, 600, 0x23 },
173    { 1024, 768, 0x25 }
174};
175
176static biosMode bios15[] = {
177    { 320, 200, 0x2D },
178    { 640, 480, 0x30 },
179    { 800, 600, 0x33 },
180    { 1024, 768, 0x36 }
181};
182
183static biosMode bios16[] = {
184    { 320, 200, 0x2e },
185    { 320, 240, 0x41 },
186    { 300, 400, 0x43 },
187    { 640, 480, 0x31 },
188    { 800, 600, 0x34 },
189    { 1024, 768, 0x37 }
190};
191
192static biosMode bios24[] = {
193    { 640, 480, 0x32 },
194    { 800, 600, 0x35 },
195    { 1024, 768, 0x38 }
196};
197
198static DisplayModeRec neo800x480Mode = {
199	NULL,           /* prev */
200	NULL,           /* next */
201	"800x480",      /* identifier of this mode */
202	MODE_OK,        /* mode status */
203	M_T_BUILTIN,    /* mode type */
204	35260,		/* Clock frequency */
205	800,		/* HDisplay */
206	856,		/* HSyncStart */
207	1040,		/* HSyncEnd */
208	1056,		/* HTotal */
209	0,		/* HSkew */
210	480,		/* VDisplay */
211	480,		/* VSyncStart */
212	486,		/* VSyncEnd */
213	488,		/* VTotal */
214	0,		/* VScan */
215	V_PHSYNC | V_PVSYNC,	/* Flags */
216	-1,		/* ClockIndex */
217	35260,		/* SynthClock */
218	800,		/* CRTC HDisplay */
219	800,            /* CRTC HBlankStart */
220	856,            /* CRTC HSyncStart */
221	1040,           /* CRTC HSyncEnd */
222	872,            /* CRTC HBlankEnd */
223	1048,           /* CRTC HTotal */
224	0,              /* CRTC HSkew */
225	480,		/* CRTC VDisplay */
226	480,		/* CRTC VBlankStart */
227	480,		/* CRTC VSyncStart */
228	486,		/* CRTC VSyncEnd */
229	487,		/* CRTC VBlankEnd */
230	488,		/* CRTC VTotal */
231	FALSE,		/* CrtcHAdjusted */
232	FALSE,		/* CrtcVAdjusted */
233	0,		/* PrivSize */
234	NULL,		/* Private */
235	0.0,		/* HSync */
236	0.0		/* VRefresh */
237};
238
239static DisplayModeRec neo1024x480Mode = {
240	NULL,           /* prev */
241	NULL,           /* next */
242	"1024x480",      /* identifier of this mode */
243	MODE_OK,        /* mode status */
244	M_T_BUILTIN,    /* mode type */
245	45900,		/* Clock frequency */
246	1024,		/* HDisplay */
247	1048,		/* HSyncStart */
248	1184,		/* HSyncEnd */
249	1344,		/* HTotal */
250	0,		/* HSkew */
251	480,		/* VDisplay */
252	480,		/* VSyncStart */
253	486,		/* VSyncEnd */
254	488,		/* VTotal */
255	0,		/* VScan */
256	V_PHSYNC | V_PVSYNC,	/* Flags */
257	-1,		/* ClockIndex */
258	45900,		/* SynthClock */
259	1024,		/* CRTC HDisplay */
260	1024,            /* CRTC HBlankStart */
261	1048,            /* CRTC HSyncStart */
262	1184,           /* CRTC HSyncEnd */
263	1072,            /* CRTC HBlankEnd */
264	1344,           /* CRTC HTotal */
265	0,              /* CRTC HSkew */
266	480,		/* CRTC VDisplay */
267	480,		/* CRTC VBlankStart */
268	480,		/* CRTC VSyncStart */
269	486,		/* CRTC VSyncEnd */
270	487,		/* CRTC VBlankEnd */
271	488,		/* CRTC VTotal */
272	FALSE,		/* CrtcHAdjusted */
273	FALSE,		/* CrtcVAdjusted */
274	0,		/* PrivSize */
275	NULL,		/* Private */
276	0.0,		/* HSync */
277	0.0		/* VRefresh */
278};
279
280/*
281 * This contains the functions needed by the server after loading the driver
282 * module.  It must be supplied, and gets passed back by the SetupProc
283 * function in the dynamic case.  In the static case, a reference to this
284 * is compiled in, and this requires that the name of this DriverRec be
285 * an upper-case version of the driver name.
286 */
287
288_X_EXPORT DriverRec NEOMAGIC = {
289    NEO_VERSION,
290    NEO_DRIVER_NAME,
291    NEOIdentify,
292    NEOProbe,
293    NEOAvailableOptions,
294    NULL,
295    0
296};
297
298static SymTabRec NEOChipsets[] = {
299    { NM2070,   "neo2070" },
300    { NM2090,   "neo2090" },
301    { NM2093,   "neo2093" },
302    { NM2097,   "neo2097" },
303    { NM2160,   "neo2160" },
304    { NM2200,   "neo2200" },
305    { NM2230,   "neo2230" },
306    { NM2360,   "neo2360" },
307    { NM2380,   "neo2380" },
308    { -1,		 NULL }
309};
310
311/* Conversion PCI ID to chipset name */
312static PciChipsets NEOPCIchipsets[] = {
313    { NM2070,  PCI_CHIP_NM2070,  RES_SHARED_VGA },
314    { NM2090,  PCI_CHIP_NM2090,  RES_SHARED_VGA },
315    { NM2093,  PCI_CHIP_NM2093,  RES_SHARED_VGA },
316    { NM2097,  PCI_CHIP_NM2097,  RES_SHARED_VGA },
317    { NM2160,  PCI_CHIP_NM2160,  RES_SHARED_VGA },
318    { NM2200,  PCI_CHIP_NM2200,  RES_SHARED_VGA },
319    { NM2230,  PCI_CHIP_NM2230,  RES_SHARED_VGA },
320    { NM2360,  PCI_CHIP_NM2360,  RES_SHARED_VGA },
321    { NM2380,  PCI_CHIP_NM2380,  RES_SHARED_VGA },
322    { -1,	     -1,	     RES_UNDEFINED}
323};
324
325#ifdef HAVE_ISA
326static IsaChipsets NEOISAchipsets[] = {
327    { NM2070,               RES_EXCLUSIVE_VGA },
328    { NM2090,               RES_EXCLUSIVE_VGA },
329    { NM2093,               RES_EXCLUSIVE_VGA },
330    { NM2097,               RES_EXCLUSIVE_VGA },
331    { NM2160,               RES_EXCLUSIVE_VGA },
332    { NM2200,               RES_EXCLUSIVE_VGA },
333    { -1,			RES_UNDEFINED }
334};
335#endif
336
337/* The options supported by the Neomagic Driver */
338typedef enum {
339    OPTION_NOLINEAR_MODE,
340    OPTION_NOACCEL,
341    OPTION_SW_CURSOR,
342    OPTION_NO_MMIO,
343    OPTION_INTERN_DISP,
344    OPTION_EXTERN_DISP,
345    OPTION_LCD_CENTER,
346    OPTION_LCD_STRETCH,
347    OPTION_SHADOW_FB,
348    OPTION_PCI_BURST,
349    OPTION_PROG_LCD_MODE_REGS,
350    OPTION_PROG_LCD_MODE_STRETCH,
351    OPTION_OVERRIDE_VALIDATE_MODE,
352    OPTION_SHOWCACHE,
353    OPTION_ROTATE,
354    OPTION_VIDEO_KEY,
355    OPTION_OVERLAYMEM,
356    OPTION_VIDEO_INTERLACE,
357    OPTION_DISPLAY_HEIGHT_480,
358    OPTION_STRANGE_LOCKUPS
359} NEOOpts;
360
361static const OptionInfoRec NEO_2070_Options[] = {
362    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
363    { OPTION_SW_CURSOR,	"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
364    { OPTION_NO_MMIO,	"noMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
365    { OPTION_INTERN_DISP,"internDisp",	OPTV_BOOLEAN,	{0}, FALSE },
366    { OPTION_EXTERN_DISP,"externDisp",  OPTV_BOOLEAN,	{0}, FALSE },
367    { OPTION_LCD_CENTER, "LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
368    { OPTION_LCD_STRETCH, "NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
369    { OPTION_SHADOW_FB,   "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
370    { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,   {0}, FALSE },
371    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
372    { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
373    { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
374      OPTV_BOOLEAN, {0}, FALSE },
375    { OPTION_PROG_LCD_MODE_STRETCH, "progLcdModeStretch",
376      OPTV_BOOLEAN, {0}, FALSE },
377    { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
378      OPTV_BOOLEAN, {0}, FALSE },
379    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
380    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
381    { OPTION_VIDEO_INTERLACE, "Interlace",
382      OPTV_INTEGER,   {0}, FALSE },
383    { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
384};
385
386static const OptionInfoRec NEOOptions[] = {
387    { OPTION_NOLINEAR_MODE,"NoLinear",  OPTV_BOOLEAN,	{0}, FALSE },
388    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE },
389    { OPTION_SW_CURSOR,	"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE },
390    { OPTION_NO_MMIO,	"noMMIO",	OPTV_BOOLEAN,	{0}, FALSE },
391    { OPTION_INTERN_DISP,"internDisp",	OPTV_BOOLEAN,	{0}, FALSE },
392    { OPTION_EXTERN_DISP,"externDisp",	OPTV_BOOLEAN,	{0}, FALSE },
393    { OPTION_LCD_CENTER, "LcdCenter",	OPTV_BOOLEAN,	{0}, FALSE },
394    { OPTION_SHADOW_FB,  "ShadowFB",	OPTV_BOOLEAN,	{0}, FALSE },
395    { OPTION_LCD_STRETCH,"NoStretch",	OPTV_BOOLEAN,	{0}, FALSE },
396    { OPTION_PCI_BURST,	 "pciBurst",	OPTV_BOOLEAN,	{0}, FALSE },
397    { OPTION_SHOWCACHE,  "ShowCache",   OPTV_BOOLEAN,	{0}, FALSE },
398    { OPTION_ROTATE, 	 "Rotate",	OPTV_ANYSTR,	{0}, FALSE },
399    { OPTION_STRANGE_LOCKUPS, "StrangeLockups", OPTV_BOOLEAN, {0}, FALSE },
400    { OPTION_DISPLAY_HEIGHT_480, "DisplayHeight480",
401      OPTV_BOOLEAN, {0}, FALSE },
402    { OPTION_PROG_LCD_MODE_REGS, "progLcdModeRegs",
403      OPTV_BOOLEAN, {0}, FALSE },
404    { OPTION_PROG_LCD_MODE_STRETCH, "progLcdModeStretch",
405      OPTV_BOOLEAN, {0}, FALSE },
406    { OPTION_OVERRIDE_VALIDATE_MODE, "overrideValidateMode",
407      OPTV_BOOLEAN, {0}, FALSE },
408    { OPTION_VIDEO_KEY, "VideoKey",     OPTV_INTEGER,   {0}, FALSE },
409    { OPTION_OVERLAYMEM, "OverlayMem",  OPTV_INTEGER,   {0}, FALSE },
410    { OPTION_VIDEO_INTERLACE, "Interlace",
411      OPTV_INTEGER,   {0}, FALSE },
412    { -1,                  NULL,           OPTV_NONE,	{0}, FALSE }
413};
414
415/*
416 * List of symbols from other modules that this module references.  This
417 * list is used to tell the loader that it is OK for symbols here to be
418 * unresolved providing that it hasn't been told that they haven't been
419 * told that they are essential via a call to xf86LoaderReqSymbols() or
420 * xf86LoaderReqSymLists().  The purpose is this is to avoid warnings about
421 * unresolved symbols that are not required.
422 */
423
424static const char *vgahwSymbols[] = {
425    "vgaHWFreeHWRec",
426    "vgaHWGetHWRec",
427    "vgaHWGetIOBase",
428    "vgaHWGetIndex",
429    "vgaHWInit",
430    "vgaHWLock",
431    "vgaHWMapMem",
432    "vgaHWProtect",
433    "vgaHWRestore",
434    "vgaHWSave",
435    "vgaHWSaveScreenWeak",
436    "vgaHWSetStdFuncs",
437    "vgaHWUnlock",
438    "vgaHWddc1SetSpeedWeak",
439    NULL
440};
441
442static const char *fbSymbols[] = {
443    "fbPictureInit",
444    "fbScreenInit",
445    NULL
446};
447
448static const char *xaaSymbols[] = {
449    "XAACreateInfoRec",
450    "XAADestroyInfoRec",
451    "XAAInit",
452    NULL
453};
454
455static const char *ramdacSymbols[] = {
456    "xf86CreateCursorInfoRec",
457    "xf86DestroyCursorInfoRec",
458    "xf86InitCursor",
459    NULL
460};
461
462static const char *shadowSymbols[] = {
463    "shadowInit",
464    NULL
465};
466
467static const char *ddcSymbols[] = {
468    "xf86DoEDID_DDC1",
469    "xf86DoEDID_DDC2",
470    "xf86PrintEDID",
471    "xf86SetDDCproperties",
472    NULL
473};
474
475static const char *vbeSymbols[] = {
476    "VBEInit",
477    "vbeDoEDID",
478    "vbeFree",
479    NULL
480};
481
482static const char *i2cSymbols[] = {
483    "xf86CreateI2CBusRec",
484    "xf86I2CBusInit",
485    NULL
486};
487
488#ifdef XFree86LOADER
489
490static MODULESETUPPROTO(neoSetup);
491
492static XF86ModuleVersionInfo neoVersRec =
493{
494	"neomagic",
495	MODULEVENDORSTRING,
496	MODINFOSTRING1,
497	MODINFOSTRING2,
498	XORG_VERSION_CURRENT,
499	NEO_MAJOR_VERSION, NEO_MINOR_VERSION, NEO_PATCHLEVEL,
500	ABI_CLASS_VIDEODRV,
501	ABI_VIDEODRV_VERSION,
502	MOD_CLASS_VIDEODRV,
503	{0,0,0,0}
504};
505
506/*
507 * This is the module init data.
508 * Its name has to be the driver name followed by ModuleData
509 */
510_X_EXPORT XF86ModuleData neomagicModuleData = { &neoVersRec, neoSetup, NULL };
511
512static pointer
513neoSetup(pointer module, pointer opts, int *errmaj, int *errmin)
514{
515    static Bool setupDone = FALSE;
516
517    if (!setupDone) {
518	setupDone = TRUE;
519        xf86AddDriver(&NEOMAGIC, module, 0);
520
521	/*
522	 * Modules that this driver always requires can be loaded here
523	 * by calling LoadSubModule().
524	 */
525
526	/*
527	 * Tell the loader about symbols from other modules that this module
528	 * might refer to.
529	 */
530	LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols,
531			  ramdacSymbols, shadowSymbols,
532			  ddcSymbols, vbeSymbols, i2cSymbols, NULL);
533	/*
534	 * The return value must be non-NULL on success even though there
535	 * is no TearDownProc.
536	 */
537  	return (pointer)1;
538    } else {
539	if (errmaj) *errmaj = LDR_ONCEONLY;
540	return NULL;
541    }
542}
543
544#endif /* XFree86LOADER */
545
546static Bool
547NEOGetRec(ScrnInfoPtr pScrn)
548{
549    /*
550     * Allocate a NEORec, and hook it into pScrn->driverPrivate.
551     * pScrn->driverPrivate is initialised to NULL, so we can check if
552     * the allocation has already been done.
553     */
554    if (pScrn->driverPrivate != NULL)
555	return TRUE;
556
557    pScrn->driverPrivate = xnfcalloc(sizeof(NEORec), 1);
558
559    if (pScrn->driverPrivate == NULL)
560	return FALSE;
561        return TRUE;
562}
563
564static void
565NEOFreeRec(ScrnInfoPtr pScrn)
566{
567    if (pScrn->driverPrivate == NULL)
568	return;
569    xfree(pScrn->driverPrivate);
570    pScrn->driverPrivate = NULL;
571}
572
573static const OptionInfoRec *
574NEOAvailableOptions(int chipid, int busid)
575{
576    int chip = (chipid & 0x0000ffff);
577
578    if (chip == PCI_CHIP_NM2070)
579	return NEO_2070_Options;
580    else
581    	return NEOOptions;
582}
583
584/* Mandatory */
585static void
586NEOIdentify(int flags)
587{
588    xf86PrintChipsets(NEO_NAME, "Driver for Neomagic chipsets",
589			NEOChipsets);
590}
591
592/* Mandatory */
593static Bool
594NEOProbe(DriverPtr drv, int flags)
595{
596    Bool foundScreen = FALSE;
597    int numDevSections, numUsed;
598    GDevPtr *devSections;
599    int *usedChips;
600    int i;
601
602    /*
603     * Find the config file Device sections that match this
604     * driver, and return if there are none.
605     */
606    if ((numDevSections = xf86MatchDevice(NEO_DRIVER_NAME,
607					  &devSections)) <= 0) {
608	return FALSE;
609    }
610
611    /* PCI BUS */
612#ifndef XSERVER_LIBPCIACCESS
613    if (xf86GetPciVideoInfo() )
614#endif
615    {
616	numUsed = xf86MatchPciInstances(NEO_NAME, PCI_VENDOR_NEOMAGIC,
617					NEOChipsets, NEOPCIchipsets,
618					devSections,numDevSections,
619					drv, &usedChips);
620
621	if (numUsed > 0) {
622	    if (flags & PROBE_DETECT)
623		foundScreen = TRUE;
624	    else for (i = 0; i < numUsed; i++) {
625		ScrnInfoPtr pScrn = NULL;
626		/* Allocate a ScrnInfoRec and claim the slot */
627		if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
628						       NEOPCIchipsets,NULL, NULL,
629						       NULL, NULL, NULL))) {
630		    pScrn->driverVersion = NEO_VERSION;
631		    pScrn->driverName    = NEO_DRIVER_NAME;
632		    pScrn->name          = NEO_NAME;
633		    pScrn->Probe         = NEOProbe;
634		    pScrn->PreInit       = NEOPreInit;
635		    pScrn->ScreenInit    = NEOScreenInit;
636		    pScrn->SwitchMode    = NEOSwitchMode;
637		    pScrn->AdjustFrame   = NEOAdjustFrame;
638		    pScrn->EnterVT       = NEOEnterVT;
639		    pScrn->LeaveVT       = NEOLeaveVT;
640		    pScrn->FreeScreen    = NEOFreeScreen;
641		    pScrn->ValidMode     = NEOValidMode;
642		    foundScreen = TRUE;
643		}
644	    }
645	    xfree(usedChips);
646	}
647    }
648
649#ifdef HAVE_ISA
650    /* Isa Bus */
651
652    numUsed = xf86MatchIsaInstances(NEO_NAME,NEOChipsets,NEOISAchipsets,
653				     drv,neoFindIsaDevice,devSections,
654				     numDevSections,&usedChips);
655    if (numUsed > 0) {
656      if (flags & PROBE_DETECT)
657	foundScreen = TRUE;
658      else for (i = 0; i < numUsed; i++) {
659	ScrnInfoPtr pScrn = NULL;
660	if ((pScrn = xf86ConfigIsaEntity(pScrn, 0, usedChips[i],
661					 NEOISAchipsets, NULL, NULL,
662					 NULL, NULL, NULL))) {
663	    pScrn->driverVersion = NEO_VERSION;
664	    pScrn->driverName    = NEO_DRIVER_NAME;
665	    pScrn->name          = NEO_NAME;
666	    pScrn->Probe         = NEOProbe;
667	    pScrn->PreInit       = NEOPreInit;
668	    pScrn->ScreenInit    = NEOScreenInit;
669	    pScrn->SwitchMode    = NEOSwitchMode;
670	    pScrn->AdjustFrame   = NEOAdjustFrame;
671	    pScrn->EnterVT       = NEOEnterVT;
672	    pScrn->LeaveVT       = NEOLeaveVT;
673	    pScrn->FreeScreen    = NEOFreeScreen;
674	    pScrn->ValidMode     = NEOValidMode;
675	    foundScreen = TRUE;
676	}
677      }
678      xfree(usedChips);
679    }
680#endif
681
682    xfree(devSections);
683    return foundScreen;
684}
685
686#ifdef HAVE_ISA
687static int
688neoFindIsaDevice(GDevPtr dev)
689{
690    unsigned int vgaIOBase;
691    unsigned char id;
692
693    vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0;
694    /* §§§ Too intrusive ? */
695    outw(GRAX, 0x2609); /* Unlock NeoMagic registers */
696
697    outb(vgaIOBase + 4, 0x1A);
698    id = inb(vgaIOBase + 5);
699
700    outw(GRAX, 0x0009); /* Lock NeoMagic registers */
701
702    switch (id) {
703    case PROBED_NM2070 :
704	return NM2070;
705    case PROBED_NM2090 :
706	return NM2090;
707    case PROBED_NM2093 :
708	return NM2093;
709    default :
710	return -1;
711    }
712}
713#endif
714
715/* Mandatory */
716Bool
717NEOPreInit(ScrnInfoPtr pScrn, int flags)
718{
719    ClockRangePtr clockRanges;
720    int i;
721    NEOPtr nPtr;
722    vgaHWPtr hwp;
723    int bppSupport = NoDepth24Support;
724    int videoRam = 896;
725    int maxClock = 65000;
726    int CursorMem = 1024;
727    int CursorOff = 0x100;
728    int linearSize = 1024;
729    int maxWidth = 1024;
730    int maxHeight = 1024;
731    unsigned char type, dpy;
732    int w;
733    int apertureSize;
734    Bool height_480 = FALSE;
735    Bool lcdCenterOptSet = FALSE;
736    char *s;
737
738    if (flags & PROBE_DETECT)  {
739	neoProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
740	return TRUE;
741    }
742
743    /* The vgahw module should be loaded here when needed */
744    if (!xf86LoadSubModule(pScrn, "vgahw"))
745	return FALSE;
746
747    xf86LoaderReqSymLists(vgahwSymbols, NULL);
748
749    /*
750     * Allocate a vgaHWRec.
751     */
752    if (!vgaHWGetHWRec(pScrn))
753	return FALSE;
754    hwp = VGAHWPTR(pScrn);
755
756    /* Allocate the NeoRec driverPrivate */
757    if (!NEOGetRec(pScrn)) {
758	return FALSE;
759    }
760# define RETURN \
761    { NEOFreeRec(pScrn);\
762			    return FALSE;\
763					     }
764
765    nPtr = NEOPTR(pScrn);
766
767    /* Since, the capabilities are determined by the chipset the very
768     * first thing to do is, figure out the chipset and its capabilities
769     */
770    /* This driver doesn't expect more than one entity per screen */
771    if (pScrn->numEntities > 1)
772	RETURN;
773
774    /* This is the general case */
775    for (i = 0; i<pScrn->numEntities; i++) {
776	nPtr->pEnt = xf86GetEntityInfo(pScrn->entityList[i]);
777	if (nPtr->pEnt->resources) return FALSE;
778	nPtr->NeoChipset = nPtr->pEnt->chipset;
779	pScrn->chipset = (char *)xf86TokenToString(NEOChipsets,
780						   nPtr->pEnt->chipset);
781	/* This driver can handle ISA and PCI buses */
782	if (nPtr->pEnt->location.type == BUS_PCI) {
783	    nPtr->PciInfo = xf86GetPciInfoForEntity(nPtr->pEnt->index);
784#ifndef XSERVER_LIBPCIACCESS
785	    nPtr->PciTag = pciTag(nPtr->PciInfo->bus,
786				  nPtr->PciInfo->device,
787				  nPtr->PciInfo->func);
788#endif
789	}
790    }
791    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Chipset is a ");
792    switch(nPtr->NeoChipset){
793    case NM2070:
794	xf86ErrorF("MagicGraph 128 (NM2070)");
795	break;
796    case NM2090 :
797	xf86ErrorF("MagicGraph 128V (NM2090)");
798	break;
799    case NM2093 :
800	xf86ErrorF("MagicGraph 128ZV (NM2093)");
801	break;
802    case NM2097 :
803	xf86ErrorF("MagicGraph 128ZV+ (NM2097)");
804	break;
805    case NM2160 :
806	xf86ErrorF("MagicGraph 128XD (NM2160)");
807	break;
808    case NM2200 :
809        xf86ErrorF("MagicMedia 256AV (NM2200)");
810	break;
811    case NM2230 :
812        xf86ErrorF("MagicMedia 256AV+ (NM2230)");
813	break;
814    case NM2360 :
815        xf86ErrorF("MagicMedia 256ZX (NM2360)");
816	break;
817    case NM2380 :
818        xf86ErrorF("MagicMedia 256XL+ (NM2380)");
819	break;
820    }
821    xf86ErrorF("\n");
822
823    vgaHWGetIOBase(hwp);
824    nPtr->vgaIOBase = hwp->IOBase;
825    vgaHWSetStdFuncs(hwp);
826
827    /* Determine the panel type */
828    VGAwGR(0x09,0x26);
829    type = VGArGR(0x21);
830    dpy = VGArGR(0x20);
831
832    /* Determine panel width -- used in NeoValidMode. */
833    w = VGArGR(0x20);
834    VGAwGR(0x09,0x00);
835    switch ((w & 0x18) >> 3) {
836    case 0x00 :
837	nPtr->NeoPanelWidth  = 640;
838	nPtr->NeoPanelHeight = 480;
839	break;
840    case 0x01 :
841	nPtr->NeoPanelWidth  = 800;
842	nPtr->NeoPanelHeight = 600;
843	break;
844    case 0x02 :
845	nPtr->NeoPanelWidth  = 1024;
846	nPtr->NeoPanelHeight = 768;
847	break;
848    case 0x03 :
849        /* 1280x1024 panel support needs to be added */
850#ifdef NOT_DONE
851	nPtr->NeoPanelWidth  = 1280;
852	nPtr->NeoPanelHeight = 1024;
853	break;
854#else
855	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
856		     "Only 640x480,\n"
857                     "     800x600,\n"
858                     " and 1024x768 panels are currently supported\n");
859	return FALSE;
860#endif
861    default :
862	nPtr->NeoPanelWidth  = 640;
863	nPtr->NeoPanelHeight = 480;
864	break;
865    }
866
867    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel is a %dx%d %s %s display\n",
868	       nPtr->NeoPanelWidth,
869	       nPtr->NeoPanelHeight,
870	       (type & 0x02) ? "color" : "monochrome",
871	       (type & 0x10) ? "TFT" : "dual scan");
872
873
874    switch (nPtr->NeoChipset){
875    case NM2070:
876	bppSupport = NoDepth24Support;
877	videoRam   = 896;
878	maxClock   = 65000;
879	CursorMem  = 2048;
880	CursorOff  = 0x100;
881	linearSize = 1024;
882	maxWidth   = 1024;
883	maxHeight  = 1024;
884	break;
885    case NM2090:
886    case NM2093:
887	bppSupport = Support24bppFb | Support32bppFb |
888	    SupportConvert32to24 | PreferConvert32to24;
889	videoRam   = 1152;
890	maxClock   = 80000;
891	CursorMem  = 2048;
892	CursorOff  = 0x100;
893	linearSize = 2048;
894	maxWidth   = 1024;
895	maxHeight  = 1024;
896	break;
897    case NM2097:
898	bppSupport = Support24bppFb | Support32bppFb |
899	  SupportConvert32to24 | PreferConvert32to24;
900	videoRam   = 1152;
901	maxClock   = 80000;
902	CursorMem  = 1024;
903	CursorOff  = 0x100;
904	linearSize = 2048;
905	maxWidth   = 1024;
906	maxHeight  = 1024;
907	break;
908    case NM2160:
909	bppSupport = Support24bppFb | Support32bppFb |
910	    SupportConvert32to24 | PreferConvert32to24;
911	videoRam   = 2048;
912	maxClock   = 90000;
913	CursorMem  = 1024;
914	CursorOff  = 0x100;
915	linearSize = 2048;
916	maxWidth   = 1024;
917	maxHeight  = 1024;
918	break;
919    case NM2200:
920	bppSupport = Support24bppFb | Support32bppFb |
921	    SupportConvert32to24 | PreferConvert32to24;
922	videoRam   = 2560;
923	maxClock   = 110000;
924	CursorMem  = 1024;
925	CursorOff  = 0x1000;
926	linearSize = 4096;
927	maxWidth   = 1280;
928	maxHeight  = 1024;  /* ???? */
929	break;
930    case NM2230:
931	bppSupport = Support24bppFb | Support32bppFb |
932	    SupportConvert32to24 | PreferConvert32to24;
933	videoRam   = 3008;
934	maxClock   = 110000;
935	CursorMem  = 1024;
936	CursorOff  = 0x1000;
937	linearSize = 4096;
938	maxWidth   = 1280;
939	maxHeight  = 1024;  /* ???? */
940	break;
941    case NM2360:
942	bppSupport = Support24bppFb | Support32bppFb |
943	    SupportConvert32to24 | PreferConvert32to24;
944	videoRam   = 4096;
945	maxClock   = 110000;
946	CursorMem  = 1024;
947	CursorOff  = 0x1000;
948	linearSize = 4096;
949	maxWidth   = 1280;
950	maxHeight  = 1024;  /* ???? */
951	break;
952    case NM2380:
953	bppSupport = Support24bppFb | Support32bppFb |
954	    SupportConvert32to24 | PreferConvert32to24;
955	videoRam   = 6144;
956	maxClock   = 110000;
957	CursorMem  = 1024;
958	CursorOff  = 0x1000;
959	linearSize = 8192;
960	maxWidth   = 1280;
961	maxHeight  = 1024;  /* ???? */
962	break;
963    }
964
965    pScrn->monitor = pScrn->confScreen->monitor;
966
967    if (xf86LoadSubModule(pScrn, "ddc")) {
968        xf86LoaderReqSymLists(ddcSymbols, NULL);
969#if 1 /* for DDC1 testing */
970	if (!neoDoDDCVBE(pScrn))
971	  if (!neoDoDDC2(pScrn))
972#endif
973	      neoDoDDC1(pScrn);
974    }
975
976    if (!xf86SetDepthBpp(pScrn, 16, 0, 0, bppSupport ))
977	return FALSE;
978    else {
979	/* Check that the returned depth is one we support */
980	switch (pScrn->depth) {
981	case 8:
982	case 15:
983	case 16:
984	    break;
985	case 24:
986	    if (nPtr->NeoChipset != NM2070)
987		break;
988	default:
989	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
990		       "Given depth (%d) is not supported by this driver\n",
991		       pScrn->depth);
992	    return FALSE;
993	}
994    }
995    xf86PrintDepthBpp(pScrn);
996    if (pScrn->depth == 8)
997	pScrn->rgbBits = 6;
998
999    /* Get the depth24 pixmap format */
1000    if (pScrn->depth == 24 && pix24bpp == 0)
1001	pix24bpp = xf86GetBppFromDepth(pScrn, 24);
1002
1003    /*
1004     * This must happen after pScrn->display has been set because
1005     * xf86SetWeight references it.
1006     */
1007    if (pScrn->depth > 8) {
1008	/* The defaults are OK for us */
1009	rgb zeros = {0, 0, 0};
1010
1011	if (!xf86SetWeight(pScrn, zeros, zeros)) {
1012	    return FALSE;
1013	} else {
1014	    /* XXX check that weight returned is supported */
1015	    ;
1016	}
1017    }
1018
1019    if (!xf86SetDefaultVisual(pScrn, -1))
1020	return FALSE;
1021
1022    if (pScrn->depth > 1) {
1023	Gamma zeros = {0.0, 0.0, 0.0};
1024
1025	if (!xf86SetGamma(pScrn, zeros))
1026	    return FALSE;
1027    }
1028
1029    nPtr->strangeLockups = TRUE;
1030
1031    /* Collect all of the relevant option flags (fill in pScrn->options) */
1032    xf86CollectOptions(pScrn, NULL);
1033    /* Process the options */
1034    if (nPtr->NeoChipset == NM2070) {
1035	if (!(nPtr->Options = xalloc(sizeof(NEO_2070_Options))))
1036	    return FALSE;
1037	memcpy(nPtr->Options, NEO_2070_Options, sizeof(NEO_2070_Options));
1038    } else {
1039	if (!(nPtr->Options = xalloc(sizeof(NEOOptions))))
1040	    return FALSE;
1041	memcpy(nPtr->Options, NEOOptions, sizeof(NEOOptions));
1042    }
1043
1044    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, nPtr->Options);
1045
1046    xf86GetOptValBool(nPtr->Options, OPTION_NOLINEAR_MODE,&nPtr->noLinear);
1047    xf86GetOptValBool(nPtr->Options, OPTION_SW_CURSOR,&nPtr->swCursor);
1048    xf86GetOptValBool(nPtr->Options, OPTION_NO_MMIO,&nPtr->noMMIO);
1049    xf86GetOptValBool(nPtr->Options, OPTION_INTERN_DISP,&nPtr->internDisp);
1050    xf86GetOptValBool(nPtr->Options, OPTION_EXTERN_DISP,&nPtr->externDisp);
1051    if (xf86GetOptValBool(nPtr->Options, OPTION_LCD_CENTER,&nPtr->lcdCenter))
1052	lcdCenterOptSet = TRUE;
1053    xf86GetOptValBool(nPtr->Options, OPTION_LCD_STRETCH,&nPtr->noLcdStretch);
1054    xf86GetOptValBool(nPtr->Options, OPTION_SHADOW_FB,&nPtr->shadowFB);
1055    xf86GetOptValBool(nPtr->Options, OPTION_SHOWCACHE,&nPtr->showcache);
1056    nPtr->onPciBurst = TRUE;
1057    xf86GetOptValBool(nPtr->Options, OPTION_PCI_BURST,&nPtr->onPciBurst);
1058    xf86GetOptValBool(nPtr->Options,
1059		      OPTION_PROG_LCD_MODE_REGS,&nPtr->progLcdRegs);
1060    if (xf86GetOptValBool(nPtr->Options,
1061		      OPTION_PROG_LCD_MODE_STRETCH,&nPtr->progLcdStretch))
1062	nPtr->progLcdStretchOpt = TRUE;
1063    xf86GetOptValBool(nPtr->Options,
1064		      OPTION_OVERRIDE_VALIDATE_MODE, &nPtr->overrideValidate);
1065    xf86GetOptValBool(nPtr->Options, OPTION_DISPLAY_HEIGHT_480,&height_480);
1066    xf86GetOptValBool(nPtr->Options, OPTION_STRANGE_LOCKUPS,
1067		      &nPtr->strangeLockups);
1068    nPtr->noAccelSet =
1069	xf86GetOptValBool(nPtr->Options, OPTION_NOACCEL,&nPtr->noAccel);
1070
1071    nPtr->rotate = 0;
1072    if ((s = xf86GetOptValString(nPtr->Options, OPTION_ROTATE))) {
1073	if(!xf86NameCmp(s, "CW")) {
1074	    /* accel is disabled below for shadowFB */
1075	    nPtr->shadowFB = TRUE;
1076	    nPtr->swCursor = TRUE;
1077	    nPtr->rotate = 1;
1078	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1079		       "Rotating screen clockwise - acceleration disabled\n");
1080	} else if(!xf86NameCmp(s, "CCW")) {
1081	    nPtr->shadowFB = TRUE;
1082	    nPtr->swCursor = TRUE;
1083	    nPtr->rotate = -1;
1084	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,  "Rotating screen"
1085		       "counter clockwise - acceleration disabled\n");
1086	} else {
1087	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
1088		       "value for Option \"Rotate\"\n", s);
1089	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1090		       "Valid options are \"CW\" or \"CCW\"\n");
1091      }
1092    }
1093
1094    if(xf86GetOptValInteger(nPtr->Options,
1095			    OPTION_VIDEO_KEY, &(nPtr->videoKey))) {
1096        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
1097		   nPtr->videoKey);
1098    } else {
1099        nPtr->videoKey = (1 << pScrn->offset.red) |
1100	    (1 << pScrn->offset.green) |
1101	    (((pScrn->mask.blue >> pScrn->offset.blue) - 1)
1102	     << pScrn->offset.blue);
1103    }
1104    if(xf86GetOptValInteger(nPtr->Options, OPTION_OVERLAYMEM,
1105			    &(nPtr->overlay))) {
1106        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1107		   "reserve %d bytes for overlay.\n", nPtr->overlay);
1108    } else {
1109	nPtr->overlay = 0;
1110    }
1111    nPtr->interlace = 0;
1112    if(xf86GetOptValInteger(nPtr->Options, OPTION_VIDEO_INTERLACE,
1113			    &(nPtr->interlace))) {
1114	if (nPtr->interlace >= 0  &&  nPtr->interlace <= 2){
1115	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "interlace flag = %d\n",
1116		       nPtr->interlace);
1117	} else {
1118	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1119		       "\"%s\" is not a valid value for "
1120		       "Option \"Interlaced\"\n", s);
1121	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid options are  0..2\n");
1122        }
1123    }
1124
1125    if (height_480
1126	&& (nPtr->NeoPanelWidth == 800 || nPtr->NeoPanelWidth == 1024)) {
1127	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1128		   "Overriding Panel height: Set to 480\n");
1129	nPtr->NeoPanelHeight = 480;
1130	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1131		   "Disabling LCD stretching for panel height 480\n");
1132	nPtr->noLcdStretch = TRUE;
1133	if (!lcdCenterOptSet)
1134	    nPtr->lcdCenter = TRUE;
1135    }
1136
1137    if (nPtr->internDisp && nPtr->externDisp)
1138	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1139		   "Simultaneous LCD/CRT display mode\n");
1140    else if (nPtr->externDisp)
1141	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1142		   "External CRT only display mode\n");
1143    else  if (nPtr->internDisp)
1144	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1145		   "Internal LCD only display mode\n");
1146    else {
1147	nPtr->internDisp = ((dpy & 0x02) == 0x02);
1148    	nPtr->externDisp = ((dpy & 0x01) == 0x01);
1149	if (nPtr->internDisp && nPtr->externDisp)
1150	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1151		       "Simultaneous LCD/CRT display mode\n");
1152	else if (nPtr->externDisp)
1153	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1154		       "External CRT only display mode\n");
1155	else if (nPtr->internDisp)
1156	    xf86DrvMsg(pScrn->scrnIndex,X_PROBED,
1157		       "Internal LCD only display mode\n");
1158	else {
1159	    /* this is a fallback if probed values are bogus */
1160	    nPtr->internDisp = TRUE;
1161	    xf86DrvMsg(pScrn->scrnIndex,X_DEFAULT,
1162		       "Internal LCD only display mode\n");
1163	}
1164    }
1165
1166    if (nPtr->noLcdStretch)
1167	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1168		   "Low resolution video modes are not stretched\n");
1169    if (nPtr->lcdCenter)
1170	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1171		   "Video modes are centered on the display\n");
1172    if (nPtr->noLinear)
1173	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using nonlinear mode\n");
1174    else
1175	xf86DrvMsg(pScrn->scrnIndex,X_DEFAULT, "using linear mode\n");
1176    if (nPtr->swCursor)
1177	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using sofware cursor\n");
1178    if (nPtr->noMMIO)
1179	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "MMIO mode disabled\n");
1180    if (nPtr->onPciBurst)
1181	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG, "using PCI Burst mode\n");
1182    if (nPtr->strangeLockups)
1183	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1184		   "Option StrangeLockups set: disabling some acceleration\n");
1185    if (nPtr->showcache)
1186	xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,
1187		   "Show chache for debugging\n");
1188    if (nPtr->shadowFB) {
1189	if (nPtr->noLinear) {
1190    	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1191		       "Option \"ShadowFB\" ignored. Not supported without"
1192		       " linear addressing\n");
1193	    nPtr->shadowFB = FALSE;
1194	    nPtr->rotate = 0;
1195	} else {
1196	    nPtr->noAccel = TRUE;
1197	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1198		    "Using \"Shadow Framebuffer\" - acceleration disabled\n");
1199	}
1200    }
1201
1202    nPtr->NeoFbMapSize = linearSize * 1024;
1203    nPtr->NeoCursorOffset = CursorOff;
1204
1205    if (nPtr->pEnt->device->MemBase) {
1206	/* XXX Check this matches a PCI base address */
1207	nPtr->NeoLinearAddr = nPtr->pEnt->device->MemBase;
1208	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1209		   "FB base address is set at 0x%lX.\n",
1210		   nPtr->NeoLinearAddr);
1211    } else {
1212	nPtr->NeoLinearAddr = 0;
1213    }
1214
1215    nPtr->NeoMMIOAddr2 = 0;
1216    nPtr->NeoMMIOBase2 = NULL;
1217    if (nPtr->pEnt->device->IOBase && !nPtr->noMMIO) {
1218	/* XXX Check this matches a PCI base address */
1219	nPtr->NeoMMIOAddr = nPtr->pEnt->device->IOBase;
1220	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1221		   "MMIO base address is set at 0x%lX.\n",
1222		   nPtr->NeoMMIOAddr);
1223    } else {
1224	nPtr->NeoMMIOAddr = 0;
1225    }
1226
1227    if (nPtr->pEnt->location.type == BUS_PCI) {
1228	if (!nPtr->NeoLinearAddr) {
1229	    nPtr->NeoLinearAddr = PCI_REGION_BASE(nPtr->PciInfo, 0, REGION_MEM);
1230	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1231		       "FB base address is set at 0x%lX.\n",
1232		       nPtr->NeoLinearAddr);
1233	}
1234	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
1235	    switch (nPtr->NeoChipset) {
1236	    case NM2070 :
1237		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
1238		break;
1239	    case NM2090:
1240	    case NM2093:
1241		nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x200000;
1242		break;
1243	    case NM2160:
1244	    case NM2097:
1245	    case NM2200:
1246	    case NM2230:
1247	    case NM2360:
1248	    case NM2380:
1249		nPtr->NeoMMIOAddr = PCI_REGION_BASE(nPtr->PciInfo, 1, REGION_MEM);
1250		nPtr->NeoMMIOAddr2 = PCI_REGION_BASE(nPtr->PciInfo, 2, REGION_MEM);
1251		break;
1252	    }
1253	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1254		       "MMIO base address is set at 0x%lX.\n",
1255		       nPtr->NeoMMIOAddr);
1256	    if (nPtr->NeoMMIOAddr2 != 0){
1257	        xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1258		           "MMIO base address2 is set at 0x%lX.\n",
1259		           nPtr->NeoMMIOAddr2);
1260	    }
1261	}
1262	/* XXX What about VGA resources in OPERATING mode? */
1263	if (xf86RegisterResources(nPtr->pEnt->index, NULL, ResExclusive))
1264	    RETURN;
1265
1266    } else if (nPtr->pEnt->location.type == BUS_ISA) {
1267	unsigned int addr;
1268	resRange linearRes[] = { {ResExcMemBlock|ResBios|ResBus,0,0},_END };
1269
1270	if (!nPtr->NeoLinearAddr) {
1271	    VGAwGR(0x09,0x26);
1272	    addr = VGArGR(0x13);
1273	    VGAwGR(0x09,0x00);
1274	    nPtr->NeoLinearAddr = addr << 20;
1275	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1276		       "FB base address is set at 0x%lX.\n",
1277		       nPtr->NeoLinearAddr);
1278	}
1279	if (!nPtr->NeoMMIOAddr && !nPtr->noMMIO) {
1280	    nPtr->NeoMMIOAddr = nPtr->NeoLinearAddr + 0x100000;
1281	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1282		       "MMIO base address is set at 0x%lX.\n",
1283		       nPtr->NeoMMIOAddr);
1284	}
1285	linearRes[0].rBegin = nPtr->NeoLinearAddr;
1286	linearRes[1].rEnd = nPtr->NeoLinearAddr + nPtr->NeoFbMapSize - 1;
1287	if (xf86RegisterResources(nPtr->pEnt->index,linearRes,ResNone)) {
1288	    nPtr->noLinear = TRUE; /* XXX */
1289	}
1290    } else
1291	RETURN;
1292
1293    if (nPtr->pEnt->device->videoRam != 0) {
1294	pScrn->videoRam = nPtr->pEnt->device->videoRam;
1295	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "VideoRAM: %d kByte\n",
1296		   pScrn->videoRam);
1297    } else {
1298	pScrn->videoRam = videoRam;
1299	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "VideoRAM: %d kByte\n",
1300		   pScrn->videoRam);
1301    }
1302
1303    if (nPtr->pEnt->device->dacSpeeds[0] != 0) {
1304	maxClock = nPtr->pEnt->device->dacSpeeds[0];
1305	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Max Clock: %d kHz\n",
1306		   maxClock);
1307    } else {
1308	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Max Clock: %d kHz\n",
1309		   maxClock);
1310    }
1311
1312    pScrn->progClock = TRUE;
1313    /*
1314     * Setup the ClockRanges, which describe what clock ranges are available,
1315     * and what sort of modes they can be used for.
1316     */
1317    clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
1318    clockRanges->next = NULL;
1319    clockRanges->ClockMulFactor = 1;
1320    clockRanges->minClock = 11000;   /* guessed §§§ */
1321    clockRanges->maxClock = maxClock;
1322    clockRanges->clockIndex = -1;		/* programmable */
1323	clockRanges->interlaceAllowed = FALSE;
1324    clockRanges->doubleScanAllowed = TRUE;
1325
1326    /* Subtract memory for HW cursor */
1327    if (!nPtr->swCursor)
1328	nPtr->NeoCursorMem = CursorMem;
1329    else
1330	nPtr->NeoCursorMem = 0;
1331    apertureSize = (pScrn->videoRam * 1024) - nPtr->NeoCursorMem;
1332
1333    if ((nPtr->NeoPanelWidth == 800) && (nPtr->NeoPanelHeight == 480)) {
1334	neo800x480Mode.next = pScrn->monitor->Modes;
1335	pScrn->monitor->Modes = &neo800x480Mode;
1336    }
1337    if ((nPtr->NeoPanelWidth == 1024) && (nPtr->NeoPanelHeight == 480)) {
1338	neo1024x480Mode.next = pScrn->monitor->Modes;
1339	pScrn->monitor->Modes = &neo1024x480Mode;
1340    }
1341
1342    if (!pScrn->monitor->DDC) {
1343	/*
1344	 * If the monitor parameters are not specified explicitly, set them
1345	 * so that 60Hz modes up to the panel size are allowed.
1346	 */
1347	if (pScrn->monitor->nHsync == 0) {
1348	    pScrn->monitor->nHsync = 1;
1349	    pScrn->monitor->hsync[0].lo = 28;
1350	    pScrn->monitor->hsync[0].hi =
1351				60.0 * 1.07 * nPtr->NeoPanelHeight / 1000.0;
1352	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1353		       "Using hsync range matching panel size: %.2f-%.2f kHz\n",
1354		       pScrn->monitor->hsync[0].lo,
1355		       pScrn->monitor->hsync[0].hi);
1356	}
1357	if (pScrn->monitor->nVrefresh == 0) {
1358	    pScrn->monitor->nVrefresh = 1;
1359	    pScrn->monitor->vrefresh[0].lo = 55.0;
1360	    pScrn->monitor->vrefresh[0].hi = 65.0;
1361	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1362		       "Using vsync range for panel: %.2f-%.2f kHz\n",
1363		       pScrn->monitor->vrefresh[0].lo,
1364		       pScrn->monitor->vrefresh[0].hi);
1365	}
1366    }
1367
1368    /*
1369     * For external displays, limit the width to 1024 pixels or less.
1370     */
1371    {
1372       i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
1373			  pScrn->display->modes, clockRanges,
1374			  NULL, 256, maxWidth,(8 * pScrn->bitsPerPixel),/*§§§*/
1375			  128, maxHeight, pScrn->display->virtualX,
1376			  pScrn->display->virtualY, apertureSize,
1377			  LOOKUP_BEST_REFRESH);
1378
1379       if (i == -1)
1380           RETURN;
1381    }
1382
1383    /* Prune the modes marked as invalid */
1384    xf86PruneDriverModes(pScrn);
1385
1386    if (i == 0 || pScrn->modes == NULL) {
1387	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1388	RETURN;
1389    }
1390
1391    /*
1392     * Set the CRTC parameters for all of the modes based on the type
1393     * of mode, and the chipset's interlace requirements.
1394     *
1395     * Calling this is required if the mode->Crtc* values are used by the
1396     * driver and if the driver doesn't provide code to set them.  They
1397     * are not pre-initialised at all.
1398     */
1399    xf86SetCrtcForModes(pScrn, 0);
1400
1401    /* Set the current mode to the first in the list */
1402    pScrn->currentMode = pScrn->modes;
1403
1404    /* Print the list of modes being used */
1405    xf86PrintModes(pScrn);
1406
1407    /* If monitor resolution is set on the command line, use it */
1408    xf86SetDpi(pScrn, 0, 0);
1409
1410    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
1411	RETURN;
1412    }
1413
1414    xf86LoaderReqSymLists(fbSymbols, NULL);
1415
1416    if (!nPtr->noLinear) {
1417	if (!xf86LoadSubModule(pScrn, "xaa"))
1418	    RETURN;
1419	xf86LoaderReqSymLists(xaaSymbols, NULL);
1420    }
1421
1422    if (nPtr->shadowFB) {
1423	if (!xf86LoadSubModule(pScrn, "shadow")) {
1424	    RETURN;
1425	}
1426	xf86LoaderReqSymLists(shadowSymbols, NULL);
1427    }
1428
1429    if (!nPtr->swCursor) {
1430	if (!xf86LoadSubModule(pScrn, "ramdac"))
1431	    RETURN;
1432	xf86LoaderReqSymLists(ramdacSymbols, NULL);
1433    }
1434    return TRUE;
1435}
1436#undef RETURN
1437
1438/* Mandatory */
1439static Bool
1440NEOEnterVT(int scrnIndex, int flags)
1441{
1442    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1443    NEOPtr nPtr = NEOPTR(pScrn);
1444
1445    /* Should we re-save the text mode on each VT enter? */
1446    if(!neoModeInit(pScrn, pScrn->currentMode))
1447      return FALSE;
1448
1449    if (nPtr->video)
1450	NEOResetVideo(pScrn);
1451
1452    if (nPtr->NeoHWCursorShown)
1453	NeoShowCursor(pScrn);
1454    NEOAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1455
1456    return TRUE;
1457}
1458
1459/* Mandatory */
1460static void
1461NEOLeaveVT(int scrnIndex, int flags)
1462{
1463    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1464    NEOPtr nPtr = NEOPTR(pScrn);
1465
1466    /* Invalidate the cached acceleration registers */
1467    if (nPtr->NeoHWCursorShown)
1468	NeoHideCursor(pScrn);
1469    neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
1470    neoLock(pScrn);
1471
1472}
1473
1474static void
1475NEOLoadPalette(
1476   ScrnInfoPtr pScrn,
1477   int numColors,
1478   int *indices,
1479   LOCO *colors,
1480   VisualPtr pVisual
1481){
1482   int i, index, shift, Gshift;
1483   vgaHWPtr hwp = VGAHWPTR(pScrn);
1484
1485   switch(pScrn->depth) {
1486   case 15:
1487	shift = Gshift = 1;
1488	break;
1489   case 16:
1490	shift = 0;
1491        Gshift = 0;
1492	break;
1493   default:
1494	shift = Gshift = 0;
1495	break;
1496   }
1497
1498   for(i = 0; i < numColors; i++) {
1499        index = indices[i];
1500        hwp->writeDacWriteAddr(hwp, index);
1501	DACDelay(hwp);
1502        hwp->writeDacData(hwp, colors[index].red << shift);
1503	DACDelay(hwp);
1504        hwp->writeDacData(hwp, colors[index].green << Gshift);
1505	DACDelay(hwp);
1506        hwp->writeDacData(hwp, colors[index].blue << shift);
1507	DACDelay(hwp);
1508   }
1509}
1510
1511/* Mandatory */
1512static Bool
1513NEOScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
1514{
1515    ScrnInfoPtr pScrn;
1516    vgaHWPtr hwp;
1517    NEOPtr nPtr;
1518    NEOACLPtr nAcl;
1519    int ret;
1520    VisualPtr visual;
1521    int allocatebase, freespace, currentaddr;
1522    unsigned int racflag = RAC_FB;
1523    unsigned char *FBStart;
1524    int height, width, displayWidth;
1525
1526    /*
1527     * we need to get the ScrnInfoRec for this screen, so let's allocate
1528     * one first thing
1529     */
1530    pScrn = xf86Screens[pScreen->myNum];
1531    nPtr = NEOPTR(pScrn);
1532    nAcl = NEOACLPTR(pScrn);
1533
1534    hwp = VGAHWPTR(pScrn);
1535    hwp->MapSize = 0x10000;		/* Standard 64k VGA window */
1536    /* Map the VGA memory */
1537    if (!vgaHWMapMem(pScrn))
1538	return FALSE;
1539
1540    /* Map the Neo memory and possible MMIO areas */
1541    if (!neoMapMem(pScrn))
1542	return FALSE;
1543
1544    /*
1545     * next we save the current state and setup the first mode
1546     */
1547    neoSave(pScrn);
1548
1549    if (!neoModeInit(pScrn,pScrn->currentMode))
1550	return FALSE;
1551    vgaHWSaveScreen(pScreen,SCREEN_SAVER_ON);
1552    NEOAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1553
1554    /*
1555     * Reset visual list.
1556     */
1557    miClearVisualTypes();
1558
1559    /* Setup the visuals we support. */
1560#if 0
1561    if (!miSetVisualTypes(pScrn->depth,
1562      		      miGetDefaultVisualMask(pScrn->depth),
1563		      pScrn->rgbBits, pScrn->defaultVisual))
1564         return FALSE;
1565#else
1566    if (!miSetVisualTypes(pScrn->depth,
1567      		      miGetDefaultVisualMask(pScrn->depth),
1568		      pScrn->rgbBits, pScrn->defaultVisual))
1569         return FALSE;
1570    if (pScrn->depth > 8) {
1571	if (!miSetVisualTypes(8, miGetDefaultVisualMask(8), 6,
1572			      pScrn->defaultVisual))
1573	    return FALSE;
1574    }
1575#endif
1576    if (!miSetPixmapDepths ()) return FALSE;
1577
1578    /*
1579     * Call the framebuffer layer's ScreenInit function, and fill in other
1580     * pScreen fields.
1581     */
1582    displayWidth = pScrn->displayWidth;
1583    if (nPtr->rotate) {
1584	height = pScrn->virtualX;
1585	width = pScrn->virtualY;
1586    } else {
1587	width = pScrn->virtualX;
1588	height = pScrn->virtualY;
1589    }
1590
1591    if(nPtr->shadowFB) {
1592	nPtr->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
1593	nPtr->ShadowPtr = xalloc(nPtr->ShadowPitch * height);
1594	displayWidth = nPtr->ShadowPitch / (pScrn->bitsPerPixel >> 3);
1595	FBStart = nPtr->ShadowPtr;
1596    } else {
1597	nPtr->ShadowPtr = NULL;
1598	FBStart = nPtr->NeoFbBase;
1599    }
1600
1601    ret = fbScreenInit(pScreen, FBStart,
1602			    width, height,
1603			    pScrn->xDpi, pScrn->yDpi,
1604			    displayWidth, pScrn->bitsPerPixel);
1605    if (!ret)
1606	return FALSE;
1607    if (pScrn->depth > 8) {
1608        /* Fixup RGB ordering */
1609        visual = pScreen->visuals + pScreen->numVisuals;
1610        while (--visual >= pScreen->visuals) {
1611	    if ((visual->class | DynamicClass) == DirectColor
1612		&& visual->nplanes > 8) {
1613		visual->offsetRed = pScrn->offset.red;
1614		visual->offsetGreen = pScrn->offset.green;
1615		visual->offsetBlue = pScrn->offset.blue;
1616		visual->redMask = pScrn->mask.red;
1617		visual->greenMask = pScrn->mask.green;
1618		visual->blueMask = pScrn->mask.blue;
1619	    }
1620	}
1621    }
1622
1623    /* must be after RGB ordering fixed */
1624    fbPictureInit(pScreen, 0, 0);
1625
1626    xf86SetBlackWhitePixels(pScreen);
1627
1628    if (!nPtr->shadowFB)
1629	NEODGAInit(pScreen);
1630
1631    nPtr->NeoHWCursorShown = FALSE;
1632    nPtr->NeoHWCursorInitialized = FALSE;
1633    nAcl->UseHWCursor = FALSE;
1634    nAcl->CursorAddress = -1;
1635
1636    if (nPtr->noLinear) {
1637	miBankInfoPtr pBankInfo;
1638
1639	/* Setup the vga banking variables */
1640	pBankInfo = (miBankInfoPtr)xnfcalloc(sizeof(miBankInfoRec),1);
1641	if (pBankInfo == NULL)
1642	    return FALSE;
1643
1644	pBankInfo->pBankA = hwp->Base;
1645	pBankInfo->pBankB = (unsigned char *)hwp->Base;
1646	pBankInfo->BankSize = 0x10000;
1647	pBankInfo->nBankDepth = pScrn->depth;
1648
1649	pBankInfo->SetSourceBank = (miBankProcPtr)NEOSetRead;
1650	pBankInfo->SetDestinationBank =
1651	    (miBankProcPtr)NEOSetWrite;
1652	pBankInfo->SetSourceAndDestinationBanks =
1653	    (miBankProcPtr)NEOSetReadWrite;
1654	if (!miInitializeBanking(pScreen, pScrn->virtualX, pScrn->virtualY,
1655				 pScrn->displayWidth, pBankInfo)) {
1656	    xfree(pBankInfo);
1657	    pBankInfo = NULL;
1658	    return FALSE;
1659	}
1660	xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Using nonlinear mode\n");
1661	xf86DrvMsg(pScrn->scrnIndex,X_INFO, "Using software cursor in "
1662		   "nonlinear mode\n");
1663    } else {
1664	nAcl->cacheStart = -1;
1665	nAcl->cacheEnd = -1;
1666	xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1667		   "Using linear framebuffer at: 0x%08lX\n",
1668		   nPtr->NeoLinearAddr);
1669	/* Setup pointers to free space in video ram */
1670	allocatebase = (pScrn->videoRam << 10);
1671	freespace = allocatebase - pScrn->displayWidth *
1672	    pScrn->virtualY * (pScrn->bitsPerPixel >> 3);
1673	currentaddr = allocatebase;
1674	xf86DrvMsg(scrnIndex, X_PROBED,
1675		   "%d bytes off-screen memory available\n", freespace);
1676
1677	if (nPtr->swCursor || !nPtr->NeoMMIOBase) {
1678	    xf86DrvMsg(scrnIndex, X_CONFIG,
1679		       "Using Software Cursor.\n");
1680	} else if (nPtr->NeoCursorMem <= freespace) {
1681	    currentaddr -= nPtr->NeoCursorMem;
1682	    freespace  -= nPtr->NeoCursorMem;
1683	    /* alignment */
1684	    freespace  -= currentaddr & 0x3FF;
1685	    currentaddr &= 0xfffffc00;
1686	    nAcl->CursorAddress = currentaddr;
1687	    xf86DrvMsg(scrnIndex, X_INFO,
1688		       "Using H/W Cursor.\n");
1689	} else {
1690	    xf86DrvMsg(scrnIndex, X_ERROR,
1691		       "Too little space for H/W cursor.\n");
1692	}
1693
1694	if (!nPtr->noAccel && !nPtr->NeoMMIOBase)
1695	  xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1696		     "Acceleration disabled when not using MMIO\n");
1697
1698	if (nPtr->overlay > 0){
1699	    if (nPtr->overlay > freespace){
1700		xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1701			   "Can not reserve %d bytes for overlay. "
1702			   "Resize to %d bytes.\n",
1703			   nPtr->overlay, freespace);
1704		nPtr->overlay = freespace;
1705	    }
1706	    currentaddr -= nPtr->overlay;
1707	    freespace -= nPtr->overlay;
1708	    nPtr->overlay_offset = currentaddr;
1709	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Overlay at 0x%x\n",
1710		       nPtr->overlay_offset);
1711	}
1712
1713	nAcl->cacheStart = currentaddr - freespace;
1714	nAcl->cacheEnd = currentaddr;
1715	freespace = 0;
1716	if (nAcl->cacheStart < nAcl->cacheEnd) {
1717	    BoxRec AvailFBArea;
1718	    int lines = nAcl->cacheEnd /
1719		(pScrn->displayWidth * (pScrn->bitsPerPixel >> 3));
1720	    if (!nPtr->noAccel && nPtr->NeoMMIOBase && lines > 1024)
1721		lines = 1024;
1722	    AvailFBArea.x1 = 0;
1723	    AvailFBArea.y1 = 0;
1724	    AvailFBArea.x2 = pScrn->displayWidth;
1725	    AvailFBArea.y2 = lines;
1726	    xf86InitFBManager(pScreen, &AvailFBArea);
1727
1728	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1729		       "Using %i scanlines of offscreen memory \n",
1730		       lines - pScrn->virtualY);
1731	}
1732
1733	/* Setup the acceleration primitives */
1734	if (!nPtr->noAccel && nPtr->NeoMMIOBase) {
1735	    Bool ret = FALSE;
1736	    if (nAcl->cacheStart >= nAcl->cacheEnd) {
1737		xf86DrvMsg(scrnIndex, X_ERROR,
1738			   "Too little space for pixmap cache.\n");
1739	    }
1740	    switch(nPtr->NeoChipset) {
1741	    case NM2070 :
1742		ret = Neo2070AccelInit(pScreen);
1743		break;
1744	    case NM2090 :
1745	    case NM2093 :
1746		ret = Neo2090AccelInit(pScreen);
1747		break;
1748	    case NM2097 :
1749	    case NM2160 :
1750		ret = Neo2097AccelInit(pScreen);
1751		break;
1752	    case NM2200 :
1753	    case NM2230 :
1754	    case NM2360 :
1755	    case NM2380 :
1756	        ret = Neo2200AccelInit(pScreen);
1757		break;
1758	    }
1759	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1760		       "Acceleration %s Initialized\n",ret ? "" : "not");
1761	}
1762
1763    }
1764    miInitializeBackingStore(pScreen);
1765    xf86SetBackingStore(pScreen);
1766    xf86SetSilkenMouse(pScreen);
1767
1768    /* Initialise cursor functions */
1769    miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
1770
1771    if (nAcl->CursorAddress != -1) {
1772      /* HW cursor functions */
1773      if (!NeoCursorInit(pScreen)) {
1774	xf86DrvMsg(scrnIndex, X_ERROR,
1775		   "Hardware cursor initialization failed\n");
1776	return FALSE;
1777      }
1778      nAcl->UseHWCursor = TRUE;
1779      nPtr->NeoHWCursorInitialized = TRUE;
1780    } else
1781      nAcl->UseHWCursor = FALSE;
1782
1783    if (nPtr->shadowFB) {
1784        nPtr->refreshArea = neoRefreshArea;
1785
1786	if(nPtr->rotate) {
1787	    if (!nPtr->PointerMoved) {
1788		nPtr->PointerMoved = pScrn->PointerMoved;
1789		pScrn->PointerMoved = neoPointerMoved;
1790	    }
1791	    switch(pScrn->bitsPerPixel) {
1792	    case 8:	nPtr->refreshArea = neoRefreshArea8;	break;
1793	    case 16:	nPtr->refreshArea = neoRefreshArea16;	break;
1794	    case 24:	nPtr->refreshArea = neoRefreshArea24;	break;
1795	    case 32:	nPtr->refreshArea = neoRefreshArea32;	break;
1796	    }
1797	}
1798#if 0
1799	ShadowFBInit(pScreen, nPtr->refreshArea);
1800#else
1801	shadowInit (pScreen, neoShadowUpdate, 0);
1802#endif
1803    }
1804
1805    /* Initialise default colourmap */
1806    if(!miCreateDefColormap(pScreen))
1807	return FALSE;
1808
1809    if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits,
1810                         NEOLoadPalette, NULL,
1811                         CMAP_PALETTED_TRUECOLOR | CMAP_RELOAD_ON_MODE_SWITCH))
1812	return FALSE;
1813
1814    racflag |= RAC_COLORMAP;
1815    if (nPtr->NeoHWCursorInitialized)
1816        racflag |= RAC_CURSOR;
1817
1818    pScrn->racIoFlags = pScrn->racMemFlags = racflag;
1819
1820    NEOInitVideo(pScreen);
1821
1822    pScreen->SaveScreen = vgaHWSaveScreenWeak();
1823
1824    /* Setup DPMS mode */
1825    if (nPtr->NeoChipset != NM2070)
1826	xf86DPMSInit(pScreen, (DPMSSetProcPtr)NeoDisplayPowerManagementSet,
1827		     0);
1828
1829    if (!nPtr->noLinear) {
1830	pScrn->memPhysBase = (unsigned long)nPtr->NeoLinearAddr;
1831	pScrn->fbOffset = 0;
1832    }
1833
1834    /* Wrap the current CloseScreen function */
1835    nPtr->CloseScreen = pScreen->CloseScreen;
1836    pScreen->CloseScreen = NEOCloseScreen;
1837
1838    /* Report any unused options (only for the first generation) */
1839    if (serverGeneration == 1) {
1840	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1841    }
1842
1843    return TRUE;
1844}
1845
1846/* Mandatory */
1847Bool
1848NEOSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
1849{
1850    return neoModeInit(xf86Screens[scrnIndex], mode);
1851}
1852
1853/* Mandatory */
1854void
1855NEOAdjustFrame(int scrnIndex, int x, int y, int flags)
1856{
1857    ScrnInfoPtr pScrn;
1858    NEOPtr nPtr;
1859    vgaHWPtr hwp;
1860    int oldExtCRTDispAddr;
1861    int Base;
1862
1863    pScrn = xf86Screens[scrnIndex];
1864    hwp = VGAHWPTR(pScrn);
1865    nPtr = NEOPTR(pScrn);
1866
1867    if (nPtr->showcache && y) {
1868	int lastline = nPtr->NeoFbMapSize /
1869	    ((pScrn->displayWidth * pScrn->bitsPerPixel) / 8);
1870
1871	lastline -= pScrn->currentMode->VDisplay;
1872	y += pScrn->virtualY - 1;
1873        if (y > lastline) y = lastline;
1874    }
1875
1876    Base = (y * pScrn->displayWidth + x) >> 2;
1877
1878    /* Scale Base by the number of bytes per pixel. */
1879    switch (pScrn->depth) {
1880    case  8 :
1881	break;
1882    case 15 :
1883    case 16 :
1884	Base *= 2;
1885	break;
1886    case 24 :
1887	Base *= 3;
1888	break;
1889    default :
1890	break;
1891    }
1892    /*
1893     * These are the generic starting address registers.
1894     */
1895    VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
1896    VGAwCR(0x0D, (Base & 0x00FF));
1897
1898    /*
1899     * Make sure we don't clobber some other bits that might already
1900     * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
1901     * be needed.
1902     */
1903    oldExtCRTDispAddr = VGArGR(0x0E);
1904    VGAwGR(0x0E,(((Base >> 16) & 0x07) | (oldExtCRTDispAddr & 0xf8)));
1905#if 0
1906    /*
1907     * This is a workaround for a higher level bug that causes the cursor
1908     * to be at the wrong position after a virtual screen resolution change
1909     */
1910    if (nPtr->NeoHWCursorInitialized) { /*§§§ do we still need this?*/
1911	NeoRepositionCursor();
1912    }
1913#endif
1914}
1915
1916/* Mandatory */
1917static Bool
1918NEOCloseScreen(int scrnIndex, ScreenPtr pScreen)
1919{
1920    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1921    NEOPtr nPtr = NEOPTR(pScrn);
1922
1923    if(pScrn->vtSema){
1924	if (nPtr->NeoHWCursorShown)
1925	    NeoHideCursor(pScrn);
1926	neoRestore(pScrn, &(VGAHWPTR(pScrn))->SavedReg, &nPtr->NeoSavedReg, TRUE);
1927
1928	neoLock(pScrn);
1929	neoUnmapMem(pScrn);
1930    }
1931    if (nPtr->AccelInfoRec)
1932	XAADestroyInfoRec(nPtr->AccelInfoRec);
1933    if (nPtr->CursorInfo)
1934	xf86DestroyCursorInfoRec(nPtr->CursorInfo);
1935    if (nPtr->ShadowPtr)
1936	xfree(nPtr->ShadowPtr);
1937
1938    pScrn->vtSema = FALSE;
1939    pScreen->CloseScreen = nPtr->CloseScreen;
1940    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
1941}
1942
1943/* Optional */
1944static void
1945NEOFreeScreen(int scrnIndex, int flags)
1946{
1947    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
1948	vgaHWFreeHWRec(xf86Screens[scrnIndex]);
1949    NEOFreeRec(xf86Screens[scrnIndex]);
1950}
1951
1952/* Optional */
1953static ModeStatus
1954NEOValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
1955{
1956    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
1957    NEOPtr nPtr = NEOPTR(pScrn);
1958    int vDisplay = mode->VDisplay * ((mode->Flags & V_DBLSCAN) ? 2 : 1);
1959
1960    /*
1961     * Is there any LineCompare Bit 10? Where?
1962     * The 9 well known VGA bits give us a maximum height of 1024
1963     */
1964    if (vDisplay > 1024)
1965	return MODE_BAD;
1966
1967    /*
1968     * Limit the modes to just those allowed by the various NeoMagic
1969     * chips.
1970     */
1971
1972    if (nPtr->overrideValidate) {
1973	xf86DrvMsg(scrnIndex, X_WARNING, "display mode validation disabled\n");
1974    } else {
1975	/*
1976	 * When the LCD is active, only allow modes that are (1) equal to
1977	 * or smaller than the size of the panel and (2) are one of the
1978	 * following sizes: 1024x768, 800x600, 640x480.
1979	 */
1980	if (nPtr->internDisp || !nPtr->externDisp) {
1981	    /* Is the mode larger than the LCD panel? */
1982	    if ((mode->HDisplay > nPtr->NeoPanelWidth) ||
1983		(vDisplay > nPtr->NeoPanelHeight)) {
1984		xf86DrvMsg(scrnIndex,X_INFO, "Removing mode (%dx%d) "
1985			   "larger than the LCD panel (%dx%d)\n",
1986			   mode->HDisplay,
1987			   mode->VDisplay,
1988			   nPtr->NeoPanelWidth,
1989			   nPtr->NeoPanelHeight);
1990		return(MODE_BAD);
1991	    }
1992
1993	    /* Is the mode one of the acceptable sizes? */
1994	    switch (mode->HDisplay) {
1995	    case 1280:
1996		if (mode->VDisplay == 1024)
1997		    return(MODE_OK);
1998		break;
1999	    case 1024 :
2000		if (mode->VDisplay == 768)
2001		    return(MODE_OK);
2002		if ((mode->VDisplay == 480) && (nPtr->NeoPanelHeight == 480))
2003		    return(MODE_OK);
2004		break;
2005	    case  800 :
2006		if (mode->VDisplay == 600)
2007		    return(MODE_OK);
2008		if ((mode->VDisplay == 480) && (nPtr->NeoPanelHeight == 480))
2009		    return(MODE_OK);
2010		break;
2011	    case  640 :
2012		if (mode->VDisplay == 480)
2013		    return(MODE_OK);
2014		break;
2015#if 1
2016	    case 320:
2017		if (mode->VDisplay == 240)
2018		    return(MODE_OK);
2019		break;
2020#endif
2021	    default:
2022		break;
2023	    }
2024
2025	    xf86DrvMsg(scrnIndex, X_INFO, "Removing mode (%dx%d) that won't "
2026		       "display properly on LCD\n",
2027		       mode->HDisplay,
2028		       mode->VDisplay);
2029	    return(MODE_BAD);
2030	}
2031    }
2032    return(MODE_OK);
2033}
2034
2035static void
2036neoLock(ScrnInfoPtr pScrn)
2037{
2038    vgaHWPtr hwp = VGAHWPTR(pScrn);
2039
2040    VGAwGR(0x09,0x00);
2041    vgaHWLock(hwp);
2042}
2043
2044static void
2045neoUnlock(ScrnInfoPtr pScrn)
2046{
2047    vgaHWPtr hwp = VGAHWPTR(pScrn);
2048
2049    vgaHWUnlock(hwp);
2050    VGAwGR(0x09,0x26);
2051}
2052
2053static Bool
2054neoMapMem(ScrnInfoPtr pScrn)
2055{
2056    NEOPtr nPtr = NEOPTR(pScrn);
2057    vgaHWPtr hwp = VGAHWPTR(pScrn);
2058
2059    if (!nPtr->noLinear) {
2060	if (!nPtr->noMMIO) {
2061	    if (nPtr->pEnt->location.type == BUS_PCI){
2062
2063#ifndef XSERVER_LIBPCIACCESS
2064		nPtr->NeoMMIOBase =
2065		    xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
2066				  nPtr->PciTag, nPtr->NeoMMIOAddr,
2067				  0x200000L);
2068		if (nPtr->NeoMMIOAddr2 != 0){
2069		    nPtr->NeoMMIOBase2 =
2070		        xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
2071				      nPtr->PciTag, nPtr->NeoMMIOAddr2,
2072				      0x100000L);
2073		}
2074
2075#else
2076		void** result = (void**)&nPtr->NeoMMIOBase;
2077		int err = pci_device_map_range(nPtr->PciInfo,
2078					       nPtr->NeoMMIOAddr,
2079					       0x200000L,
2080					       PCI_DEV_MAP_FLAG_WRITABLE,
2081					       result);
2082		if (err)
2083		    return FALSE;
2084
2085		if (nPtr->NeoMMIOAddr2 != 0){
2086		    result = (void**)&nPtr->NeoMMIOBase2;
2087		    err = pci_device_map_range(nPtr->PciInfo,
2088						   nPtr->NeoMMIOAddr2,
2089						   0x100000L,
2090						   PCI_DEV_MAP_FLAG_WRITABLE,
2091						   result);
2092
2093		    if (err)
2094			return FALSE;
2095		}
2096#endif
2097	    } else
2098		nPtr->NeoMMIOBase =
2099		    xf86MapVidMem(pScrn->scrnIndex,
2100				  VIDMEM_MMIO, nPtr->NeoMMIOAddr,
2101				  0x200000L);
2102	    if (nPtr->NeoMMIOBase == NULL)
2103	        return FALSE;
2104	}
2105
2106	if (nPtr->pEnt->location.type == BUS_PCI)
2107
2108#ifndef XSERVER_LIBPCIACCESS
2109	    nPtr->NeoFbBase =
2110		xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2111			      nPtr->PciTag,
2112			      (unsigned long)nPtr->NeoLinearAddr,
2113			      nPtr->NeoFbMapSize);
2114#else
2115	{
2116	    void** result = (void**)&nPtr->NeoFbBase;
2117	    int err = pci_device_map_range(nPtr->PciInfo,
2118					   nPtr->NeoLinearAddr,
2119					   nPtr->NeoFbMapSize,
2120					   PCI_DEV_MAP_FLAG_WRITABLE |
2121					   PCI_DEV_MAP_FLAG_WRITE_COMBINE,
2122					   result);
2123	    if (err)
2124		return FALSE;
2125	}
2126#endif
2127	else
2128	    nPtr->NeoFbBase =
2129		xf86MapVidMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2130			      (unsigned long)nPtr->NeoLinearAddr,
2131			      nPtr->NeoFbMapSize);
2132	if (nPtr->NeoFbBase == NULL)
2133	    return FALSE;
2134    } else {
2135	/* In paged mode Base is the VGA window at 0xA0000 */
2136	nPtr->NeoFbBase = hwp->Base;
2137    }
2138    return TRUE;
2139}
2140
2141/*
2142 * Unmap the framebuffer and MMIO memory.
2143 */
2144
2145static Bool
2146neoUnmapMem(ScrnInfoPtr pScrn)
2147{
2148    NEOPtr nPtr = NEOPTR(pScrn);
2149
2150    if (!nPtr->noLinear) {
2151#ifndef XSERVER_LIBPCIACCESS
2152      if (nPtr->NeoMMIOBase)
2153	  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase,
2154			  0x200000L);
2155#else
2156      if (nPtr->NeoMMIOBase)
2157	  pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoMMIOBase, 0x200000L);
2158#endif
2159      nPtr->NeoMMIOBase = NULL;
2160#ifndef XSERVER_LIBPCIACCESS
2161      if (nPtr->NeoMMIOBase2)
2162	  xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoMMIOBase2,
2163			  0x100000L);
2164#else
2165      if (nPtr->NeoMMIOBase2)
2166	  pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoMMIOBase2, 0x100000L);
2167#endif
2168      nPtr->NeoMMIOBase2 = NULL;
2169#ifndef XSERVER_LIBPCIACCESS
2170      xf86UnMapVidMem(pScrn->scrnIndex, (pointer)nPtr->NeoFbBase,
2171		    nPtr->NeoFbMapSize);
2172#else
2173      pci_device_unmap_range(nPtr->PciInfo, (pointer)nPtr->NeoFbBase, nPtr->NeoFbMapSize);
2174#endif
2175    }
2176    nPtr->NeoFbBase = NULL;
2177
2178    return TRUE;
2179}
2180
2181static void
2182neoSave(ScrnInfoPtr pScrn)
2183{
2184    vgaRegPtr VgaSave = &VGAHWPTR(pScrn)->SavedReg;
2185    vgaHWPtr hwp = VGAHWPTR(pScrn);
2186    NEOPtr nPtr = NEOPTR(pScrn);
2187    NeoRegPtr save;
2188    int i;
2189
2190    save = &nPtr->NeoSavedReg;
2191
2192    VGAwGR(0x09,0x26);
2193    /*
2194     * Whatever code is needed to get back to bank zero goes here.
2195     */
2196    VGAwGR(0x15,0x00);
2197
2198    /* get generic registers */
2199    vgaHWSave(pScrn, VgaSave, VGA_SR_ALL);
2200
2201    /*
2202     * The port I/O code necessary to read in the extended registers
2203     * into the fields of the vgaNeoRec structure goes here.
2204     */
2205
2206    save->GeneralLockReg = VGArGR(0x0A);
2207
2208    save->ExtCRTDispAddr = VGArGR(0x0E);
2209    if (nPtr->NeoChipset != NM2070) {
2210	save->ExtCRTOffset = VGArGR(0x0F);
2211    }
2212    save->SysIfaceCntl1 = VGArGR(0x10);
2213    save->SysIfaceCntl2 = VGArGR(0x11);
2214    save->SingleAddrPage = VGArGR(0x15);
2215    save->DualAddrPage = VGArGR(0x16);
2216    save->PanelDispCntlReg1 = VGArGR(0x20);
2217    save->PanelDispCntlReg2 = VGArGR(0x25);
2218    save->PanelDispCntlReg3 = VGArGR(0x30);
2219    save->PanelVertCenterReg1 = VGArGR(0x28);
2220    save->PanelVertCenterReg2 = VGArGR(0x29);
2221    save->PanelVertCenterReg3 = VGArGR(0x2A);
2222    if (nPtr->NeoChipset != NM2070) {
2223        save->PanelVertCenterReg4 = VGArGR(0x32);
2224	save->PanelHorizCenterReg1 = VGArGR(0x33);
2225	save->PanelHorizCenterReg2 = VGArGR(0x34);
2226	save->PanelHorizCenterReg3 = VGArGR(0x35);
2227    }
2228    if (nPtr->NeoChipset == NM2160) {
2229        save->PanelHorizCenterReg4 = VGArGR(0x36);
2230    }
2231    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2232	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2233	save->PanelHorizCenterReg4 = VGArGR(0x36);
2234	save->PanelVertCenterReg5  = VGArGR(0x37);
2235	save->PanelHorizCenterReg5 = VGArGR(0x38);
2236    }
2237    save->ExtColorModeSelect = VGArGR(0x90);
2238    save->VCLK3NumeratorLow = VGArGR(0x9B);
2239    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2240	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380)
2241	save->VCLK3NumeratorHigh = VGArGR(0x8F);
2242    save->VCLK3Denominator = VGArGR(0x9F);
2243    save->ProgramVCLK = TRUE;
2244
2245    if (save->reg == NULL)
2246        save->reg = (regSavePtr)xnfcalloc(sizeof(regSaveRec), 1);
2247    else
2248        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2249		   "Non-NULL reg in NeoSave: reg=%p\n", (void *)save->reg);
2250
2251    save->reg->CR[0x23] = VGArCR(0x23);
2252    save->reg->CR[0x25] = VGArCR(0x25);
2253    save->reg->CR[0x2F] = VGArCR(0x2F);
2254    for (i = 0x40; i <= 0x59; i++) {
2255	save->reg->CR[i] = VGArCR(i);
2256    }
2257    for (i = 0x60; i <= 0x69; i++) {
2258	save->reg->CR[i] = VGArCR(i);
2259    }
2260    for (i = 0x70; i <= NEO_EXT_CR_MAX; i++) {
2261	save->reg->CR[i] = VGArCR(i);
2262    }
2263
2264    for (i = 0x0A; i <= NEO_EXT_GR_MAX; i++) {
2265        save->reg->GR[i] = VGArGR(i);
2266    }
2267}
2268
2269/*
2270 * neoProgramShadowRegs
2271 *
2272 * Setup the shadow registers to their default values.  The NeoSave
2273 * routines will restore the proper values on server exit.
2274 */
2275static void
2276neoProgramShadowRegs(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, NeoRegPtr restore)
2277{
2278    int i;
2279    Bool noProgramShadowRegs;
2280    vgaHWPtr hwp = VGAHWPTR(pScrn);
2281    NEOPtr nPtr = NEOPTR(pScrn);
2282    Bool prog_lcd;
2283
2284    /*
2285     * If display is external only and we want internal
2286     * we need to program the shadow registers.
2287     */
2288    prog_lcd = (((VGArGR(0x20) & 0x3) == 0x1) && nPtr->internDisp);
2289
2290
2291    /*
2292     * Convoluted logic for shadow register programming.
2293     *
2294     * As far as we know, shadow programming is needed for the 2070,
2295     * but not in stretched modes.  Special case this code.
2296     */
2297    switch (nPtr->NeoChipset) {
2298    case NM2070:
2299	/* Program the shadow regs by default */
2300	noProgramShadowRegs = FALSE;
2301	if (!nPtr->progLcdRegs && !prog_lcd)
2302	    noProgramShadowRegs = TRUE;
2303
2304	if (restore->PanelDispCntlReg2 & 0x84) {
2305	    /* Don't program by default if in stretch mode */
2306	    noProgramShadowRegs = TRUE;
2307	    if (nPtr->progLcdStretch)
2308		noProgramShadowRegs = FALSE;
2309	}
2310	break;
2311    case NM2090:
2312    case NM2093:
2313    case NM2097:
2314    case NM2160:
2315    case NM2200:
2316    case NM2230:
2317    case NM2360:
2318    case NM2380:
2319    default:
2320	/* Don't program the shadow regs by default */
2321	noProgramShadowRegs = TRUE;
2322	if (nPtr->progLcdRegs || prog_lcd)
2323	    noProgramShadowRegs = FALSE;
2324
2325	if (restore->PanelDispCntlReg2 & 0x84) {
2326	    /* Only change the behavior if an option is set */
2327	    if (nPtr->progLcdStretchOpt)
2328		noProgramShadowRegs = !nPtr->progLcdStretch;
2329	}
2330	break;
2331    }
2332
2333    if (noProgramShadowRegs) {
2334	xf86DrvMsgVerb(pScrn->scrnIndex,X_INFO,5,"Not programming shadow registers\n");
2335	if (nPtr->NeoSavedReg.reg){
2336	    for (i = 0x40; i <= 0x59; i++) {
2337		VGAwCR(i, nPtr->NeoSavedReg.reg->CR[i]);
2338	    }
2339	    for (i = 0x60; i <= 0x64; i++) {
2340		VGAwCR(i, nPtr->NeoSavedReg.reg->CR[i]);
2341	    }
2342	}
2343    } else {
2344	/*
2345	 * Program the shadow regs based on the panel width.  This works
2346	 * fine for normal sized panels, but what about the odd ones like
2347	 * the Libretto 100 which has an 800x480 panel???
2348	 */
2349	switch (nPtr->NeoPanelWidth) {
2350	case 640 :
2351	    VGAwCR(0x40,0x5F);
2352	    VGAwCR(0x41,0x50);
2353	    VGAwCR(0x42,0x02);
2354	    VGAwCR(0x43,0x55);
2355	    VGAwCR(0x44,0x81);
2356	    VGAwCR(0x45,0x0B);
2357	    VGAwCR(0x46,0x2E);
2358	    VGAwCR(0x47,0xEA);
2359	    VGAwCR(0x48,0x0C);
2360	    VGAwCR(0x49,0xE7);
2361	    VGAwCR(0x4A,0x04);
2362	    VGAwCR(0x4B,0x2D);
2363	    VGAwCR(0x4C,0x28);
2364	    VGAwCR(0x4D,0x90);
2365	    VGAwCR(0x4E,0x2B);
2366	    VGAwCR(0x4F,0xA0);
2367	    break;
2368	case 800 :
2369	    switch (nPtr->NeoPanelHeight) {
2370	    case 600:
2371		VGAwCR(0x40,0x7F);
2372		VGAwCR(0x41,0x63);
2373		VGAwCR(0x42,0x02);
2374		VGAwCR(0x43,0x6C);
2375		VGAwCR(0x44,0x1C);
2376		VGAwCR(0x45,0x72);
2377		VGAwCR(0x46,0xE0);
2378		VGAwCR(0x47,0x58);
2379		VGAwCR(0x48,0x0C);
2380		VGAwCR(0x49,0x57);
2381		VGAwCR(0x4A,0x73);
2382		VGAwCR(0x4B,0x3D);
2383		VGAwCR(0x4C,0x31);
2384		VGAwCR(0x4D,0x01);
2385		VGAwCR(0x4E,0x36);
2386		VGAwCR(0x4F,0x1E);
2387		if (nPtr->NeoChipset != NM2070) {
2388		    VGAwCR(0x50,0x6B);
2389		    VGAwCR(0x51,0x4F);
2390		    VGAwCR(0x52,0x0E);
2391		    VGAwCR(0x53,0x58);
2392		    VGAwCR(0x54,0x88);
2393		    VGAwCR(0x55,0x33);
2394		    VGAwCR(0x56,0x27);
2395		    VGAwCR(0x57,0x16);
2396		    VGAwCR(0x58,0x2C);
2397		    VGAwCR(0x59,0x94);
2398		}
2399		break;
2400	    case 480:
2401		VGAwCR(0x40,0x7F);
2402		VGAwCR(0x41,0x63);
2403		VGAwCR(0x42,0x02);
2404		VGAwCR(0x43,0x6B);
2405		VGAwCR(0x44,0x1B);
2406		VGAwCR(0x45,0x72);
2407		VGAwCR(0x46,0xE0);
2408		VGAwCR(0x47,0x1C);
2409		VGAwCR(0x48,0x00);
2410		VGAwCR(0x49,0x57);
2411		VGAwCR(0x4A,0x73);
2412		VGAwCR(0x4B,0x3E);
2413		VGAwCR(0x4C,0x31);
2414		VGAwCR(0x4D,0x01);
2415		VGAwCR(0x4E,0x36);
2416		VGAwCR(0x4F,0x1E);
2417		VGAwCR(0x50,0x6B);
2418		VGAwCR(0x51,0x4F);
2419		VGAwCR(0x52,0x0E);
2420		VGAwCR(0x53,0x57);
2421		VGAwCR(0x54,0x87);
2422		VGAwCR(0x55,0x33);
2423		VGAwCR(0x56,0x27);
2424		VGAwCR(0x57,0x16);
2425		VGAwCR(0x58,0x2C);
2426		VGAwCR(0x59,0x94);
2427		break;
2428		break;
2429		/* Not done */
2430	    }
2431	    break;
2432	case 1024 :
2433	    switch (nPtr->NeoPanelHeight) {
2434	    case 768:
2435		VGAwCR(0x40,0xA3);
2436		VGAwCR(0x41,0x7F);
2437		VGAwCR(0x42,0x06);
2438		VGAwCR(0x43,0x85);
2439		VGAwCR(0x44,0x96);
2440		VGAwCR(0x45,0x24);
2441		VGAwCR(0x46,0xE5);
2442		VGAwCR(0x47,0x02);
2443		VGAwCR(0x48,0x08);
2444		VGAwCR(0x49,0xFF);
2445		VGAwCR(0x4A,0x25);
2446		VGAwCR(0x4B,0x4F);
2447		VGAwCR(0x4C,0x40);
2448		VGAwCR(0x4D,0x00);
2449		VGAwCR(0x4E,0x44);
2450		VGAwCR(0x4F,0x0C);
2451		VGAwCR(0x50,0x7A);
2452		VGAwCR(0x51,0x56);
2453		VGAwCR(0x52,0x00);
2454		VGAwCR(0x53,0x5D);
2455		VGAwCR(0x54,0x0E);
2456		VGAwCR(0x55,0x3B);
2457		VGAwCR(0x56,0x2B);
2458		VGAwCR(0x57,0x00);
2459		VGAwCR(0x58,0x2F);
2460		VGAwCR(0x59,0x18);
2461		VGAwCR(0x60,0x88);
2462		VGAwCR(0x61,0x63);
2463		VGAwCR(0x62,0x0B);
2464		VGAwCR(0x63,0x69);
2465		VGAwCR(0x64,0x1A);
2466		break;
2467	    case 480:
2468		VGAwCR(0x40,0xA3);
2469		VGAwCR(0x41,0x7F);
2470		VGAwCR(0x42,0x1B);
2471		VGAwCR(0x43,0x89);
2472		VGAwCR(0x44,0x16);
2473		VGAwCR(0x45,0x0B);
2474		VGAwCR(0x46,0x2C);
2475		VGAwCR(0x47,0xE8);
2476		VGAwCR(0x48,0x0C);
2477		VGAwCR(0x49,0xE7);
2478		VGAwCR(0x4A,0x09);
2479		VGAwCR(0x4B,0x4F);
2480		VGAwCR(0x4C,0x40);
2481		VGAwCR(0x4D,0x00);
2482		VGAwCR(0x4E,0x44);
2483		VGAwCR(0x4F,0x0C);
2484		VGAwCR(0x50,0x7A);
2485		VGAwCR(0x51,0x56);
2486		VGAwCR(0x52,0x00);
2487		VGAwCR(0x53,0x5D);
2488		VGAwCR(0x54,0x0E);
2489		VGAwCR(0x55,0x3B);
2490		VGAwCR(0x56,0x2A);
2491		VGAwCR(0x57,0x00);
2492		VGAwCR(0x58,0x2F);
2493		VGAwCR(0x59,0x18);
2494		VGAwCR(0x60,0x88);
2495		VGAwCR(0x61,0x63);
2496		VGAwCR(0x62,0x0B);
2497		VGAwCR(0x63,0x69);
2498		VGAwCR(0x64,0x1A);
2499		break;
2500	    }
2501	    break;
2502	case 1280:
2503#ifdef NOT_DONE
2504	    VGAwCR(0x40,0x?? );
2505            .
2506		.
2507		.
2508		VGAwCR(0x64,0x?? );
2509		break;
2510#else
2511		/* Probe should prevent this case for now */
2512		FatalError("1280 panel support incomplete\n");
2513#endif
2514	}
2515    }
2516}
2517
2518static void
2519neoRestore(ScrnInfoPtr pScrn, vgaRegPtr VgaReg, NeoRegPtr restore,
2520	     Bool restoreText)
2521{
2522    NEOPtr nPtr = NEOPTR(pScrn);
2523    vgaHWPtr hwp = VGAHWPTR(pScrn);
2524    unsigned char temp;
2525    int i;
2526    Bool clock_hi = FALSE;
2527
2528    vgaHWProtect(pScrn,TRUE);		/* Blank the screen */
2529
2530    VGAwGR(0x09,0x26);
2531
2532    /* Init the shadow registers if necessary */
2533    neoProgramShadowRegs(pScrn, VgaReg, restore);
2534
2535    VGAwGR(0x15,0x00);
2536
2537    VGAwGR(0x0A,restore->GeneralLockReg);
2538
2539    /*
2540     * The color mode needs to be set before calling vgaHWRestore
2541     * to ensure the DAC is initialized properly.
2542     *
2543     * NOTE: Make sure we don't change bits make sure we don't change
2544     * any reserved bits.
2545     */
2546    temp = VGArGR(0x90);
2547
2548    switch (nPtr->NeoChipset) {
2549    case NM2070 :
2550	temp &= 0xF0; /* Save bits 7:4 */
2551	temp |= (restore->ExtColorModeSelect & ~0xF0);
2552	break;
2553    case NM2090 :
2554    case NM2093 :
2555    case NM2097 :
2556    case NM2160 :
2557    case NM2200 :
2558    case NM2230 :
2559    case NM2360 :
2560    case NM2380 :
2561	temp &= 0x70; /* Save bits 6:4 */
2562	temp |= (restore->ExtColorModeSelect & ~0x70);
2563	break;
2564    }
2565    VGAwGR(0x90,temp);
2566
2567    /*
2568     * In some rare cases a lockup might occur if we don't delay
2569     * here. (Reported by Miles Lane)
2570     */
2571    xf86UDelay(200000);
2572    /*
2573     * Disable horizontal and vertical graphics and text expansions so
2574     * that vgaHWRestore works properly.
2575     */
2576    temp = VGArGR(0x25);
2577    temp &= 0x39;
2578    VGAwGR(0x25, temp);
2579
2580    /*
2581     * Sleep for 200ms to make sure that the two operations above have
2582     * had time to take effect.
2583     */
2584    xf86UDelay(200000);
2585    /*
2586     * This function handles restoring the generic VGA registers.  */
2587    vgaHWRestore(pScrn, VgaReg,
2588		 VGA_SR_MODE
2589		 | (restoreText ? (VGA_SR_FONTS | VGA_SR_CMAP) : 0));
2590
2591    VGAwGR(0x0E, restore->ExtCRTDispAddr);
2592    VGAwGR(0x0F, restore->ExtCRTOffset);
2593    temp = VGArGR(0x10);
2594    temp &= 0x0F; /* Save bits 3:0 */
2595    temp |= (restore->SysIfaceCntl1 & ~0x0F);
2596    VGAwGR(0x10, temp);
2597
2598    VGAwGR(0x11, restore->SysIfaceCntl2);
2599    VGAwGR(0x15, restore->SingleAddrPage);
2600    VGAwGR(0x16, restore->DualAddrPage);
2601
2602    temp = VGArGR(0x20);
2603    switch (nPtr->NeoChipset) {
2604    case NM2070 :
2605	temp &= 0xFC; /* Save bits 7:2 */
2606	temp |= (restore->PanelDispCntlReg1 & ~0xFC);
2607	break;
2608    case NM2090 :
2609    case NM2093 :
2610    case NM2097 :
2611    case NM2160 :
2612	temp &= 0xDC; /* Save bits 7:6,4:2 */
2613	temp |= (restore->PanelDispCntlReg1 & ~0xDC);
2614	break;
2615    case NM2200 :
2616    case NM2230 :
2617    case NM2360 :
2618    case NM2380 :
2619	temp &= 0x98; /* Save bits 7,4:3 */
2620	temp |= (restore->PanelDispCntlReg1 & ~0x98);
2621	break;
2622    }
2623    VGAwGR(0x20, temp);
2624
2625    temp = VGArGR(0x25);
2626    temp &= 0x38; /* Save bits 5:3 */
2627    temp |= (restore->PanelDispCntlReg2 & ~0x38);
2628    VGAwGR(0x25, temp);
2629
2630    if (nPtr->NeoChipset != NM2070) {
2631	temp = VGArGR(0x30);
2632	temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
2633	temp |= (restore->PanelDispCntlReg3 & ~0xEF);
2634	VGAwGR(0x30, temp);
2635    }
2636
2637    VGAwGR(0x28, restore->PanelVertCenterReg1);
2638    VGAwGR(0x29, restore->PanelVertCenterReg2);
2639    VGAwGR(0x2a, restore->PanelVertCenterReg3);
2640
2641    if (nPtr->NeoChipset != NM2070) {
2642	VGAwGR(0x32, restore->PanelVertCenterReg4);
2643	VGAwGR(0x33, restore->PanelHorizCenterReg1);
2644	VGAwGR(0x34, restore->PanelHorizCenterReg2);
2645	VGAwGR(0x35, restore->PanelHorizCenterReg3);
2646    }
2647
2648    if (nPtr->NeoChipset == NM2160) {
2649	VGAwGR(0x36, restore->PanelHorizCenterReg4);
2650    }
2651
2652    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2653	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2654        VGAwGR(0x36, restore->PanelHorizCenterReg4);
2655        VGAwGR(0x37, restore->PanelVertCenterReg5);
2656        VGAwGR(0x38, restore->PanelHorizCenterReg5);
2657    }
2658    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2659	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380)
2660	clock_hi = TRUE;
2661
2662    /* Program VCLK3 if needed. */
2663    if (restore->ProgramVCLK
2664	 && ((VGArGR(0x9B) != restore->VCLK3NumeratorLow)
2665	    || (VGArGR(0x9F) !=  restore->VCLK3Denominator)
2666	    || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
2667			     != (restore->VCLK3NumeratorHigh & ~0x0F))))) {
2668	VGAwGR(0x9B, restore->VCLK3NumeratorLow);
2669	if (clock_hi) {
2670	    temp = VGArGR(0x8F);
2671	    temp &= 0x0F; /* Save bits 3:0 */
2672	    temp |= (restore->VCLK3NumeratorHigh & ~0x0F);
2673	    VGAwGR(0x8F, temp);
2674	}
2675	VGAwGR(0x9F, restore->VCLK3Denominator);
2676    }
2677    if (restore->biosMode)
2678	VGAwCR(0x23,restore->biosMode);
2679
2680    if (restore->reg) {
2681	VGAwCR(0x23,restore->reg->CR[0x23]);
2682	VGAwCR(0x25,restore->reg->CR[0x25]);
2683	VGAwCR(0x2F,restore->reg->CR[0x2F]);
2684	for (i = 0x40; i <= 0x59; i++) {
2685	    VGAwCR(i, restore->reg->CR[i]);
2686	}
2687	for (i = 0x60; i <= 0x69; i++) {
2688	    VGAwCR(i, restore->reg->CR[i]);
2689	}
2690	for (i = 0x70; i <= NEO_EXT_CR_MAX; i++) {
2691	    VGAwCR(i, restore->reg->CR[i]);
2692	}
2693
2694	for (i = 0x0a; i <= 0x3f; i++) {
2695	    VGAwGR(i, restore->reg->GR[i]);
2696	}
2697	for (i = 0x90; i <= NEO_EXT_GR_MAX; i++) {
2698	    VGAwGR(i, restore->reg->GR[i]);
2699	}
2700    }
2701
2702    VGAwGR (0x93, 0xc0); /* Gives faster framebuffer writes */
2703
2704    /* Program vertical extension register */
2705    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
2706	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
2707	VGAwCR(0x70, restore->VerticalExt);
2708    }
2709
2710    vgaHWProtect(pScrn, FALSE);		/* Turn on screen */
2711}
2712
2713static Bool
2714neoModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
2715{
2716    NEOPtr nPtr = NEOPTR(pScrn);
2717    NEOACLPtr nAcl = NEOACLPTR(pScrn);
2718    int hoffset, voffset;
2719    vgaHWPtr hwp = VGAHWPTR(pScrn);
2720    NeoRegPtr NeoNew = &nPtr->NeoModeReg;
2721    vgaRegPtr NeoStd = &hwp->ModeReg;
2722    Bool noLcdStretch = nPtr->noLcdStretch;
2723    int clockMul = 1;
2724
2725    neoUnlock(pScrn);
2726
2727    /*
2728     * This will allocate the datastructure and initialize all of the
2729     * generic VGA registers.
2730     */
2731
2732    if (!vgaHWInit(pScrn, mode))
2733	return(FALSE);
2734
2735    /*
2736     * Several registers need to be corrected from the default values
2737     * assigned by vgaHWinit().
2738     */
2739    pScrn->vtSema = TRUE;
2740
2741    /*
2742     * The default value assigned by vgaHW.c is 0x41, but this does
2743     * not work for NeoMagic.
2744     */
2745    NeoStd->Attribute[16] = 0x01;
2746
2747    switch (pScrn->depth) { /*@!@*/
2748    case  8 :
2749	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 3;
2750	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 11;
2751	NeoNew->ExtColorModeSelect = 0x11;
2752	break;
2753    case 15 :
2754        NeoNew->ExtColorModeSelect = 0x12;
2755	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 2;
2756	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 10;
2757        break;
2758    case 16 :
2759        NeoNew->ExtColorModeSelect = 0x13;
2760	NeoStd->CRTC[0x13] = pScrn->displayWidth >> 2;
2761	NeoNew->ExtCRTOffset   = pScrn->displayWidth >> 10;
2762	break;
2763    case 24 :
2764	NeoStd->CRTC[0x13] = (pScrn->displayWidth * 3) >> 3;
2765	NeoNew->ExtCRTOffset   = (pScrn->displayWidth * 3) >> 11;
2766	NeoNew->ExtColorModeSelect = 0x14;
2767	break;
2768    default :
2769	break;
2770    }
2771
2772    NeoNew->ExtCRTDispAddr = 0x10;
2773
2774    /* Vertical Extension */
2775    NeoNew->VerticalExt = (((mode->CrtcVTotal -2) & 0x400) >> 10 )
2776      | (((mode->CrtcVDisplay -1) & 0x400) >> 9 )
2777        | (((mode->CrtcVSyncStart) & 0x400) >> 8 )
2778          | (((mode->CrtcVBlankStart - 1) & 0x400) >> 7 );
2779
2780    /* Fast write bursts on unless disabled. */
2781    if (nPtr->onPciBurst) {
2782	NeoNew->SysIfaceCntl1 = 0x30;
2783    } else {
2784	NeoNew->SysIfaceCntl1 = 0x00;
2785    }
2786
2787    /* If they are used, enable linear addressing and/or enable MMIO. */
2788    NeoNew->SysIfaceCntl2 = 0x00;
2789    if (!nPtr->noLinear)
2790	NeoNew->SysIfaceCntl2 |= 0x80;
2791    if (!nPtr->noMMIO)
2792	NeoNew->SysIfaceCntl2 |= 0x40;
2793
2794    /* Enable any user specified display devices. */
2795    NeoNew->PanelDispCntlReg1 = 0x00;
2796    if (nPtr->internDisp) {
2797	NeoNew->PanelDispCntlReg1 |= 0x02;
2798    }
2799    if (nPtr->externDisp) {
2800	NeoNew->PanelDispCntlReg1 |= 0x01;
2801    }
2802
2803#if 0
2804    /*
2805     * This was replaced: if no devices are specified take the
2806     * probed settings. If the probed settings are bogus fallback
2807     * to internal only.
2808     */
2809    /* If the user did not specify any display devices, then... */
2810    if (NeoNew->PanelDispCntlReg1 == 0x00) {
2811	/* Default to internal (i.e., LCD) only. */
2812	NeoNew->PanelDispCntlReg1 |= 0x02;
2813    }
2814#endif
2815    /* If we are using a fixed mode, then tell the chip we are. */
2816    switch (mode->HDisplay) {
2817    case 1280:
2818	NeoNew->PanelDispCntlReg1 |= 0x60;
2819        break;
2820    case 1024:
2821	NeoNew->PanelDispCntlReg1 |= 0x40;
2822        break;
2823    case 800:
2824	NeoNew->PanelDispCntlReg1 |= 0x20;
2825        break;
2826    case 640:
2827    default:
2828        break;
2829    }
2830
2831    /* Setup shadow register locking. */
2832    switch (NeoNew->PanelDispCntlReg1 & 0x03) {
2833    case 0x01 : /* External CRT only mode: */
2834	NeoNew->GeneralLockReg = 0x00;
2835	/* We need to program the VCLK for external display only mode. */
2836	NeoNew->ProgramVCLK = TRUE;
2837	break;
2838    case 0x02 : /* Internal LCD only mode: */
2839    case 0x03 : /* Simultaneous internal/external (LCD/CRT) mode: */
2840	NeoNew->GeneralLockReg = 0x01;
2841	/* Don't program the VCLK when using the LCD. */
2842	NeoNew->ProgramVCLK = FALSE;
2843	break;
2844    }
2845
2846    /*
2847     * If the screen is to be stretched, turn on stretching for the
2848     * various modes.
2849     *
2850     * OPTION_LCD_STRETCH means stretching should be turned off!
2851     */
2852    NeoNew->PanelDispCntlReg2 = 0x00;
2853    NeoNew->PanelDispCntlReg3 = 0x00;
2854    nAcl->NoCursorMode = FALSE;
2855
2856    if ((!noLcdStretch) &&
2857	(NeoNew->PanelDispCntlReg1 & 0x02)) {
2858	if (mode->HDisplay == nPtr->NeoPanelWidth) {
2859	    /*
2860	     * Don't disable the flag.  It will be needed if another mode
2861	     * is selected.
2862	     */
2863	    /*
2864	     * No stretching required when the requested display width
2865	     * equals the panel width.
2866	     */
2867	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Stretching disabled\n");
2868	        noLcdStretch = TRUE;
2869	} else {
2870
2871	    switch (mode->HDisplay) {
2872	    case  320 : /* Needs testing.  KEM -- 24 May 98 */
2873	    case  400 : /* Needs testing.  KEM -- 24 May 98 */
2874	    case  640 :
2875	    case  800 :
2876	    case 1024 :
2877		NeoNew->PanelDispCntlReg2 |= 0xC6;
2878		nAcl->NoCursorMode = TRUE;
2879		break;
2880	    default   :
2881		/* No stretching in these modes. */
2882		xf86DrvMsg(pScrn->scrnIndex,X_INFO,
2883			   "Stretching disabled not supported in this mode\n");
2884		noLcdStretch = TRUE;
2885		break;
2886	    }
2887	}
2888    } else if (mode->Flags & V_DBLSCAN) {
2889	nAcl->NoCursorMode = TRUE;
2890    }
2891
2892    /*
2893     * If the screen is to be centerd, turn on the centering for the
2894     * various modes.
2895     */
2896    NeoNew->PanelVertCenterReg1  = 0x00;
2897    NeoNew->PanelVertCenterReg2  = 0x00;
2898    NeoNew->PanelVertCenterReg3  = 0x00;
2899    NeoNew->PanelVertCenterReg4  = 0x00;
2900    NeoNew->PanelVertCenterReg5  = 0x00;
2901    NeoNew->PanelHorizCenterReg1 = 0x00;
2902    NeoNew->PanelHorizCenterReg2 = 0x00;
2903    NeoNew->PanelHorizCenterReg3 = 0x00;
2904    NeoNew->PanelHorizCenterReg4 = 0x00;
2905    NeoNew->PanelHorizCenterReg5 = 0x00;
2906
2907    if (nPtr->lcdCenter &&
2908	(NeoNew->PanelDispCntlReg1 & 0x02)) {
2909	Bool doCenter = FALSE;
2910
2911	hoffset = 0;
2912	voffset = 0;
2913	if (mode->HDisplay == nPtr->NeoPanelWidth) {
2914	    /*
2915	     * No centering required when the requested display width
2916	     * equals the panel width.
2917	     */
2918	} else {
2919	    NeoNew->PanelDispCntlReg3 |= 0x10;
2920	    if (noLcdStretch) {
2921		/* Calculate the horizontal offsets. */
2922		int HDisplay = mode->HDisplay
2923		    << ((mode->VDisplay < 480) ? 1 : 0);
2924		hoffset = ((nPtr->NeoPanelWidth - HDisplay) >> 4) - 1;
2925		if (mode->VDisplay < 480)
2926		    hoffset >>= 1;
2927		doCenter = TRUE;
2928	    } else {
2929		/* Stretched modes cannot be centered. */
2930		hoffset = 0;
2931	    }
2932	}
2933	if (mode->VDisplay == nPtr->NeoPanelHeight) {
2934	    /*
2935	     * No centering required when the requested display width
2936	     * equals the panel width.
2937	     */
2938	} else {
2939	    NeoNew->PanelDispCntlReg2 |= 0x01;
2940	    if (noLcdStretch) {
2941		/* Calculate the vertical offsets. */
2942		int VDisplay = mode->VDisplay
2943		    << ((mode->Flags & V_DBLSCAN) ? 1 : 0);
2944		voffset = ((nPtr->NeoPanelHeight - VDisplay) >> 1) - 2;
2945		doCenter = TRUE;
2946	    } else {
2947		/* Stretched modes cannot be centered. */
2948		voffset = 0;
2949	    }
2950	}
2951
2952	if (doCenter) {
2953	    switch (mode->HDisplay) {
2954	    case  320 : /* Needs testing.  KEM -- 24 May 98 */
2955  		NeoNew->PanelHorizCenterReg3 = hoffset;
2956		NeoNew->PanelVertCenterReg3  = voffset;
2957		break;
2958	    case  400 : /* Needs testing.  KEM -- 24 May 98 */
2959		NeoNew->PanelHorizCenterReg4 = hoffset;
2960		NeoNew->PanelVertCenterReg1  = voffset;
2961		break;
2962	    case  640 :
2963		NeoNew->PanelHorizCenterReg1 = hoffset;
2964		NeoNew->PanelVertCenterReg3  = voffset;
2965		break;
2966	    case  800 :
2967		NeoNew->PanelHorizCenterReg2 = hoffset;
2968		switch (mode->VDisplay) {
2969		case 600:
2970		    NeoNew->PanelVertCenterReg4  = voffset;
2971		    break;
2972		case 480:
2973		    /* Not sure if this is correct */
2974		    NeoNew->PanelVertCenterReg3  = voffset;
2975		    break;
2976		}
2977		break;
2978	    case 1024 :
2979		NeoNew->PanelHorizCenterReg5 = hoffset;
2980		NeoNew->PanelVertCenterReg5  = voffset;
2981		break;
2982	    case 1280 :
2983	    default   :
2984		/* No centering in these modes. */
2985		break;
2986	    }
2987	}
2988    }
2989
2990    if (!noLcdStretch &&
2991	(NeoNew->PanelDispCntlReg1 & 0x02))  {
2992	if (mode->HDisplay != nPtr->NeoPanelWidth)
2993	    nPtr->videoHZoom = (double)nPtr->NeoPanelWidth/mode->HDisplay;
2994	if (mode->VDisplay != nPtr->NeoPanelHeight)
2995	    nPtr->videoVZoom = (double)nPtr->NeoPanelHeight/mode->VDisplay;
2996    } else {
2997	nPtr->videoHZoom = 1.0;
2998	nPtr->videoVZoom = 1.0;
2999    }
3000    /* Do double scan */
3001    if (mode->VDisplay < 480) {
3002	NeoStd->Sequencer[1] |= 0x8;
3003	clockMul = 2;
3004    }
3005
3006    NeoNew->biosMode = neoFindMode(mode->HDisplay,mode->VDisplay,pScrn->depth);
3007
3008    /*
3009     * New->reg should be empty.  Just in
3010     * case it isn't, warn us and clear it anyway.
3011     */
3012    if (NeoNew->reg) {
3013	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3014		   "Non-NULL reg in NeoInit: reg=%p\n", (void *)NeoNew->reg);
3015	xfree(NeoNew->reg);
3016	NeoNew->reg = NULL;
3017    }
3018
3019    /*
3020     * Calculate the VCLK that most closely matches the requested dot
3021     * clock.
3022     */
3023    neoCalcVCLK(pScrn, mode->SynthClock*clockMul);
3024
3025    /* Since we program the clocks ourselves, always use VCLK3. */
3026    NeoStd->MiscOutReg |= 0x0C;
3027
3028    neoRestore(pScrn, NeoStd, NeoNew, FALSE);
3029
3030    return(TRUE);
3031}
3032
3033/*
3034 * neoCalcVCLK --
3035 *
3036 * Determine the closest clock frequency to the one requested.
3037 */
3038#define REF_FREQ 14.31818
3039#define MAX_N 127
3040#define MAX_D 31
3041#define MAX_F 1
3042
3043static void
3044neoCalcVCLK(ScrnInfoPtr pScrn, long freq)
3045{
3046    NEOPtr nPtr = NEOPTR(pScrn);
3047
3048    int n, d, f;
3049    double f_out;
3050    double f_diff;
3051    int n_best = 0, d_best = 1, f_best = 0;
3052    double f_best_diff = 999999.0;
3053    double f_target = freq/1000.0;
3054
3055    for (f = 0; f <= MAX_F; f++)
3056	for (n = 0; n <= MAX_N; n++)
3057	    for (d = 1; d <= MAX_D; d++) {
3058		f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
3059		f_diff = abs(f_out-f_target);
3060		if (f_diff < f_best_diff) {
3061		    f_best_diff = f_diff;
3062		    n_best = n;
3063		    d_best = d;
3064		    f_best = f;
3065		}
3066	    }
3067
3068    if (nPtr->NeoChipset == NM2200 || nPtr->NeoChipset == NM2230
3069	|| nPtr->NeoChipset == NM2360 || nPtr->NeoChipset == NM2380) {
3070        /* NOT_DONE:  We are trying the full range of the 2200 clock.
3071           We should be able to try n up to 2047 */
3072	nPtr->NeoModeReg.VCLK3NumeratorLow  = n_best;
3073	nPtr->NeoModeReg.VCLK3NumeratorHigh = (f_best << 7);
3074    }
3075    else {
3076	nPtr->NeoModeReg.VCLK3NumeratorLow  = n_best | (f_best << 7);
3077    }
3078    nPtr->NeoModeReg.VCLK3Denominator = d_best;
3079#ifdef DEBUG
3080    ErrorF("neoVCLK: f:%f NumLow=%i NumHi=%i Den=%i Df=%f\n",
3081	   f_target,
3082	   nPtr->NeoModeReg.VCLK3NumeratorLow,
3083	   nPtr->NeoModeReg.VCLK3NumeratorHigh,
3084	   nPtr->NeoModeReg.VCLK3Denominator,
3085	   f_best_diff);
3086#endif
3087}
3088
3089/*
3090 * NeoDisplayPowerManagementSet --
3091 *
3092 * Sets VESA Display Power Management Signaling (DPMS) Mode.
3093 */
3094static void
3095NeoDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
3096			     int flags)
3097{
3098    NEOPtr nPtr = NEOPTR(pScrn);
3099    vgaHWPtr hwp = VGAHWPTR(pScrn);
3100    unsigned char SEQ01 = 0;
3101    unsigned char LogicPowerMgmt = 0;
3102    unsigned char LCD_on = 0;
3103
3104    if (!pScrn->vtSema)
3105	return;
3106
3107    switch (PowerManagementMode) {
3108    case DPMSModeOn:
3109	/* Screen: On; HSync: On, VSync: On */
3110	SEQ01 = 0x00;
3111	LogicPowerMgmt = 0x00;
3112	if (nPtr->internDisp || ! nPtr->externDisp)
3113	    LCD_on = 0x02;
3114	else
3115	    LCD_on = 0x00;
3116	break;
3117    case DPMSModeStandby:
3118	/* Screen: Off; HSync: Off, VSync: On */
3119	SEQ01 = 0x20;
3120	LogicPowerMgmt = 0x10;
3121	LCD_on = 0x00;
3122	break;
3123    case DPMSModeSuspend:
3124	/* Screen: Off; HSync: On, VSync: Off */
3125	SEQ01 = 0x20;
3126	LogicPowerMgmt = 0x20;
3127	LCD_on = 0x00;
3128	break;
3129    case DPMSModeOff:
3130	/* Screen: Off; HSync: Off, VSync: Off */
3131	SEQ01 = 0x20;
3132	LogicPowerMgmt = 0x30;
3133	LCD_on = 0x00;
3134	break;
3135    }
3136
3137    /* Turn the screen on/off */
3138    SEQ01 |= VGArSR(0x01) & ~0x20;
3139    VGAwSR(0x01, SEQ01);
3140
3141    /* Turn the LCD on/off */
3142    LCD_on |= VGArGR(0x20) & ~0x02;
3143    VGAwGR(0x20, LCD_on);
3144
3145    /* Set the DPMS mode */
3146    LogicPowerMgmt |= 0x80;
3147    LogicPowerMgmt |= VGArGR(0x01) & ~0xF0;
3148    VGAwGR(0x01,LogicPowerMgmt);
3149}
3150
3151static unsigned int
3152neo_ddc1Read(ScrnInfoPtr pScrn)
3153{
3154    register vgaHWPtr hwp = VGAHWPTR(pScrn);
3155    register unsigned int tmp;
3156
3157    /* This needs to be investigated: we may have to swap this around */
3158    while (!(hwp->readST01(hwp)&0x8)) {};
3159    while (hwp->readST01(hwp)&0x8) {};
3160
3161    tmp = (VGArGR(0xA1) & 0x08);
3162
3163    return (tmp);
3164}
3165
3166static xf86MonPtr
3167neo_ddc1(int scrnIndex)
3168{
3169    vgaHWPtr hwp = VGAHWPTR(xf86Screens[scrnIndex]);
3170    unsigned int reg1, reg2, reg3;
3171    xf86MonPtr ret;
3172
3173    /* initialize chipset */
3174    reg1 = VGArCR(0x21);
3175    reg2 = VGArCR(0x1D);
3176    reg3 = VGArCR(0xA1);
3177    VGAwCR(0x21,0x00);
3178    VGAwCR(0x1D,0x01);  /* some Voodoo */
3179    VGAwGR(0xA1,0x2F);
3180    ret =  xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),neo_ddc1Read);
3181    /* undo initialization */
3182    VGAwCR(0x21,reg1);
3183    VGAwCR(0x1D,reg2);
3184    VGAwGR(0xA1,reg3);
3185    return ret;
3186}
3187
3188static Bool
3189neoDoDDC1(ScrnInfoPtr pScrn)
3190{
3191    Bool ret = FALSE;
3192    vgaHWPtr hwp = VGAHWPTR(pScrn);
3193
3194    VGAwGR(0x09,0x26);
3195    ret = xf86SetDDCproperties(pScrn,
3196				xf86PrintEDID(neo_ddc1(pScrn->scrnIndex)));
3197    VGAwGR(0x09,0x00);
3198
3199    return ret;
3200}
3201
3202static Bool
3203neoDoDDC2(ScrnInfoPtr pScrn)
3204{
3205    NEOPtr nPtr = NEOPTR(pScrn);
3206    vgaHWPtr hwp = VGAHWPTR(pScrn);
3207    Bool ret = FALSE;
3208
3209    VGAwGR(0x09,0x26);
3210    if (xf86LoadSubModule(pScrn, "i2c")) {
3211        xf86LoaderReqSymLists(i2cSymbols, NULL);
3212	if (neo_I2CInit(pScrn)) {
3213	    ret = xf86SetDDCproperties(pScrn,xf86PrintEDID(xf86DoEDID_DDC2(
3214					      pScrn->scrnIndex,nPtr->I2C)));
3215	}
3216    }
3217    VGAwGR(0x09,0x00);
3218
3219    return ret;
3220}
3221
3222static Bool
3223neoDoDDCVBE(ScrnInfoPtr pScrn)
3224{
3225    NEOPtr nPtr = NEOPTR(pScrn);
3226    vgaHWPtr hwp = VGAHWPTR(pScrn);
3227    vbeInfoPtr pVbe;
3228    Bool ret = FALSE;
3229
3230    VGAwGR(0x09,0x26);
3231    if (xf86LoadSubModule(pScrn, "vbe")) {
3232	xf86LoaderReqSymLists(vbeSymbols, NULL);
3233        if ((pVbe = VBEInit(NULL,nPtr->pEnt->index))) {
3234	  ret = xf86SetDDCproperties(
3235				     pScrn,xf86PrintEDID(vbeDoEDID(pVbe,NULL)));
3236	  vbeFree(pVbe);
3237	}
3238    }
3239    VGAwGR(0x09,0x00);
3240    return ret;
3241}
3242
3243static int
3244neoFindMode(int xres, int yres, int depth)
3245{
3246    int xres_s;
3247    int i, size;
3248    biosMode *mode;
3249
3250    switch (depth) {
3251    case 8:
3252	size = sizeof(bios8) / sizeof(biosMode);
3253	mode = bios8;
3254	break;
3255    case 15:
3256	size = sizeof(bios15) / sizeof(biosMode);
3257	mode = bios15;
3258	break;
3259    case 16:
3260	size = sizeof(bios16) / sizeof(biosMode);
3261	mode = bios16;
3262	break;
3263    case 24:
3264	size = sizeof(bios24) / sizeof(biosMode);
3265	mode = bios24;
3266	break;
3267    default:
3268	return 0;
3269    }
3270
3271    for (i = 0; i < size; i++) {
3272	if (xres <= mode[i].x_res) {
3273	    xres_s = mode[i].x_res;
3274	    for (; i < size; i++) {
3275		if (mode[i].x_res != xres_s)
3276		    return mode[i-1].mode;
3277		if (yres <= mode[i].y_res)
3278		    return mode[i].mode;
3279	    }
3280	}
3281    }
3282    return mode[size - 1].mode;
3283
3284}
3285
3286static void
3287neoProbeDDC(ScrnInfoPtr pScrn, int index)
3288{
3289    vbeInfoPtr pVbe;
3290
3291    if (xf86LoadSubModule(pScrn, "vbe")) {
3292        if ((pVbe = VBEInit(NULL,index))) {
3293	    ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
3294	    vbeFree(pVbe);
3295	}
3296    }
3297}
3298