apm_driver.c revision 17a48c7c
1/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/apm/apm_driver.c,v 1.65 2003/10/30 17:36:57 tsi Exp $ */
2
3#ifdef HAVE_CONFIG_H
4#include "config.h"
5#endif
6
7#include "apm.h"
8#include "xf86cmap.h"
9#include "shadowfb.h"
10#include "xf86Resources.h"
11#include "xf86int10.h"
12#include "xf86RAC.h"
13#include "vbe.h"
14
15#include "opaque.h"
16#define DPMS_SERVER
17#include <X11/extensions/dpms.h>
18
19#define APM_VERSION		4000
20#define APM_NAME		"APM"
21#define APM_DRIVER_NAME		"apm"
22#define APM_MAJOR_VERSION       1
23#define APM_MINOR_VERSION       1
24#define APM_PATCHLEVEL          1
25#ifndef PCI_CHIP_AT3D
26#define PCI_CHIP_AT3D	0x643D
27#endif
28
29/* bytes to save for text/font data */
30#define TEXT_AMOUNT 32768
31
32/* Mandatory functions */
33static const OptionInfoRec *	ApmAvailableOptions(int chipid, int busid);
34static void     ApmIdentify(int flags);
35static Bool     ApmProbe(DriverPtr drv, int flags);
36static Bool     ApmPreInit(ScrnInfoPtr pScrn, int flags);
37static Bool     ApmScreenInit(int Index, ScreenPtr pScreen, int argc,
38                                  char **argv);
39static Bool     ApmEnterVT(int scrnIndex, int flags);
40static void     ApmLeaveVT(int scrnIndex, int flags);
41static Bool     ApmCloseScreen(int scrnIndex, ScreenPtr pScreen);
42static void     ApmFreeScreen(int scrnIndex, int flags);
43static ModeStatus ApmValidMode(int scrnIndex, DisplayModePtr mode,
44                               Bool verbose, int flags);
45static Bool	ApmSaveScreen(ScreenPtr pScreen, int mode);
46static void	ApmUnlock(ApmPtr pApm);
47static void	ApmLock(ApmPtr pApm);
48static void	ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg,
49			    ApmRegPtr ApmReg);
50static void	ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices,
51				LOCO *colors, VisualPtr pVisual);
52static void	ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn,
53					     int PowerManagementMode,
54					     int flags);
55static void	ApmProbeDDC(ScrnInfoPtr pScrn, int index);
56
57
58int ApmPixmapIndex = -1;
59static unsigned long ApmGeneration = 0;
60
61_X_EXPORT DriverRec APM = {
62	APM_VERSION,
63	APM_DRIVER_NAME,
64	ApmIdentify,
65	ApmProbe,
66	ApmAvailableOptions,
67	NULL,
68	0
69};
70
71static SymTabRec ApmChipsets[] = {
72    { AP6422,	"AP6422"	},
73    { AT24,	"AT24"		},
74    { AT3D,	"AT3D"		},
75    { -1,	NULL		}
76};
77
78static PciChipsets ApmPciChipsets[] = {
79    { PCI_CHIP_AP6422,	PCI_CHIP_AP6422,	RES_SHARED_VGA },
80    { PCI_CHIP_AT24,	PCI_CHIP_AT24,		RES_SHARED_VGA },
81    { PCI_CHIP_AT3D,	PCI_CHIP_AT3D,		RES_SHARED_VGA },
82    { -1,			-1,		RES_UNDEFINED }
83};
84
85static IsaChipsets ApmIsaChipsets[] = {
86    { PCI_CHIP_AP6422,	RES_EXCLUSIVE_VGA},
87    {-1,		RES_UNDEFINED}
88};
89
90typedef enum {
91    OPTION_SET_MCLK,
92    OPTION_SW_CURSOR,
93    OPTION_HW_CURSOR,
94    OPTION_NOLINEAR,
95    OPTION_NOACCEL,
96    OPTION_SHADOW_FB,
97    OPTION_PCI_BURST,
98    OPTION_REMAP_DPMS_ON,
99    OPTION_REMAP_DPMS_STANDBY,
100    OPTION_REMAP_DPMS_SUSPEND,
101    OPTION_REMAP_DPMS_OFF,
102    OPTION_PCI_RETRY
103} ApmOpts;
104
105static const OptionInfoRec ApmOptions[] =
106{
107    {OPTION_SET_MCLK, "SetMclk", OPTV_FREQ,
108	{0}, FALSE},
109    {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN,
110	{0}, FALSE},
111    {OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN,
112	{0}, TRUE},
113    {OPTION_NOLINEAR, "NoLinear", OPTV_BOOLEAN,
114	{0}, FALSE},
115    {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN,
116	{0}, FALSE},
117    {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN,
118	{0}, FALSE},
119    {OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN,
120	{0}, FALSE},
121    {OPTION_REMAP_DPMS_ON, "Remap_DPMS_On", OPTV_ANYSTR,
122	{0}, FALSE},
123    {OPTION_REMAP_DPMS_STANDBY, "Remap_DPMS_Standby", OPTV_ANYSTR,
124	{0}, FALSE},
125    {OPTION_REMAP_DPMS_SUSPEND, "Remap_DPMS_Suspend", OPTV_ANYSTR,
126	{0}, FALSE},
127    {OPTION_REMAP_DPMS_OFF, "Remap_DPMS_Off", OPTV_ANYSTR,
128	{0}, FALSE},
129    {OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN,
130	{0}, FALSE},
131    {-1, NULL, OPTV_NONE,
132	{0}, FALSE}
133};
134
135/*
136 * List of symbols from other modules that this module references.  This
137 * list is used to tell the loader that it is OK for symbols here to be
138 * unresolved providing that it hasn't been told that they haven't been
139 * told that they are essential via a call to xf86LoaderReqSymbols() or
140 * xf86LoaderReqSymLists().  The purpose is this is to avoid warnings about
141 * unresolved symbols that are not required.
142 */
143
144static const char *vgahwSymbols[] = {
145    "vgaHWBlankScreen",
146    "vgaHWCursor",
147    "vgaHWFreeHWRec",
148    "vgaHWGetHWRec",
149    "vgaHWGetIOBase",
150    "vgaHWInit",
151    "vgaHWLock",
152    "vgaHWMapMem",
153    "vgaHWProtect",
154    "vgaHWRestore",
155    "vgaHWSave",
156    "vgaHWSetMmioFuncs",
157    "vgaHWUnlock",
158    NULL
159};
160
161static const char *xaaSymbols[] = {
162    "XAACreateInfoRec",
163    "XAACursorInfoRec",
164    "XAACursorInit",
165    "XAADestroyInfoRec",
166    "XAAGlyphScanlineFuncLSBFirst",
167    "XAAInit",
168    "XAAReverseBitOrder",
169    "XAAStippleScanlineFuncMSBFirst",
170    NULL
171};
172
173static const char *ramdacSymbols[] = {
174    "xf86CreateCursorInfoRec",
175    "xf86DestroyCursorInfoRec",
176    "xf86InitCursor",
177    NULL
178};
179
180#ifdef XFree86LOADER
181static const char *vbeSymbols[] = {
182    "VBEInit",
183    "vbeDoEDID",
184    "vbeFree",
185    NULL
186};
187#endif
188
189static const char *ddcSymbols[] = {
190    "xf86DoEDID_DDC1",
191    "xf86DoEDID_DDC2",
192    "xf86PrintEDID",
193    NULL
194};
195
196static const char *i2cSymbols[] = {
197    "xf86CreateI2CBusRec",
198    "xf86I2CBusInit",
199    NULL
200};
201
202static const char *shadowSymbols[] = {
203    "ShadowFBInit",
204    NULL
205};
206
207#ifdef XFree86LOADER
208static const char *miscfbSymbols[] = {
209    "xf1bppScreenInit",
210    "xf4bppScreenInit",
211    NULL
212};
213#endif
214
215static const char *fbSymbols[] = {
216    "fbPictureInit",
217    "fbScreenInit",
218    NULL
219};
220
221static const char *int10Symbols[] = {
222    "xf86Free10",
223    "xf86InitInt10",
224    NULL
225};
226
227#ifdef XFree86LOADER
228
229static XF86ModuleVersionInfo apmVersRec = {
230    "apm",
231    MODULEVENDORSTRING,
232    MODINFOSTRING1,
233    MODINFOSTRING2,
234    XORG_VERSION_CURRENT,
235    APM_MAJOR_VERSION, APM_MINOR_VERSION, APM_PATCHLEVEL,
236    ABI_CLASS_VIDEODRV,			/* This is a video driver */
237    ABI_VIDEODRV_VERSION,
238    MOD_CLASS_VIDEODRV,
239    {0,0,0,0}
240};
241
242static MODULESETUPPROTO(apmSetup);
243
244/*
245 * This is the module init data.
246 * Its name has to be the driver name followed by ModuleData.
247 */
248_X_EXPORT XF86ModuleData apmModuleData = { &apmVersRec, apmSetup, NULL };
249
250static pointer
251apmSetup(pointer module, pointer opts, int *errmaj, int *errmain)
252{
253    static Bool setupDone = FALSE;
254
255    if (!setupDone) {
256	setupDone = TRUE;
257	xf86AddDriver(&APM, module, 0);
258
259	LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols,
260			  miscfbSymbols, ramdacSymbols, vbeSymbols,
261			  ddcSymbols, i2cSymbols, shadowSymbols,
262			  int10Symbols, NULL);
263
264	return (pointer)1;
265    }
266    else {
267	if (errmaj) *errmaj = LDR_ONCEONLY;
268	return NULL;
269    }
270}
271#endif
272
273static Bool
274ApmGetRec(ScrnInfoPtr pScrn)
275{
276    if (pScrn->driverPrivate)
277	return TRUE;
278    pScrn->driverPrivate = xnfcalloc(sizeof(ApmRec), 1);
279    /* pScrn->driverPrivate != NULL at this point */
280
281    return TRUE;
282}
283
284static void
285ApmFreeRec(ScrnInfoPtr pScrn)
286{
287    if (pScrn->driverPrivate) {
288	xfree(pScrn->driverPrivate);
289	pScrn->driverPrivate = NULL;
290    }
291}
292
293
294/* unlock Alliance registers */
295static void
296ApmUnlock(ApmPtr pApm)
297{
298    if (pApm->Chipset >= AT3D && !pApm->noLinear)
299	ApmWriteSeq(0x10, 0x12);
300    else
301	wrinx(pApm->xport, 0x10, 0x12);
302}
303
304/* lock Alliance registers */
305static void
306ApmLock(ApmPtr pApm)
307{
308    if (pApm->Chipset >= AT3D && !pApm->noLinear)
309	ApmWriteSeq(0x10, pApm->savedSR10 ? 0 : 0x12);
310    else
311	wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12);
312}
313
314static void
315ApmIdentify(int flags)
316{
317    xf86PrintChipsets(APM_NAME, "driver for the Alliance chipsets",
318		      ApmChipsets);
319}
320
321static const OptionInfoRec *
322ApmAvailableOptions(int chipid, int busid)
323{
324    return ApmOptions;
325}
326
327static int
328ApmFindIsaDevice(GDevPtr dev)
329{
330    char	save = rdinx(0x3C4, 0x10);
331    int		i;
332    int		apmChip = -1;
333
334    /*
335     * Start by probing the VGA chipset.
336     */
337    outw(0x3C4, 0x1210);
338    if (rdinx(0x3C4, 0x11) == 'P' && rdinx(0x3C4, 0x12) == 'r' &&
339	rdinx(0x3C4, 0x13) == 'o') {
340	char	id_ap6420[] = "6420";
341	char	id_ap6422[] = "6422";
342	char	id_at24[]   = "6424";
343	char	id_at3d[]   = "AT3D";
344	char	idstring[]  = "    ";
345
346	/*
347	 * Must be an Alliance !!!
348	 */
349	for (i = 0; i < 4; i++)
350	    idstring[i] = rdinx(0x3C4, 0x14 + i);
351	if (!memcmp(id_ap6420, idstring, 4) ||
352	    !memcmp(id_ap6422, idstring, 4))
353	    apmChip = AP6422;
354	else if (!memcmp(id_at24, idstring, 4))
355	    apmChip = AT24;
356	else if (!memcmp(id_at3d, idstring, 4))
357	    apmChip = AT3D;
358	if (apmChip >= 0) {
359	    int	apm_xbase;
360
361	    apm_xbase = (rdinx(0x3C4, 0x1F) << 8) | rdinx(0x3C4, 0x1E);
362
363	    if (!(wrinx(0x3C4, 0x1D, 0xCA >> 2), inb(apm_xbase + 2))) {
364		/*
365		 * TODO Not PCI
366		 */
367	    }
368
369	}
370    }
371    wrinx(0x3C4, 0x10, save);
372
373    return apmChip;
374}
375
376static void
377ApmAssignFPtr(ScrnInfoPtr pScrn)
378{
379    pScrn->driverVersion	= APM_VERSION;
380    pScrn->driverName		= APM_DRIVER_NAME;
381    pScrn->name			= APM_NAME;
382    pScrn->Probe		= ApmProbe;
383    pScrn->PreInit		= ApmPreInit;
384    pScrn->ScreenInit		= ApmScreenInit;
385    pScrn->SwitchMode		= ApmSwitchMode;
386    pScrn->AdjustFrame		= ApmAdjustFrame;
387    pScrn->EnterVT		= ApmEnterVT;
388    pScrn->LeaveVT		= ApmLeaveVT;
389    pScrn->FreeScreen		= ApmFreeScreen;
390    pScrn->ValidMode		= ApmValidMode;
391}
392
393static Bool
394ApmProbe(DriverPtr drv, int flags)
395{
396    int			numDevSections, numUsed, i;
397    GDevPtr		*DevSections;
398    int			*usedChips;
399    int			foundScreen = FALSE;
400
401    /*
402     * Check if there is a chipset override in the config file
403     */
404    if ((numDevSections = xf86MatchDevice(APM_DRIVER_NAME,
405					   &DevSections)) <= 0)
406	return FALSE;
407
408    /*
409     * We need to probe the hardware first. We then need to see how this
410     * fits in with what is given in the config file, and allow the config
411     * file info to override any contradictions.
412     */
413
414    if (xf86GetPciVideoInfo() == NULL) {
415	return FALSE;
416    }
417    numUsed = xf86MatchPciInstances(APM_NAME, PCI_VENDOR_ALLIANCE,
418		    ApmChipsets, ApmPciChipsets, DevSections, numDevSections,
419		    drv, &usedChips);
420
421    if (numUsed > 0) {
422	if (flags & PROBE_DETECT)
423	    foundScreen = TRUE;
424	else for (i = 0; i < numUsed; i++) {
425	    ScrnInfoPtr	pScrn;
426
427	    /*
428	     * Allocate a ScrnInfoRec and claim the slot
429	     */
430	    pScrn = NULL;
431	    if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
432						   ApmPciChipsets, NULL,
433						   NULL,NULL,NULL,NULL))){
434
435		/*
436		 * Fill in what we can of the ScrnInfoRec
437		 */
438		ApmAssignFPtr(pScrn);
439		foundScreen = TRUE;
440	    }
441	}
442    }
443
444    /* Check for non-PCI cards */
445    numUsed = xf86MatchIsaInstances(APM_NAME, ApmChipsets,
446			ApmIsaChipsets, drv, ApmFindIsaDevice, DevSections,
447			numDevSections, &usedChips);
448    if (numUsed > 0) {
449	if (flags & PROBE_DETECT)
450	    foundScreen = TRUE;
451	else for (i = 0; i < numUsed; i++) {
452	    ScrnInfoPtr pScrn = NULL;
453	    if ((pScrn = xf86ConfigIsaEntity(pScrn, 0, usedChips[i],
454					     ApmIsaChipsets, NULL, NULL, NULL,
455					     NULL, NULL))) {
456	    /*
457	     * Fill in what we can of the ScrnInfoRec
458	     */
459	    ApmAssignFPtr(pScrn);
460	    foundScreen = TRUE;
461	    }
462	}
463    }
464    xfree(DevSections);
465    return foundScreen;
466}
467
468/*
469 * GetAccelPitchValues -
470 *
471 * This function returns a list of display width (pitch) values that can
472 * be used in accelerated mode.
473 */
474static int *
475GetAccelPitchValues(ScrnInfoPtr pScrn)
476{
477    int *linePitches = NULL;
478    int linep[] = {640, 800, 1024, 1152, 1280, 0};
479
480    if (sizeof linep > 0) {
481	linePitches = (int *)xnfalloc(sizeof linep);
482	memcpy(linePitches, linep, sizeof linep);
483    }
484
485    return linePitches;
486}
487
488static unsigned int
489ddc1Read(ScrnInfoPtr pScrn)
490{
491    APMDECL(pScrn);
492    unsigned char	tmp;
493
494    tmp = RDXB_IOP(0xD0);
495    WRXB_IOP(0xD0, tmp & 0x07);
496    while (STATUS_IOP() & 0x800);
497    while (!(STATUS_IOP() & 0x800));
498    return (STATUS_IOP() & STATUS_SDA) != 0;
499}
500
501static void
502ApmProbeDDC(ScrnInfoPtr pScrn, int index)
503{
504    vbeInfoPtr pVbe;
505
506    if (xf86LoadSubModule(pScrn, "vbe")) {
507        pVbe = VBEInit(NULL, index);
508        ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
509	vbeFree(pVbe);
510    }
511}
512
513static Bool
514ApmPreInit(ScrnInfoPtr pScrn, int flags)
515{
516    APMDECL(pScrn);
517    EntityInfoPtr	pEnt;
518    vgaHWPtr		hwp;
519    MessageType		from;
520    char		*mod = NULL, *req = NULL, *s;
521    ClockRangePtr	clockRanges;
522    int			i;
523    xf86MonPtr		MonInfo = NULL;
524    double		real;
525
526    /*
527     * Note: This function is only called once at server startup, and
528     * not at the start of each server generation.  This means that
529     * only things that are persistent across server generations can
530     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
531     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
532     * are too, and should be used for data that must persist across
533     * server generations.
534     *
535     * Per-generation data should be allocated with
536     * AllocateScreenPrivateIndex() from the ScreenInit() function.
537     */
538
539    /* Check the number of entities, and fail if it isn't one. */
540    if (pScrn->numEntities != 1)
541	return FALSE;
542
543    /* Allocate the ApmRec driverPrivate */
544    if (!ApmGetRec(pScrn)) {
545	return FALSE;
546    }
547    pApm = APMPTR(pScrn);
548
549    /* Get the entity */
550    pEnt = pApm->pEnt	= xf86GetEntityInfo(pScrn->entityList[0]);
551    if (pEnt->location.type == BUS_PCI) {
552	pApm->PciInfo	= xf86GetPciInfoForEntity(pEnt->index);
553	pApm->PciTag	= pciTag(pApm->PciInfo->bus, pApm->PciInfo->device,
554				 pApm->PciInfo->func);
555    }
556    else {
557	pApm->PciInfo	= NULL;
558	pApm->PciTag	= 0;
559    }
560
561    if (flags & PROBE_DETECT) {
562        ApmProbeDDC(pScrn, pEnt->index);
563        return TRUE;
564    }
565
566    /* The vgahw module should be allocated here when needed */
567    if (!xf86LoadSubModule(pScrn, "vgahw"))
568	return FALSE;
569
570    xf86LoaderReqSymLists(vgahwSymbols, NULL);
571
572    /*
573     * Allocate a vgaHWRec
574     */
575    if (!vgaHWGetHWRec(pScrn))
576	return FALSE;
577
578    hwp = VGAHWPTR(pScrn);
579    vgaHWGetIOBase(hwp);
580    pApm->iobase = hwp->PIOOffset;
581    pApm->xport = hwp->PIOOffset + 0x3C4;
582
583    /* Set pScrn->monitor */
584    pScrn->monitor = pScrn->confScreen->monitor;
585
586    /* XXX: Access funcs */
587    /*
588     * The first thing we should figure out is the depth, bpp, etc.
589     */
590    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb | Support32bppFb)) {
591	return FALSE;
592    } else {
593	/* Check that the returned depth is one we support */
594	switch (pScrn->depth) {
595	case 4:
596	case 8:
597	case 15:
598	case 16:
599	case 24:
600	    /* OK */
601	    break;
602	default:
603	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
604		       "Given depth (%d) is not supported by this driver\n",
605		       pScrn->depth);
606	    return FALSE;
607	}
608    }
609    xf86PrintDepthBpp(pScrn);
610
611    /*
612     * This must happen after pScrn->display has been set because
613     * xf86SetWeight references it.
614     */
615    if (pScrn->depth > 8) {
616	/* The defaults are OK for us */
617	rgb zeros = {0, 0, 0};
618
619	if (!xf86SetWeight(pScrn, zeros, zeros)) {
620	    return FALSE;
621	} else {
622	    /* XXX check that weight returned is supported */
623            ;
624        }
625    }
626
627    if (!xf86SetDefaultVisual(pScrn, -1)) {
628	return FALSE;
629    } else {
630	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
631	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
632		       " (%s) is not supported at depth %d\n",
633		       xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
634	    return FALSE;
635	}
636    }
637
638    /* We use a programmable clock */
639    pScrn->progClock = TRUE;
640
641    /* Collect all of the relevant option flags (fill in pScrn->options) */
642    xf86CollectOptions(pScrn, NULL);
643
644    /* Process the options */
645    if (!(pApm->Options = xalloc(sizeof(ApmOptions))))
646	return FALSE;
647    memcpy(pApm->Options, ApmOptions, sizeof(ApmOptions));
648    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pApm->Options);
649
650    pApm->scrnIndex = pScrn->scrnIndex;
651    /* Set the bits per RGB for 8bpp mode */
652    if (pScrn->depth > 1 && pScrn->depth <= 8) {
653	/* Default to 8 */
654	pScrn->rgbBits = 8;
655    }
656    if (xf86ReturnOptValBool(pApm->Options, OPTION_NOLINEAR, FALSE)) {
657	pApm->noLinear = TRUE;
658	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "No linear framebuffer\n");
659    }
660    from = X_DEFAULT;
661    pApm->hwCursor = FALSE;
662    if (xf86GetOptValBool(pApm->Options, OPTION_HW_CURSOR, &pApm->hwCursor))
663	from = X_CONFIG;
664    if (pApm->noLinear ||
665	xf86ReturnOptValBool(pApm->Options, OPTION_SW_CURSOR, FALSE)) {
666	from = X_CONFIG;
667	pApm->hwCursor = FALSE;
668    }
669    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
670		pApm->hwCursor ? "HW" : "SW");
671    from = X_DEFAULT;
672    if (pScrn->bitsPerPixel < 8)
673	pApm->NoAccel = TRUE;
674    if (xf86ReturnOptValBool(pApm->Options, OPTION_NOACCEL, FALSE)) {
675	from = X_CONFIG;
676	pApm->NoAccel = TRUE;
677    }
678    if (pApm->NoAccel)
679	xf86DrvMsg(pScrn->scrnIndex, from, "Acceleration disabled\n");
680    if (xf86GetOptValFreq(pApm->Options, OPTION_SET_MCLK, OPTUNITS_MHZ, &real)) {
681	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "MCLK used is %.1f MHz\n", real);
682	pApm->MemClk = (int)(real * 1000.0);
683    }
684    if (xf86ReturnOptValBool(pApm->Options, OPTION_SHADOW_FB, FALSE)) {
685	pApm->ShadowFB = TRUE;
686	pApm->NoAccel = TRUE;
687	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
688		"Using \"Shadow Framebuffer\" - acceleration disabled\n");
689    }
690    if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_RETRY, FALSE)) {
691	if (xf86ReturnOptValBool(pApm->Options, OPTION_PCI_BURST, FALSE)) {
692	  pApm->UsePCIRetry = TRUE;
693	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n");
694	}
695	else
696	  xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option requires pci_burst \"on\".\n");
697    }
698    pApm->DPMSMask[DPMSModeOn]		= DPMSModeOn;
699    pApm->DPMSMask[DPMSModeStandby]	= DPMSModeStandby;
700    pApm->DPMSMask[DPMSModeSuspend]	= DPMSModeSuspend;
701    pApm->DPMSMask[DPMSModeOff]		= DPMSModeOff;
702    if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_ON))) {
703	if (!strcmp(s, "on"))
704	    pApm->DPMSMask[DPMSModeOn] = DPMSModeOn;
705	else if (!strcmp(s, "standby"))
706	    pApm->DPMSMask[DPMSModeOn] = DPMSModeStandby;
707	else if (!strcmp(s, "suspend"))
708	    pApm->DPMSMask[DPMSModeOn] = DPMSModeSuspend;
709	else if (!strcmp(s, "off"))
710	    pApm->DPMSMask[DPMSModeOn] = DPMSModeOff;
711	else if (s[0] >= '0' && s[0] <= '9') {
712	    pApm->DPMSMask[DPMSModeOn] = strtol(s, NULL, 0);
713	    if (pApm->DPMSMask[DPMSModeOn] > (sizeof pApm->DPMSMask)-1)
714		pApm->DPMSMask[DPMSModeOn] = (sizeof pApm->DPMSMask) - 1;
715	}
716    }
717    if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_STANDBY))) {
718	if (!strcmp(s, "on"))
719	    pApm->DPMSMask[DPMSModeStandby] = DPMSModeOn;
720	else if (!strcmp(s, "standby"))
721	    pApm->DPMSMask[DPMSModeStandby] = DPMSModeStandby;
722	else if (!strcmp(s, "suspend"))
723	    pApm->DPMSMask[DPMSModeStandby] = DPMSModeSuspend;
724	else if (!strcmp(s, "off"))
725	    pApm->DPMSMask[DPMSModeStandby] = DPMSModeOff;
726	else if (s[0] >= '0' && s[0] <= '9') {
727	    pApm->DPMSMask[DPMSModeStandby] = strtol(s, NULL, 0);
728	    if (pApm->DPMSMask[DPMSModeStandby] > (sizeof pApm->DPMSMask)-1)
729		pApm->DPMSMask[DPMSModeStandby] = (sizeof pApm->DPMSMask) - 1;
730	}
731    }
732    if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_SUSPEND))) {
733	if (!strcmp(s, "on"))
734	    pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOn;
735	else if (!strcmp(s, "standby"))
736	    pApm->DPMSMask[DPMSModeSuspend] = DPMSModeStandby;
737	else if (!strcmp(s, "suspend"))
738	    pApm->DPMSMask[DPMSModeSuspend] = DPMSModeSuspend;
739	else if (!strcmp(s, "off"))
740	    pApm->DPMSMask[DPMSModeSuspend] = DPMSModeOff;
741	else if (s[0] >= '0' && s[0] <= '9') {
742	    pApm->DPMSMask[DPMSModeSuspend] = strtol(s, NULL, 0);
743	    if (pApm->DPMSMask[DPMSModeSuspend] > (sizeof pApm->DPMSMask)-1)
744		pApm->DPMSMask[DPMSModeSuspend] = (sizeof pApm->DPMSMask) - 1;
745	}
746    }
747    if ((s = xf86GetOptValString(pApm->Options, OPTION_REMAP_DPMS_OFF))) {
748	if (!strcmp(s, "on"))
749	    pApm->DPMSMask[DPMSModeOff] = DPMSModeOn;
750	else if (!strcmp(s, "standby"))
751	    pApm->DPMSMask[DPMSModeOff] = DPMSModeStandby;
752	else if (!strcmp(s, "suspend"))
753	    pApm->DPMSMask[DPMSModeOff] = DPMSModeSuspend;
754	else if (!strcmp(s, "off"))
755	    pApm->DPMSMask[DPMSModeOff] = DPMSModeOff;
756	else if (s[0] >= '0' && s[0] <= '9') {
757	    pApm->DPMSMask[DPMSModeOff] = strtol(s, NULL, 0);
758	    if (pApm->DPMSMask[DPMSModeOff] > (sizeof pApm->DPMSMask)-1)
759		pApm->DPMSMask[DPMSModeOff] = (sizeof pApm->DPMSMask) - 1;
760	}
761    }
762
763    /*
764     * Set the Chipset and ChipRev, allowing config file entries to
765     * override.
766     */
767    if (pEnt->device->chipset && *pEnt->device->chipset) {
768	pScrn->chipset = pEnt->device->chipset;
769        pApm->Chipset = xf86StringToToken(ApmChipsets, pScrn->chipset);
770        from = X_CONFIG;
771    } else if (pEnt->device->chipID >= 0) {
772	pApm->Chipset = pEnt->device->chipID;
773	pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset);
774
775	from = X_CONFIG;
776	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
777		   pApm->Chipset);
778    } else {
779	from = X_PROBED;
780	if (pApm->PciInfo)
781	    pApm->Chipset = pApm->PciInfo->chipType;
782	else
783	    pApm->Chipset = pEnt->chipset;
784	pScrn->chipset = (char *)xf86TokenToString(ApmChipsets, pApm->Chipset);
785    }
786    if (pScrn->bitsPerPixel == 24 && pApm->Chipset < AT24) {
787	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
788		   "Given depth (%d) is not supported by this driver\n",
789		   pScrn->depth);
790	return FALSE;
791    }
792    if (pEnt->device->chipRev >= 0) {
793	pApm->ChipRev = pEnt->device->chipRev;
794	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
795		   pApm->ChipRev);
796    } else if (pApm->PciInfo) {
797	pApm->ChipRev = pApm->PciInfo->chipRev;
798    }
799
800    /*
801     * This shouldn't happen because such problems should be caught in
802     * ApmProbe(), but check it just in case.
803     */
804    if (pScrn->chipset == NULL) {
805	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
806		   "ChipID 0x%04X is not recognised\n", pApm->Chipset);
807	return FALSE;
808    }
809    if (pApm->Chipset < 0) {
810	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
811		   "Chipset \"%s\" is not recognised\n", pScrn->chipset);
812	return FALSE;
813    }
814
815    xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
816
817    if (pEnt->device->MemBase != 0) {
818	pApm->LinAddress = pEnt->device->MemBase;
819	from = X_CONFIG;
820    } else if (pApm->PciInfo) {
821	pApm->LinAddress = pApm->PciInfo->memBase[0] & 0xFF800000;
822	from = X_PROBED;
823    } else {
824	/*
825	 * VESA local bus.
826	 * Pray that 2048MB works.
827	 */
828	pApm->LinAddress = 0x80000000;
829    }
830
831    xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
832	       (unsigned long)pApm->LinAddress);
833
834    if (xf86LoadSubModule(pScrn, "ddc")) {
835	xf86LoaderReqSymLists(ddcSymbols, NULL);
836	if (xf86LoadSubModule(pScrn, "i2c")) {
837	    xf86LoaderReqSymLists(i2cSymbols, NULL);
838	    pApm->I2C = TRUE;
839	}
840    }
841
842    if (pApm->noLinear) {
843	/*
844	 * TODO not AT3D.
845	 * XXX ICI XXX
846	 */
847	pApm->LinMapSize      =  4 * 1024 * 1024 /* 0x10000 */;
848	pApm->FbMapSize       =  4 * 1024 * 1024 /* 0x10000 */;
849	if (pApm->Chipset >= AT3D)
850	    pApm->LinAddress +=  8 * 1024 * 1024 /* 0xA0000 */;
851    }
852    else {
853	if (pApm->Chipset >= AT3D)
854	    pApm->LinMapSize  = 16 * 1024 * 1024;
855	else
856	    pApm->LinMapSize  =  6 * 1024 * 1024;
857	pApm->FbMapSize   =  4 * 1024 * 1024;
858    }
859
860    if (xf86LoadSubModule(pScrn, "int10")) {
861	void	*ptr;
862
863	xf86LoaderReqSymLists(int10Symbols, NULL);
864	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
865	ptr = xf86InitInt10(pEnt->index);
866	if (ptr)
867	    xf86FreeInt10(ptr);
868    }
869
870    xf86RegisterResources(pEnt->index, NULL, ResNone);
871    xf86SetOperatingState(resVga, pEnt->index, ResDisableOpr);
872    pScrn->racMemFlags = 0;	/* For noLinear, access to 0xA0000 */
873    if (pApm->VGAMap)
874	pScrn->racIoFlags = 0;
875    else
876	pScrn->racIoFlags = RAC_COLORMAP | RAC_VIEWPORT;
877
878    if (pEnt->device->videoRam != 0) {
879	pScrn->videoRam = pEnt->device->videoRam;
880	from = X_CONFIG;
881    } else if (!pApm->noLinear && pApm->Chipset >= AT3D) {
882	unsigned char		d9, db, uc;
883	/*unsigned long		save;*/
884	volatile unsigned char	*LinMap;
885
886	LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
887				     pApm->PciTag, pApm->LinAddress,
888				     pApm->LinMapSize);
889	/*save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG);
890	pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_MEM_ENABLE);*/
891	d9 = LinMap[0xFFECD9];
892	db = LinMap[0xFFECDB];
893	LinMap[0xFFECDB] = (db & 0xF4) | 0x0A;
894	LinMap[0xFFECD9] = (d9 & 0xCF) | 0x20;
895	LinMap[0xFFF3C4] = 0x1C;
896	uc = LinMap[0xFFF3C5];
897	LinMap[0xFFF3C5] = 0x3F;
898	LinMap[0xFFF3C4] = 0x20;
899	pScrn->videoRam = LinMap[0xFFF3C5] * 64;
900	LinMap[0xFFF3C4] = 0x10;
901	pApm->savedSR10 = LinMap[0xFFF3C5];
902	LinMap[0xFFF3C4] = 0x1E;
903	pApm->xbase  = LinMap[0xFFF3C5];
904	LinMap[0xFFF3C4] = 0x1F;
905	pApm->xbase |= LinMap[0xFFF3C5] << 8;
906	LinMap[0xFFF3C4] = 0x1C;
907	LinMap[0xFFF3C5] = uc;
908	LinMap[0xFFECDB] = db;
909	LinMap[0xFFECD9] = d9;
910	/*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/
911	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)LinMap, pApm->LinMapSize);
912	from = X_PROBED;
913    }
914    else {
915	/*unsigned long		save;
916
917	save = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG);
918	pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save | PCI_CMD_IO_ENABLE);*/
919	pApm->savedSR10 = rdinx(pApm->xport, 0x10);
920	wrinx(pApm->xport, 0x10, 0x12);
921	pScrn->videoRam = rdinx(pApm->xport, 0x20) * 64;
922	pApm->xbase = rdinx(pApm->xport, 0x1F) << 8;
923	pApm->xbase |= rdinx(pApm->xport, 0x1E);
924	pApm->xbase += pApm->iobase;
925	wrinx(pApm->xport, 0x10, pApm->savedSR10 ? 0 : 0x12);
926	/*pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, save);*/
927	from = X_PROBED;
928    }
929    if (pApm->Chipset < AT3D && pScrn->videoRam >= 4096)
930	pScrn->videoRam -= 32;
931
932    xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte\n",
933               pScrn->videoRam);
934
935    if (!xf86IsPc98()) {
936	hwp->MapSize = 0x10000;
937	vgaHWMapMem(pScrn);
938	if (pApm->I2C) {
939	    if (!ApmI2CInit(pScrn)) {
940		xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"I2C initialization failed\n");
941	    }
942	    else {
943		MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex,pApm->I2CPtr);
944	    }
945	}
946	if (0 && !MonInfo)
947	    MonInfo = xf86DoEDID_DDC1(pScrn->scrnIndex,vgaHWddc1SetSpeed,ddc1Read);
948	if (MonInfo)
949	    xf86PrintEDID(MonInfo);
950	pScrn->monitor->DDC = MonInfo;
951    }
952
953    /* The gamma fields must be initialised when using the new cmap code */
954    if (pScrn->depth > 1) {
955	Gamma zeros = {0.0, 0.0, 0.0};
956
957	if (!xf86SetGamma(pScrn, zeros)) {
958	    return FALSE;
959	}
960    }
961
962    pApm->MinClock = 23125;
963    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT, "Min pixel clock set to %d MHz\n",
964	       pApm->MinClock / 1000);
965
966    /*
967     * If the user has specified ramdac speed in the XF86Config
968     * file, we respect that setting.
969     */
970    from = X_DEFAULT;
971    if (pEnt->device->dacSpeeds[0]) {
972	int speed = 0;
973
974	switch (pScrn->bitsPerPixel) {
975	case 4:
976	case 8:
977	   speed = pEnt->device->dacSpeeds[DAC_BPP8];
978	   break;
979	case 16:
980	   speed = pEnt->device->dacSpeeds[DAC_BPP16];
981	   break;
982	case 24:
983	   speed = pEnt->device->dacSpeeds[DAC_BPP24];
984	   break;
985	case 32:
986	   speed = pEnt->device->dacSpeeds[DAC_BPP32];
987	   break;
988	}
989	if (speed == 0)
990	    pApm->MaxClock = pEnt->device->dacSpeeds[0];
991	else
992	    pApm->MaxClock = speed;
993	from = X_CONFIG;
994    } else {
995	switch(pApm->Chipset)
996	{
997	  /* These values come from the Manual for AT24 and AT3D
998	     in the overview of various modes. I've taken the largest
999	     number for the different modes. Alliance wouldn't
1000	     tell me what the maximum frequency was, so...
1001	   */
1002	  case AT24:
1003	       switch(pScrn->bitsPerPixel)
1004	       {
1005		 case 4:
1006		 case 8:
1007		      pApm->MaxClock = 160000;
1008		      break;
1009		 case 16:
1010		      pApm->MaxClock = 144000;
1011		      break;
1012		 case 24:
1013		      pApm->MaxClock = 75000; /* Hmm. */
1014		      break;
1015		 case 32:
1016		      pApm->MaxClock = 94500;
1017		      break;
1018		 default:
1019		      return FALSE;
1020	       }
1021	       break;
1022	  case AT3D:
1023	       switch(pScrn->bitsPerPixel)
1024	       {
1025		 case 4:
1026		 case 8:
1027		      pApm->MaxClock = 175500;
1028		      break;
1029		 case 16:
1030		      pApm->MaxClock = 144000;
1031		      break;
1032		 case 24:
1033		      pApm->MaxClock = 94000; /* Changed from 75000 by Grenié */
1034		      break;
1035		 case 32:
1036		      pApm->MaxClock = 94500;
1037		      break;
1038		 default:
1039		      return FALSE;
1040	       }
1041	       break;
1042	  case AP6422:
1043	       switch(pScrn->bitsPerPixel)
1044	       {
1045		 case 4:
1046		 case 8:
1047		      pApm->MaxClock = 135000;
1048		      break;
1049		 case 16:
1050		      pApm->MaxClock = 75000;
1051		      break;
1052		 case 32:
1053		      pApm->MaxClock = 60000;
1054		      break;
1055		 default:
1056		      return FALSE;
1057	       }
1058	       break;
1059	  default:
1060	       pApm->MaxClock = 135000;
1061	       break;
1062	}
1063    }
1064    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
1065	       pApm->MaxClock / 1000);
1066
1067    /*
1068     * Setup the ClockRanges, which describe what clock ranges are available,
1069     * and what sort of modes they can be used for.
1070     */
1071    clockRanges = (ClockRangePtr)xnfcalloc(sizeof(ClockRange), 1);
1072    clockRanges->next = NULL;
1073    clockRanges->minClock = pApm->MinClock;
1074    clockRanges->maxClock = pApm->MaxClock;
1075    clockRanges->clockIndex = -1;		/* programmable */
1076    clockRanges->interlaceAllowed = FALSE;	/* XXX change this */
1077    clockRanges->doubleScanAllowed = FALSE;	/* XXX check this */
1078
1079    /* Select valid modes from those available */
1080    if (pApm->NoAccel) {
1081	/*
1082	 * XXX Assuming min pitch 256, max 2048
1083	 * XXX Assuming min height 128, max 1024 (changed EE)
1084	 */
1085	i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
1086			      pScrn->display->modes, clockRanges,
1087			      NULL, 256, 2048,
1088			      pScrn->bitsPerPixel, 128, 1024,
1089			      pScrn->display->virtualX,
1090			      pScrn->display->virtualY,
1091			      pApm->FbMapSize,
1092			      LOOKUP_BEST_REFRESH);
1093    } else {
1094	/*
1095	 * XXX Assuming min height 128, max 2048
1096	 */
1097	i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
1098			      pScrn->display->modes, clockRanges,
1099			      GetAccelPitchValues(pScrn), 0, 0,
1100			      pScrn->bitsPerPixel, 128, 1024,
1101			      pScrn->display->virtualX,
1102			      pScrn->display->virtualY,
1103			      pApm->FbMapSize,
1104			      LOOKUP_BEST_REFRESH);
1105    }
1106
1107    if (i == -1) {
1108	ApmFreeRec(pScrn);
1109	return FALSE;
1110    }
1111
1112    /* Prune the modes marked as invalid */
1113    xf86PruneDriverModes(pScrn);
1114
1115    if (i == 0 || pScrn->modes == NULL) {
1116	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1117	ApmFreeRec(pScrn);
1118	return FALSE;
1119    }
1120
1121    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
1122
1123    /* Set the current mode to the first in the list */
1124    pScrn->currentMode = pScrn->modes;
1125
1126    /* Print the list of modes being used */
1127    xf86PrintModes(pScrn);
1128
1129    /* Set display resolution */
1130    xf86SetDpi(pScrn, 0, 0);
1131
1132    /* Load bpp-specific modules */
1133    switch (pScrn->bitsPerPixel) {
1134    case 1:
1135	mod = "xf1bpp";
1136	req = "xf1bppScreenInit";
1137	break;
1138    case 4:
1139	mod = "xf4bpp";
1140	req = "xf4bppScreenInit";
1141	break;
1142    case 8:
1143    case 16:
1144    case 24:
1145    case 32:
1146	mod = "fb";
1147	break;
1148    }
1149
1150    if (mod && xf86LoadSubModule(pScrn, mod) == NULL) {
1151	ApmFreeRec(pScrn);
1152	return FALSE;
1153    }
1154
1155    if (mod) {
1156	if (req) {
1157	    xf86LoaderReqSymbols(req, NULL);
1158	} else {
1159	    xf86LoaderReqSymLists(fbSymbols, NULL);
1160	}
1161    }
1162
1163    /* Load XAA if needed */
1164    if (!pApm->NoAccel) {
1165	if (!xf86LoadSubModule(pScrn, "xaa")) {
1166	    ApmFreeRec(pScrn);
1167	    return FALSE;
1168	}
1169	xf86LoaderReqSymLists(xaaSymbols, NULL);
1170    }
1171
1172    /* Load ramdac if needed */
1173    if (pApm->hwCursor) {
1174	if (!xf86LoadSubModule(pScrn, "ramdac")) {
1175	    ApmFreeRec(pScrn);
1176	    return FALSE;
1177	}
1178	xf86LoaderReqSymLists(ramdacSymbols, NULL);
1179    }
1180
1181    /* Load shadowfb if needed */
1182    if (pApm->ShadowFB) {
1183	if (!xf86LoadSubModule(pScrn, "shadowfb")) {
1184	    ApmFreeRec(pScrn);
1185	    return FALSE;
1186	}
1187	xf86LoaderReqSymLists(shadowSymbols, NULL);
1188    }
1189
1190    pApm->CurrentLayout.displayWidth	= pScrn->virtualX;
1191    pApm->CurrentLayout.displayHeight	= pScrn->virtualY;
1192    pApm->CurrentLayout.bitsPerPixel	= pScrn->bitsPerPixel;
1193    pApm->CurrentLayout.bytesPerScanline= (pApm->CurrentLayout.displayWidth * pApm->CurrentLayout.bitsPerPixel) >> 3;
1194    pApm->CurrentLayout.depth		= pScrn->depth;
1195    pApm->CurrentLayout.Scanlines	= 2 * (pScrn->videoRam << 10) / pApm->CurrentLayout.bytesPerScanline;
1196    if (pScrn->bitsPerPixel == 24)
1197	pApm->CurrentLayout.mask32	= 3;
1198    else
1199	pApm->CurrentLayout.mask32	= 32 / pScrn->bitsPerPixel - 1;
1200
1201    return TRUE;
1202}
1203
1204/*
1205 * Map the framebuffer and MMIO memory.
1206 */
1207
1208static Bool
1209ApmMapMem(ScrnInfoPtr pScrn)
1210{
1211    APMDECL(pScrn);
1212    vgaHWPtr	hwp = VGAHWPTR(pScrn);
1213
1214    pApm->LinMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1215				 pApm->PciTag,
1216				 (unsigned long)pApm->LinAddress,
1217				 pApm->LinMapSize);
1218    if (pApm->LinMap == NULL)
1219	return FALSE;
1220
1221    if (!pApm->noLinear) {
1222	if (pApm->Chipset >= AT3D) {
1223	    pApm->FbBase = (void *)(((char *)pApm->LinMap) + 0x800000);
1224	    pApm->VGAMap = ((char *)pApm->LinMap) + 0xFFF000;
1225	    pApm->MemMap = ((char *)pApm->LinMap) + 0xFFEC00;
1226	    pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000);
1227	}
1228	else {
1229	    pApm->FbBase = (void *)pApm->LinMap;
1230	    pApm->VGAMap = NULL;
1231	    if (pScrn->videoRam == 6 * 1024 - 32) {
1232		pApm->MemMap = ((char *)pApm->LinMap) + 0x5FF800;
1233		pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x5F8000);
1234	    }
1235	    else {
1236		pApm->MemMap = ((char *)pApm->LinMap) + 0x3FF800;
1237		pApm->BltMap = (void *)(((char *)pApm->LinMap) + 0x3F8000);
1238	    }
1239	}
1240
1241	/*
1242	 * Initialize chipset
1243	 */
1244	pApm->c9 = RDXB(0xC9);
1245	if (pApm->Chipset >= AT3D) {
1246	    pApm->d9 = RDXB(0xD9);
1247	    pApm->db = RDXB(0xDB);
1248
1249	    /* If you change these two, change them also in apm_funcs.c */
1250	    WRXB(0xDB, (pApm->db & 0xF4) | 0x0A);
1251	    WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20);
1252
1253	    vgaHWSetMmioFuncs(hwp, (CARD8 *)pApm->LinMap, 0xFFF000);
1254	}
1255	if (pApm->Chipset >= AP6422)
1256	    WRXB(0xC9, pApm->c9 | 0x10);
1257    }
1258    else {
1259	pApm->FbBase = pApm->LinMap;
1260
1261	/*
1262	 * Initialize chipset
1263	 */
1264	if (pApm->Chipset >= AT3D) {
1265	    pApm->d9 = RDXB_IOP(0xD9);
1266	    pApm->db = RDXB_IOP(0xDB);
1267	    WRXB_IOP(0xDB, pApm->db & 0xF4);
1268	}
1269    }
1270    /*
1271     * Save color mode
1272     */
1273    pApm->MiscOut = hwp->readMiscOut(hwp);
1274
1275    return TRUE;
1276}
1277
1278/*
1279 * Unmap the framebuffer and MMIO memory
1280 */
1281
1282static Bool
1283ApmUnmapMem(ScrnInfoPtr pScrn)
1284{
1285    APMDECL(pScrn);
1286    vgaHWPtr	hwp = VGAHWPTR(pScrn);
1287
1288    /*
1289     * Reset color mode
1290     */
1291    hwp->writeMiscOut(hwp, pApm->MiscOut);
1292    if (pApm->LinMap) {
1293	if (pApm->Chipset >= AT3D) {
1294	    if (!pApm->noLinear) {
1295		WRXB(0xD9, pApm->d9);
1296		WRXB(0xDB, pApm->db);
1297	    }
1298	    else {
1299		WRXB_IOP(0xD9, pApm->d9);
1300		WRXB_IOP(0xDB, pApm->db);
1301	    }
1302	}
1303	WRXB(0xC9, pApm->c9);
1304	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, pApm->LinMapSize);
1305	pApm->LinMap = NULL;
1306    }
1307    else if (pApm->FbBase)
1308	xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pApm->LinMap, 0x10000);
1309
1310    return TRUE;
1311}
1312
1313/*
1314 * This function saves the video state.
1315 */
1316static void
1317ApmSave(ScrnInfoPtr pScrn)
1318{
1319    APMDECL(pScrn);
1320    ApmRegPtr	ApmReg = &pApm->SavedReg;
1321    vgaHWPtr	hwp    = VGAHWPTR(pScrn);
1322
1323    if (pApm->VGAMap) {
1324	ApmReg->SEQ[0x1B] = ApmReadSeq(0x1B);
1325	ApmReg->SEQ[0x1C] = ApmReadSeq(0x1C);
1326
1327	/*
1328	 * Save fonts
1329	 */
1330	if (!(hwp->SavedReg.Attribute[0x10] & 1)) {
1331	    if (pApm->FontInfo || (pApm->FontInfo = (pointer)xalloc(TEXT_AMOUNT))) {
1332		int locked;
1333
1334		locked = ApmReadSeq(0x10);
1335		if (locked)
1336		    ApmWriteSeq(0x10, 0x12);
1337		ApmWriteSeq(0x1C, 0x3F);
1338		memcpy(pApm->FontInfo, pApm->FbBase, TEXT_AMOUNT);
1339		ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]);
1340		if (locked)
1341		    ApmWriteSeq(0x10, 0);
1342	    }
1343	}
1344	/*
1345	 * This function will handle creating the data structure and filling
1346	 * in the generic VGA portion.
1347	 */
1348	vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_CMAP);
1349
1350	/* Hardware cursor registers. */
1351	ApmReg->EX[XR140] = RDXL(0x140);
1352	ApmReg->EX[XR144] = RDXW(0x144);
1353	ApmReg->EX[XR148] = RDXL(0x148);
1354	ApmReg->EX[XR14C] = RDXW(0x14C);
1355
1356	ApmReg->CRT[0x19] = ApmReadCrtc(0x19);
1357	ApmReg->CRT[0x1A] = ApmReadCrtc(0x1A);
1358	ApmReg->CRT[0x1B] = ApmReadCrtc(0x1B);
1359	ApmReg->CRT[0x1C] = ApmReadCrtc(0x1C);
1360	ApmReg->CRT[0x1D] = ApmReadCrtc(0x1D);
1361	ApmReg->CRT[0x1E] = ApmReadCrtc(0x1E);
1362
1363	/* RAMDAC registers. */
1364	ApmReg->EX[XRE8] = RDXL(0xE8);
1365	ApmReg->EX[XREC] = RDXL(0xEC);
1366
1367	/* Color correction */
1368	ApmReg->EX[XRE0] = RDXL(0xE0);
1369
1370	ApmReg->EX[XR80] = RDXB(0x80);
1371    }
1372    else {
1373	/*
1374	 * This function will handle creating the data structure and filling
1375	 * in the generic VGA portion.
1376	 */
1377	vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL);
1378
1379	ApmReg->SEQ[0x1B] = rdinx(pApm->xport, 0x1B);
1380	ApmReg->SEQ[0x1C] = rdinx(pApm->xport, 0x1C);
1381
1382	/* Hardware cursor registers. */
1383	if (pApm->noLinear) {
1384	    ApmReg->EX[XR140] = RDXL_IOP(0x140);
1385	    ApmReg->EX[XR144] = RDXW_IOP(0x144);
1386	    ApmReg->EX[XR148] = RDXL_IOP(0x148);
1387	    ApmReg->EX[XR14C] = RDXW_IOP(0x14C);
1388	}
1389	else {
1390	    ApmReg->EX[XR140] = RDXL(0x140);
1391	    ApmReg->EX[XR144] = RDXW(0x144);
1392	    ApmReg->EX[XR148] = RDXL(0x148);
1393	    ApmReg->EX[XR14C] = RDXW(0x14C);
1394	}
1395
1396	ApmReg->CRT[0x19] = rdinx(pApm->iobase + 0x3D4, 0x19);
1397	ApmReg->CRT[0x1A] = rdinx(pApm->iobase + 0x3D4, 0x1A);
1398	ApmReg->CRT[0x1B] = rdinx(pApm->iobase + 0x3D4, 0x1B);
1399	ApmReg->CRT[0x1C] = rdinx(pApm->iobase + 0x3D4, 0x1C);
1400	ApmReg->CRT[0x1D] = rdinx(pApm->iobase + 0x3D4, 0x1D);
1401	ApmReg->CRT[0x1E] = rdinx(pApm->iobase + 0x3D4, 0x1E);
1402
1403	if (pApm->noLinear) {
1404	    /* RAMDAC registers. */
1405	    ApmReg->EX[XRE8] = RDXL_IOP(0xE8);
1406	    ApmReg->EX[XREC] = RDXL_IOP(0xEC);
1407
1408	    /* Color correction */
1409	    ApmReg->EX[XRE0] = RDXL_IOP(0xE0);
1410
1411	    ApmReg->EX[XR80] = RDXB_IOP(0x80);
1412	}
1413	else {
1414	    /* RAMDAC registers. */
1415	    ApmReg->EX[XRE8] = RDXL(0xE8);
1416	    ApmReg->EX[XREC] = RDXL(0xEC);
1417
1418	    /* Color correction */
1419	    ApmReg->EX[XRE0] = RDXL(0xE0);
1420
1421	    ApmReg->EX[XR80] = RDXB(0x80);
1422	}
1423    }
1424}
1425
1426#define WITHIN(v,c1,c2) (((v) >= (c1)) && ((v) <= (c2)))
1427
1428static unsigned
1429comp_lmn(ApmPtr pApm, long clock)
1430{
1431  int     n, m, l, f;
1432  double  fvco;
1433  double  fout;
1434  double  fmax, fmin;
1435  double  fref;
1436  double  fvco_goal;
1437  double  k, c;
1438  double fout_best = 0;
1439  unsigned int best = 0;
1440
1441  if (pApm->Chipset >= AT3D)
1442    fmax = 370000.0;
1443  else
1444    fmax = 250000.0;
1445
1446  fref = 14318.0;
1447  fmin = fmax / 2.0;
1448
1449  for (m = 1; m <= 5; m++)
1450  {
1451    for (l = 3; l >= 0; l--)
1452    {
1453      for (n = 8; n <= 127; n++)
1454      {
1455        fout = ((double)(n + 1) * fref)/((double)(m + 1) * (1 << l));
1456        fvco_goal = (double)clock * (double)(1 << l);
1457        fvco = fout * (double)(1 << l);
1458        if (!WITHIN(fvco, 0.99*fvco_goal, 1.01*fvco_goal))
1459          continue;
1460        if (!WITHIN(fvco, fmin, fmax))
1461          continue;
1462        if (!WITHIN(fvco / (double)(n+1), 300.0, 300000.0))
1463          continue;
1464        if (!WITHIN(fref / (double)(m+1), 300.0, 300000.0))
1465          continue;
1466
1467	if (fout_best != 0) {
1468	    double diff_new = clock - fout;
1469	    double diff_old = clock - best;
1470	    diff_new = diff_new < 0 ? -diff_new : diff_new;
1471	    diff_old = diff_old < 0 ? -diff_old : diff_old;
1472	    if (diff_new > diff_old)
1473		continue;
1474	}
1475	fout_best = fout;
1476
1477        /* The following formula was empirically derived by
1478           matching a number of fvco values with acceptable
1479           values of f.
1480
1481           (fvco can be 185MHz - 370MHz on AT3D)
1482           (fvco can be 125MHz - 250MHz on AT24/AP6422)
1483
1484           The table that was measured up follows:
1485
1486           AT3D
1487
1488           fvco       f
1489           (125)     (x-7) guess
1490           200       5-7
1491           219       4-7
1492           253       3-6
1493           289       2-5
1494           320       0-4
1495           (400)     (0-x) guess
1496
1497           AT24
1498
1499           fvco       f
1500           126       7
1501           200       5-7
1502           211       4-7
1503
1504           AP6422
1505
1506           fvco       f
1507           126       7
1508           169       5-7
1509           200       4-5
1510           211       4-5
1511
1512           From this, a function "f = k * fvco + c" was derived.
1513
1514           For AT3D, this table was measured with MCLK == 50MHz.
1515           The driver has since been set to use MCLK == 57.3MHz for,
1516           but I don't think that makes a difference here.
1517         */
1518
1519        if (pApm->Chipset >= AT24)
1520        {
1521          k = 7.0 / (175.0 - 380.0);
1522          c = -k * 380.0;
1523          f = (int)(k * fvco/1000.0 + c + 0.5);
1524          if (f > 7) f = 7;
1525          if (f < 0) f = 0;
1526        } else { /* i.e AP6422 */
1527          c = (211.0*6.0-169.0*4.5)/(211.0-169.0);
1528          k = (4.5-c)/211.0;
1529          f = (int)(k * fvco/1000.0 + c + 0.5);
1530          if (f > 7) f = 7;
1531          if (f < 0) f = 0;
1532        }
1533
1534        best =  (n << 16) | (m << 8) | (l << 2) | (f << 4);
1535      }
1536    }
1537  }
1538
1539  if (fout_best != 0)
1540      return best;
1541
1542  xf86DrvMsg(pApm->scrnIndex, X_PROBED,
1543		"Cannot find register values for clock %6.2f MHz. "
1544		"Please use a (slightly) different clock.\n",
1545		 (double)clock / 1000.0);
1546  return 0;
1547}
1548
1549/*
1550 * Initialise a new mode.  This is currently still using the old
1551 * "initialise struct, restore/write struct to HW" model.  That could
1552 * be changed.
1553 */
1554
1555static Bool
1556ApmModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
1557{
1558    APMDECL(pScrn);
1559    ApmRegPtr	ApmReg = &pApm->ModeReg;
1560    vgaHWPtr	hwp;
1561
1562
1563    /* set clockIndex to "2" for programmable clocks */
1564    if (pScrn->progClock)
1565	mode->ClockIndex = 2;
1566
1567    /* prepare standard VGA register contents */
1568    if (!vgaHWInit(pScrn, mode))
1569	return FALSE;
1570    pScrn->vtSema = TRUE;
1571    hwp = VGAHWPTR(pScrn);
1572
1573    hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F);
1574
1575    if (xf86IsPc98())
1576       outb(0xFAC, 0xFF);
1577
1578    memcpy(ApmReg, &pApm->SavedReg, sizeof pApm->SavedReg);
1579
1580    /*
1581     * The APM chips have a scale factor of 8 for the
1582     * scanline offset. There are four extended bit in addition
1583     * to the 8 VGA bits.
1584     */
1585    {
1586	int offset;
1587
1588	offset = (pApm->CurrentLayout.displayWidth *
1589		  pApm->CurrentLayout.bitsPerPixel / 8)	>> 3;
1590	hwp->ModeReg.CRTC[0x13] = offset;
1591	/* Bit 8 resides at CR1C bits 7:4. */
1592	ApmReg->CRT[0x1C] = (offset & 0xF00) >> 4;
1593    }
1594
1595    /* Set pixel depth. */
1596    switch(pApm->CurrentLayout.bitsPerPixel)
1597    {
1598    case 4:
1599	 ApmReg->EX[XR80] = 0x01;
1600	 break;
1601    case 8:
1602	 ApmReg->EX[XR80] = 0x02;
1603	 break;
1604    case 16:
1605	 if (pApm->CurrentLayout.depth == 15)
1606	     ApmReg->EX[XR80] = 0x0C;
1607	 else
1608	     ApmReg->EX[XR80] = 0x0D;
1609	 break;
1610    case 24:
1611	 ApmReg->EX[XR80] = 0x0E;
1612	 break;
1613    case 32:
1614	 ApmReg->EX[XR80] = 0x0F;
1615	 break;
1616    default:
1617	 FatalError("Unsupported bit depth %d\n", pApm->CurrentLayout.depth);
1618	 break;
1619    }
1620
1621    /* Set banking register to zero. */
1622    ApmReg->EX[XRC0] = 0;
1623
1624    /* Handle the CRTC overflow bits. */
1625    {
1626	unsigned char val;
1627	/* Vertical Overflow. */
1628	val = 0;
1629	if ((mode->CrtcVTotal - 2) & 0x400)
1630	    val |= 0x01;
1631	if ((mode->CrtcVDisplay - 1) & 0x400)
1632	    val |= 0x02;
1633	/* VBlankStart is equal to VSyncStart + 1. */
1634	if (mode->CrtcVSyncStart & 0x400)
1635	    val |= 0x04;
1636	/* VRetraceStart is equal to VSyncStart + 1. */
1637	if (mode->CrtcVSyncStart & 0x400)
1638	    val |= 0x08;
1639	ApmReg->CRT[0x1A] = val;
1640
1641	/* Horizontal Overflow. */
1642	val = 0;
1643	if ((mode->CrtcHTotal / 8 - 5) & 0x100)
1644	    val |= 1;
1645	if ((mode->CrtcHDisplay / 8 - 1) & 0x100)
1646	    val |= 2;
1647	/* HBlankStart is equal to HSyncStart - 1. */
1648	if ((mode->CrtcHSyncStart / 8 - 1) & 0x100)
1649	    val |= 4;
1650	/* HRetraceStart is equal to HSyncStart. */
1651	if ((mode->CrtcHSyncStart / 8) & 0x100)
1652	    val |= 8;
1653	ApmReg->CRT[0x1B] = val;
1654
1655	/* Assume the CRTC is not KGA (see vgaHWInit) */
1656	hwp->ModeReg.CRTC[3] = (hwp->ModeReg.CRTC[3] & 0xE0) |
1657				(((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F);
1658	hwp->ModeReg.CRTC[5]  = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2)
1659				| (hwp->ModeReg.CRTC[5] & 0x7F);
1660	hwp->ModeReg.CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
1661    }
1662    ApmReg->CRT[0x1E] = 1;          /* disable autoreset feature */
1663
1664    /* Program clock select. */
1665    ApmReg->EX[XREC] = comp_lmn(pApm, mode->Clock);
1666    if (!ApmReg->EX[XREC])
1667      return FALSE;
1668    hwp->ModeReg.MiscOutReg |= 0x0C;
1669
1670    /* Set up the RAMDAC registers. */
1671
1672    if (pApm->CurrentLayout.bitsPerPixel > 8)
1673	/* Get rid of white border. */
1674	hwp->ModeReg.Attribute[0x11] = 0x00;
1675    else
1676	hwp->ModeReg.Attribute[0x11] = 0xFF;
1677    if (pApm->MemClk)
1678	ApmReg->EX[XRE8] = comp_lmn(pApm, pApm->MemClk);
1679    else if (pApm->Chipset >= AT3D)
1680	ApmReg->EX[XRE8] = 0x071F01E8; /* Enable 58MHz MCLK (actually 57.3 MHz)
1681				       This is what is used in the Windows
1682				       drivers. The BIOS sets it to 50MHz. */
1683    else if (!pApm->noLinear)
1684	ApmReg->EX[XRE8] = RDXL(0xE8); /* No change */
1685    else
1686	ApmReg->EX[XRE8] = RDXL_IOP(0xE8); /* No change */
1687
1688    ApmReg->EX[XRE0] = 0x10;
1689
1690    /* If you change it, change in apm_funcs.c as well */
1691    if (pApm->Chipset >= AT3D) {
1692	ApmReg->SEQ[0x1B] = 0x20;
1693	ApmReg->SEQ[0x1C] = 0x2F;
1694    }
1695    else {
1696	ApmReg->SEQ[0x1B] = 0x24;
1697	if (pScrn->videoRam >= 6 * 1024)
1698	    ApmReg->SEQ[0x1C] = 0x2F;
1699	else
1700	    ApmReg->SEQ[0x1C] = 0x2D;
1701    }
1702
1703    /* ICICICICI */
1704    ApmRestore(pScrn, &hwp->ModeReg, ApmReg);
1705
1706    return TRUE;
1707}
1708
1709/*
1710 * Restore the initial mode.
1711 */
1712static void
1713ApmRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, ApmRegPtr ApmReg)
1714{
1715    APMDECL(pScrn);
1716
1717    vgaHWProtect(pScrn, TRUE);
1718    ApmUnlock(pApm);
1719
1720    if (pApm->VGAMap) {
1721	/*
1722	 * Restore fonts
1723	 */
1724	if (!(vgaReg->Attribute[0x10] & 1) && pApm->FontInfo) {
1725	    ApmWriteSeq(0x1C, 0x3F);
1726	    memcpy(pApm->FbBase, pApm->FontInfo, TEXT_AMOUNT);
1727	}
1728
1729	/* Set aperture index to 0. */
1730	WRXW(0xC0, 0);
1731
1732	/*
1733	 * Write the extended registers first
1734	 */
1735	ApmWriteSeq(0x1B, ApmReg->SEQ[0x1B]);
1736	ApmWriteSeq(0x1C, ApmReg->SEQ[0x1C]);
1737
1738	/* Hardware cursor registers. */
1739	WRXL(0x140, ApmReg->EX[XR140]);
1740	WRXW(0x144, ApmReg->EX[XR144]);
1741	WRXL(0x148, ApmReg->EX[XR148]);
1742	WRXW(0x14C, ApmReg->EX[XR14C]);
1743
1744	ApmWriteCrtc(0x19, ApmReg->CRT[0x19]);
1745	ApmWriteCrtc(0x1A, ApmReg->CRT[0x1A]);
1746	ApmWriteCrtc(0x1B, ApmReg->CRT[0x1B]);
1747	ApmWriteCrtc(0x1D, ApmReg->CRT[0x1D]);
1748	ApmWriteCrtc(0x1E, ApmReg->CRT[0x1E]);
1749
1750	/* RAMDAC registers. */
1751	WRXL(0xE8, ApmReg->EX[XRE8]);
1752
1753	WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
1754	WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */
1755
1756	/* Color correction */
1757	WRXL(0xE0, ApmReg->EX[XRE0]);
1758
1759	/*
1760	 * This function handles restoring the generic VGA registers.
1761	 */
1762	vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP);
1763
1764	/* set these after setting the default VGA registers */
1765	ApmWriteCrtc(0x1C, ApmReg->CRT[0x1C]);
1766	WRXB(0x80, ApmReg->EX[XR80]);
1767    }
1768    else {
1769	/* Set aperture index to 0. */
1770	if (pApm->noLinear)
1771	    WRXW_IOP(0xC0, 0);
1772	else
1773	    WRXW(0xC0, 0);
1774
1775	/*
1776	 * Write the extended registers first
1777	 */
1778	wrinx(pApm->xport, 0x1B, ApmReg->SEQ[0x1B]);
1779	wrinx(pApm->xport, 0x1C, ApmReg->SEQ[0x1C]);
1780
1781	/* Hardware cursor registers. */
1782	if (pApm->noLinear) {
1783	    WRXL_IOP(0x140, ApmReg->EX[XR140]);
1784	    WRXW_IOP(0x144, ApmReg->EX[XR144]);
1785	    WRXL_IOP(0x148, ApmReg->EX[XR148]);
1786	    WRXW_IOP(0x14C, ApmReg->EX[XR14C]);
1787	}
1788	else {
1789	    WRXL(0x140, ApmReg->EX[XR140]);
1790	    WRXW(0x144, ApmReg->EX[XR144]);
1791	    WRXL(0x148, ApmReg->EX[XR148]);
1792	    WRXW(0x14C, ApmReg->EX[XR14C]);
1793	}
1794
1795	wrinx(pApm->iobase + 0x3D4, 0x19, ApmReg->CRT[0x19]);
1796	wrinx(pApm->iobase + 0x3D4, 0x1A, ApmReg->CRT[0x1A]);
1797	wrinx(pApm->iobase + 0x3D4, 0x1B, ApmReg->CRT[0x1B]);
1798	wrinx(pApm->iobase + 0x3D4, 0x1C, ApmReg->CRT[0x1C]);
1799	wrinx(pApm->iobase + 0x3D4, 0x1D, ApmReg->CRT[0x1D]);
1800	wrinx(pApm->iobase + 0x3D4, 0x1E, ApmReg->CRT[0x1E]);
1801
1802	/* RAMDAC registers. */
1803	if (pApm->noLinear) {
1804	    WRXL_IOP(0xE8, ApmReg->EX[XRE8]);
1805	    WRXL_IOP(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
1806	    WRXL_IOP(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */
1807	}
1808	else {
1809	    WRXL(0xE8, ApmReg->EX[XRE8]);
1810	    WRXL(0xEC, ApmReg->EX[XREC] & ~(1 << 7));
1811	    WRXL(0xEC, ApmReg->EX[XREC] | (1 << 7)); /* Do a PLL resync */
1812	}
1813
1814	/* Color correction */
1815	if (pApm->noLinear)
1816	    WRXL_IOP(0xE0, ApmReg->EX[XRE0]);
1817	else
1818	    WRXL(0xE0, ApmReg->EX[XRE0]);
1819
1820	if (pApm->noLinear)
1821	    WRXB_IOP(0x80, ApmReg->EX[XR80]);
1822	else
1823	    WRXB(0x80, ApmReg->EX[XR80]);
1824
1825	/*
1826	 * This function handles restoring the generic VGA registers.
1827	 */
1828	vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
1829    }
1830
1831    vgaHWProtect(pScrn, FALSE);
1832}
1833
1834
1835/* Refresh a region of the shadow framebuffer to the screen */
1836static void
1837ApmRefreshArea(ScrnInfoPtr pScrn, int num, BoxPtr pbox)
1838{
1839    APMDECL(pScrn);
1840    int width, height, Bpp, FBPitch;
1841    unsigned char *src, *dst;
1842
1843    Bpp = pApm->CurrentLayout.bitsPerPixel >> 3;
1844    FBPitch = pApm->CurrentLayout.bytesPerScanline;
1845
1846    while(num--) {
1847	width = (pbox->x2 - pbox->x1) * Bpp;
1848	height = pbox->y2 - pbox->y1;
1849	src = pApm->ShadowPtr + (pbox->y1 * pApm->ShadowPitch) +
1850						(pbox->x1 * Bpp);
1851	dst = (unsigned char *)pApm->FbBase + (pbox->y1 * FBPitch) + (pbox->x1 * Bpp);
1852
1853	while(height--) {
1854	    memcpy(dst, src, width);
1855	    dst += FBPitch;
1856	    src += pApm->ShadowPitch;
1857	}
1858
1859	pbox++;
1860    }
1861}
1862
1863
1864/* Mandatory */
1865
1866/* This gets called at the start of each server generation */
1867
1868static Bool
1869ApmScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
1870{
1871    ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
1872    APMDECL(pScrn);
1873    int			ret;
1874    unsigned char	*FbBase;
1875
1876    pApm->pScreen = pScreen;
1877
1878    /* Map the chip memory and MMIO areas */
1879    if (pApm->noLinear) {
1880	pApm->saveCmd = pciReadLong(pApm->PciTag, PCI_CMD_STAT_REG);
1881	pciWriteLong(pApm->PciTag, PCI_CMD_STAT_REG, pApm->saveCmd | (PCI_CMD_IO_ENABLE|PCI_CMD_MEM_ENABLE));
1882	pApm->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1883				 pApm->PciTag, 0xA0000, 0x10000);
1884    }
1885    else
1886	if (!ApmMapMem(pScrn))
1887	    return FALSE;
1888
1889    /* No memory reserved yet */
1890    pApm->OffscreenReserved = 0;
1891
1892    /* Save the current state */
1893    ApmSave(pScrn);
1894
1895    /* Initialise the first mode */
1896    ApmModeInit(pScrn, pScrn->currentMode);
1897    pApm->CurrentLayout.pMode = pScrn->currentMode;
1898
1899    /* Darken the screen for aesthetic reasons and set the viewport */
1900    ApmSaveScreen(pScreen, SCREEN_SAVER_ON);
1901    ApmAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1902
1903    /*
1904     * Reset fb's visual list.
1905     */
1906    miClearVisualTypes();
1907
1908    /* Setup the visuals we support. */
1909
1910    /*
1911     * For bpp > 8, the default visuals are not acceptable because we only
1912     * support TrueColor and not DirectColor.  To deal with this, call
1913     * miSetVisualTypes for each visual supported.
1914     */
1915
1916    if (pApm->CurrentLayout.bitsPerPixel > 8) {
1917	if (!miSetVisualTypes(pScrn->depth, TrueColorMask, pScrn->rgbBits,
1918				pScrn->defaultVisual))
1919	    return FALSE;
1920    } else {
1921	if (!miSetVisualTypes(pScrn->depth,
1922			      miGetDefaultVisualMask(pScrn->depth),
1923			      pScrn->rgbBits, pScrn->defaultVisual))
1924	    return FALSE;
1925    }
1926
1927    /*
1928     * Call the framebuffer layer's ScreenInit function, and fill in other
1929     * pScreen fields.
1930     */
1931
1932    if(pApm->ShadowFB) {
1933	pApm->ShadowPitch =
1934		((pScrn->virtualX * pScrn->bitsPerPixel >> 3) + 3) & ~3L;
1935	pApm->ShadowPtr = xalloc(pApm->ShadowPitch * pScrn->virtualY);
1936	FbBase = pApm->ShadowPtr;
1937    } else {
1938	pApm->ShadowPtr = NULL;
1939	FbBase = pApm->FbBase;
1940    }
1941
1942    /* Reserve memory */
1943    ApmHWCursorReserveSpace(pApm);
1944    ApmAccelReserveSpace(pApm);
1945
1946    miSetPixmapDepths();
1947
1948    switch (pScrn->bitsPerPixel) {
1949    case 1:
1950	ret = xf1bppScreenInit(pScreen, FbBase,
1951			pScrn->virtualX, pScrn->virtualY,
1952			pScrn->xDpi, pScrn->yDpi,
1953			pScrn->displayWidth);
1954	break;
1955    case 4:
1956	ret = xf4bppScreenInit(pScreen, FbBase,
1957			pScrn->virtualX, pScrn->virtualY,
1958			pScrn->xDpi, pScrn->yDpi,
1959			pScrn->displayWidth);
1960	break;
1961    case 8:
1962    case 16:
1963    case 24:
1964    case 32:
1965	ret = fbScreenInit(pScreen, FbBase, pScrn->virtualX,
1966	    pScrn->virtualY, pScrn->xDpi, pScrn->yDpi,
1967	    pScrn->displayWidth, pScrn->bitsPerPixel);
1968	break;
1969    default:
1970	xf86DrvMsg(scrnIndex, X_ERROR,
1971	    "Internal error: invalid bpp (%d) in ApmScrnInit\n",
1972	    pScrn->bitsPerPixel);
1973	ret = FALSE;
1974	break;
1975    }
1976    if (!ret)
1977	return FALSE;
1978
1979    if (pScrn->bitsPerPixel > 8) {
1980	VisualPtr	visual;
1981
1982	/* Fixup RGB ordering */
1983	visual = pScreen->visuals + pScreen->numVisuals;
1984	while (--visual >= pScreen->visuals) {
1985	    if ((visual->class | DynamicClass) == DirectColor) {
1986		visual->offsetRed = pScrn->offset.red;
1987		visual->offsetGreen = pScrn->offset.green;
1988		visual->offsetBlue = pScrn->offset.blue;
1989		visual->redMask = pScrn->mask.red;
1990		visual->greenMask = pScrn->mask.green;
1991		visual->blueMask = pScrn->mask.blue;
1992	    }
1993	}
1994    }
1995
1996    /* must be after visual RGB order fixed */
1997    if (pScrn->bitsPerPixel > 4)
1998	fbPictureInit(pScreen, 0, 0);
1999
2000    xf86SetBlackWhitePixels(pScreen);
2001
2002    if (!pApm->ShadowFB) {       /* hardware cursor needs to wrap this layer */
2003	if(!ApmDGAInit(pScreen)) {
2004	    xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DGA initialization failed\n");
2005	}
2006    }
2007
2008    /*
2009     * Initialize the acceleration interface.
2010     */
2011    if (!pApm->NoAccel) {
2012	ApmAccelInit(pScreen);		/* set up XAA interface */
2013    }
2014
2015    miInitializeBackingStore(pScreen);
2016    xf86SetBackingStore(pScreen);
2017    xf86SetSilkenMouse(pScreen);
2018
2019    /* Initialise cursor functions */
2020    miDCInitialize (pScreen, xf86GetPointerScreenFuncs());
2021
2022    /* Initialize HW cursor layer (after DGA and SW cursor) */
2023    if (pApm->hwCursor) {
2024	if (!ApmHWCursorInit(pScreen))
2025            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2026                "Hardware cursor initialization failed\n");
2027    }
2028
2029
2030    /* Initialise default colourmap */
2031    if (!miCreateDefColormap(pScreen))
2032	return FALSE;
2033
2034    /*
2035     * Initialize colormap layer.
2036     * Must follow initialization of the default colormap.
2037     */
2038    if (!xf86HandleColormaps(pScreen, 256, 8, ApmLoadPalette, NULL,
2039				CMAP_RELOAD_ON_MODE_SWITCH)) {
2040	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Colormap initialization failed\n");
2041	return FALSE;
2042    }
2043
2044    if (pApm->ShadowFB)
2045	ShadowFBInit(pScreen, ApmRefreshArea);
2046
2047    xf86DPMSInit(pScreen, ApmDisplayPowerManagementSet, 0);
2048
2049    if (pApm->noLinear)
2050	ApmInitVideo_IOP(pScreen);
2051    else
2052	ApmInitVideo(pScreen);
2053
2054    pScreen->SaveScreen  = ApmSaveScreen;
2055
2056    pApm->CloseScreen = pScreen->CloseScreen;
2057    pScreen->CloseScreen = ApmCloseScreen;
2058
2059    pScrn->memPhysBase = pApm->LinAddress;
2060    pScrn->fbOffset = (((char *)pApm->FbBase) - ((char *)pApm->LinMap));
2061
2062    /* Report any unused options (only for the first generation) */
2063    if (serverGeneration == 1) {
2064	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
2065    }
2066
2067    if (ApmGeneration != serverGeneration) {
2068	if ((ApmPixmapIndex = AllocatePixmapPrivateIndex()) < 0)
2069	    return FALSE;
2070	ApmGeneration = serverGeneration;
2071    }
2072
2073    if (!AllocatePixmapPrivate(pScreen, ApmPixmapIndex, sizeof(ApmPixmapRec)))
2074	return FALSE;
2075
2076    /* Done */
2077    return TRUE;
2078}
2079
2080/* mandatory */
2081static void
2082ApmLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
2083	       VisualPtr pVisual)
2084{
2085    APMDECL(pScrn);
2086    int i, index, last = -1;
2087
2088    if (pApm->VGAMap) {
2089	for (i = 0; i < numColors; i++) {
2090	    index = indices[i];
2091	    if (index != last)
2092		ApmWriteDacWriteAddr(index);
2093	    last = index + 1;
2094	    ApmWriteDacData(colors[index].red);
2095	    ApmWriteDacData(colors[index].green);
2096	    ApmWriteDacData(colors[index].blue);
2097	}
2098    }
2099    else {
2100	for (i = 0; i < numColors; i++) {
2101	    index = indices[i];
2102	    if (index != last)
2103		outb(pApm->iobase + 0x3C8, index);
2104	    last = index + 1;
2105	    outb(pApm->iobase + 0x3C9, colors[index].red);
2106	    outb(pApm->iobase + 0x3C9, colors[index].green);
2107	    outb(pApm->iobase + 0x3C9, colors[index].blue);
2108	}
2109    }
2110}
2111
2112/* Usually mandatory */
2113Bool
2114ApmSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
2115{
2116    return ApmModeInit(xf86Screens[scrnIndex], mode);
2117}
2118
2119/*
2120 * This function is used to initialize the Start Address - the first
2121 * displayed location in the video memory.
2122 */
2123/* Usually mandatory */
2124void
2125ApmAdjustFrame(int scrnIndex, int x, int y, int flags)
2126{
2127    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2128    APMDECL(pScrn);
2129    int Base;
2130
2131    if (pApm->CurrentLayout.bitsPerPixel == 24)
2132	x = (x + 3) & ~3;
2133    Base = ((y * pApm->CurrentLayout.displayWidth + x) * (pApm->CurrentLayout.bitsPerPixel / 8)) >> 2;
2134    /*
2135     * These are the generic starting address registers.
2136     */
2137    if (pApm->VGAMap) {
2138	ApmWriteCrtc(0x0C, Base >> 8);
2139	ApmWriteCrtc(0x0D, Base);
2140
2141	/*
2142	 * Here the high-order bits are masked and shifted, and put into
2143	 * the appropriate extended registers.
2144	 */
2145	ApmWriteCrtc(0x1C, (ApmReadCrtc(0x1C) & 0xF0) | ((Base & 0x0F0000) >> 16));
2146    }
2147    else {
2148	outw(pApm->iobase + 0x3D4, (Base & 0x00FF00) | 0x0C);
2149	outw(pApm->iobase + 0x3D4, ((Base & 0x00FF) << 8) | 0x0D);
2150
2151	/*
2152	 * Here the high-order bits are masked and shifted, and put into
2153	 * the appropriate extended registers.
2154	 */
2155	modinx(pApm->iobase + 0x3D4, 0x1C, 0x0F, (Base & 0x0F0000) >> 16);
2156    }
2157}
2158
2159/*
2160 * This is called when VT switching back to the X server.  Its job is
2161 * to reinitialise the video mode.
2162 *
2163 * We may wish to unmap video/MMIO memory too.
2164 */
2165
2166/* Mandatory */
2167static Bool
2168ApmEnterVT(int scrnIndex, int flags)
2169{
2170    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2171    APMDECL(pScrn);
2172    vgaHWPtr	hwp = VGAHWPTR(pScrn);
2173
2174    if (pApm->Chipset >= AT3D) {
2175	if (!pApm->noLinear) {
2176	    /* If you change it, change it also in apm_funcs.c */
2177	    WRXB(0xDB, (pApm->db & 0xF4) | 0x0A | pApm->Rush);
2178	    WRXB(0xD9, (pApm->d9 & 0xCF) | 0x20);
2179	}
2180	else {
2181	    WRXB_IOP(0xDB, pApm->db & 0xF4);
2182	}
2183    }
2184    if (pApm->Chipset >= AP6422)
2185	WRXB(0xC9, pApm->c9 | 0x10);
2186    ApmUnlock(APMPTR(pScrn));
2187    vgaHWUnlock(hwp);
2188    /*
2189     * Set color mode
2190     */
2191    hwp->writeMiscOut(hwp, pApm->MiscOut | 0x0F);
2192
2193    if (!ApmModeInit(pScrn, pScrn->currentMode))
2194	return FALSE;
2195    ApmAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
2196
2197    return TRUE;
2198}
2199
2200/* Mandatory */
2201static void
2202ApmLeaveVT(int scrnIndex, int flags)
2203{
2204    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2205    APMDECL(pScrn);
2206    vgaHWPtr	hwp = VGAHWPTR(pScrn);
2207
2208    ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg);
2209    /*
2210     * Reset color mode
2211     */
2212    (*hwp->writeMiscOut)(hwp, pApm->MiscOut);
2213    vgaHWLock(hwp);
2214    ApmLock(pApm);
2215    if (pApm->Chipset >= AT3D) {
2216	if (!pApm->noLinear) {
2217	    WRXB(0xD9, pApm->d9);
2218	    WRXB(0xDB, pApm->db);
2219	}
2220	else {
2221	    WRXB_IOP(0xD9, pApm->d9);
2222	    WRXB_IOP(0xDB, pApm->db);
2223	}
2224    }
2225    WRXB(0xC9, pApm->c9);
2226
2227    if (xf86IsPc98())
2228	outb(0xFAC, 0xFE);
2229}
2230
2231/*
2232 * This is called at the end of each server generation.  It restores the
2233 * original (text) mode.  It should really also unmap the video memory too.
2234 */
2235
2236/* Mandatory */
2237static Bool
2238ApmCloseScreen(int scrnIndex, ScreenPtr pScreen)
2239{
2240    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2241    vgaHWPtr	hwp = VGAHWPTR(pScrn);
2242    APMDECL(pScrn);
2243
2244    if (pScrn->vtSema) {
2245	ApmRestore(pScrn, &hwp->SavedReg, &pApm->SavedReg);
2246	vgaHWLock(hwp);
2247	ApmUnmapMem(pScrn);
2248    }
2249    if(pApm->AccelInfoRec)
2250	XAADestroyInfoRec(pApm->AccelInfoRec);
2251    if(pApm->DGAXAAInfo)
2252	XAADestroyInfoRec(pApm->DGAXAAInfo);
2253    pApm->AccelInfoRec = NULL;
2254    if(pApm->CursorInfoRec)
2255	xf86DestroyCursorInfoRec(pApm->CursorInfoRec);
2256    pApm->CursorInfoRec = NULL;
2257    if (pApm->DGAModes)
2258	xfree(pApm->DGAModes);
2259    if (pApm->adaptor)
2260	xfree(pApm->adaptor);
2261
2262    pScrn->vtSema = FALSE;
2263
2264    if (xf86IsPc98())
2265	outb(0xFAC, 0xFE);
2266
2267    pScreen->CloseScreen = pApm->CloseScreen;
2268    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
2269}
2270
2271/* Free up any per-generation data structures */
2272
2273/* Optional */
2274static void
2275ApmFreeScreen(int scrnIndex, int flags)
2276{
2277    vgaHWFreeHWRec(xf86Screens[scrnIndex]);
2278    ApmFreeRec(xf86Screens[scrnIndex]);
2279}
2280
2281/* Checks if a mode is suitable for the selected chipset. */
2282
2283/* Optional */
2284static ModeStatus
2285ApmValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
2286{
2287    if (mode->Flags & V_INTERLACE)
2288	return(MODE_BAD);
2289
2290    return(MODE_OK);
2291}
2292
2293
2294/*
2295 * ApmDisplayPowerManagementSet --
2296 *
2297 * Sets VESA Display Power Management Signaling (DPMS) Mode.
2298 */
2299static void
2300ApmDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
2301			     int flags)
2302{
2303    APMDECL(pScrn);
2304    unsigned char dpmsreg, tmp;
2305
2306    if (PowerManagementMode < sizeof pApm->DPMSMask &&
2307	    PowerManagementMode >= 0)
2308	PowerManagementMode = pApm->DPMSMask[PowerManagementMode];
2309    switch (PowerManagementMode)
2310    {
2311    case DPMSModeOn:
2312	/* Screen: On; HSync: On, VSync: On */
2313	dpmsreg = 0x00;
2314	break;
2315    case DPMSModeStandby:
2316	/* Screen: Off; HSync: Off, VSync: On */
2317	dpmsreg = 0x01;
2318	break;
2319    case DPMSModeSuspend:
2320	/* Screen: Off; HSync: On, VSync: Off */
2321	dpmsreg = 0x02;
2322	break;
2323    case DPMSModeOff:
2324	/* Screen: Off; HSync: Off, VSync: Off */
2325	dpmsreg = 0x03;
2326	break;
2327    default:
2328	dpmsreg = 0;
2329    }
2330    if (pApm->noLinear) {
2331	tmp = RDXB_IOP(0xD0);
2332	WRXB_IOP(0xD0, (tmp & 0xFC) | dpmsreg);
2333    } else {
2334	tmp = RDXB(0xD0);
2335	WRXB(0xD0, (tmp & 0xFC) | dpmsreg);
2336    }
2337}
2338
2339static Bool
2340ApmSaveScreen(ScreenPtr pScreen, int mode)
2341{
2342    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2343    Bool unblank;
2344
2345    unblank = xf86IsUnblank(mode);
2346
2347    if (unblank)
2348	SetTimeSinceLastInputEvent();
2349
2350    if (pScrn->vtSema)
2351	vgaHWBlankScreen(pScrn, unblank);
2352    return TRUE;
2353}
2354
2355#ifdef APM_DEBUG
2356unsigned char _L_ACR(unsigned char *x);
2357unsigned char _L_ACR(unsigned char *x)
2358{
2359    return *x;
2360}
2361
2362unsigned short _L_ASR(unsigned short *x);
2363unsigned short _L_ASR(unsigned short *x)
2364{
2365    return *x;
2366}
2367
2368unsigned int _L_AIR(unsigned int *x);
2369unsigned int _L_AIR(unsigned int *x)
2370{
2371    return *x;
2372}
2373
2374void _L_ACW(char *x, char y);
2375void _L_ACW(char *x, char y)
2376{
2377    *x = y;
2378}
2379
2380void _L_ASW(short *x, short y);
2381void _L_ASW(short *x, short y)
2382{
2383    *x = y;
2384}
2385
2386void _L_AIW(int *x, int y);
2387void _L_AIW(int *x, int y)
2388{
2389    *x = y;
2390}
2391#endif
2392