tseng_driver.c revision 4b9470b1
1d983712dSmrg/*
2d983712dSmrg *
3d983712dSmrg * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
4d983712dSmrg *
5d983712dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
6d983712dSmrg * documentation for any purpose is hereby granted without fee, provided that
7d983712dSmrg * the above copyright notice appear in all copies and that both that
8d983712dSmrg * copyright notice and this permission notice appear in supporting
9d983712dSmrg * documentation, and that the name of Thomas Roell not be used in
10d983712dSmrg * advertising or publicity pertaining to distribution of the software without
11d983712dSmrg * specific, written prior permission.  Thomas Roell makes no representations
12d983712dSmrg * about the suitability of this software for any purpose.  It is provided
13d983712dSmrg * "as is" without express or implied warranty.
14d983712dSmrg *
15d983712dSmrg * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16d983712dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17d983712dSmrg * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18d983712dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19d983712dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20d983712dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21d983712dSmrg * PERFORMANCE OF THIS SOFTWARE.
22d983712dSmrg *
23d983712dSmrg * Author:  Thomas Roell, roell@informatik.tu-muenchen.de
24d983712dSmrg *          ET6000 and ET4000W32 16/24/32 bpp and acceleration support by Koen Gadeyne
25d983712dSmrg *
26d983712dSmrg * Large parts rewritten for XFree86 4.0 by Koen Gadeyne.
27d983712dSmrg */
28d983712dSmrg
29d983712dSmrg#ifdef HAVE_CONFIG_H
30d983712dSmrg#include "config.h"
31d983712dSmrg#endif
32d983712dSmrg
33d983712dSmrg/*** Generic includes ***/
34d983712dSmrg
35d983712dSmrg#include "tseng.h"		       /* this includes most of the generic ones as well */
36d983712dSmrg
374b9470b1Smrg#include "xf86PciInfo.h"
384b9470b1Smrg
39d983712dSmrg/* All drivers initialising the SW cursor need this */
40d983712dSmrg#include "mipointer.h"
41d983712dSmrg
42d983712dSmrg/* All drivers implementing backing store need this */
43d983712dSmrg#include "mibstore.h"
44d983712dSmrg
45d983712dSmrg#include "fb.h"
46d983712dSmrg
47d03ff4acSmrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
48d983712dSmrg#include "xf86RAC.h"
49d983712dSmrg#include "xf86Resources.h"
50d03ff4acSmrg#endif
51d983712dSmrg#include "xf86int10.h"
52d983712dSmrg
53d983712dSmrg#include "xf86xv.h"
54d983712dSmrg#include <X11/extensions/Xv.h>
55d983712dSmrg
56d983712dSmrg/*
57d983712dSmrg * Forward definitions for the functions that make up the driver.
58d983712dSmrg */
59d983712dSmrg
60d983712dSmrg/* Mandatory functions */
61d983712dSmrgstatic const OptionInfoRec * TsengAvailableOptions(int chipid, int busid);
62d983712dSmrgstatic void TsengIdentify(int flags);
63d983712dSmrgstatic Bool TsengProbe(DriverPtr drv, int flags);
64d983712dSmrgstatic Bool TsengPreInit(ScrnInfoPtr pScrn, int flags);
654b9470b1Smrgstatic Bool TsengScreenInit(SCREEN_INIT_ARGS_DECL);
664b9470b1Smrgstatic Bool TsengEnterVT(VT_FUNC_ARGS_DECL);
674b9470b1Smrgstatic void TsengLeaveVT(VT_FUNC_ARGS_DECL);
684b9470b1Smrgstatic Bool TsengCloseScreen(CLOSE_SCREEN_ARGS_DECL);
69d983712dSmrgstatic Bool TsengSaveScreen(ScreenPtr pScreen, int mode);
70d983712dSmrg
71d983712dSmrg/* Required if the driver supports mode switching */
724b9470b1Smrgstatic Bool TsengSwitchMode(SWITCH_MODE_ARGS_DECL);
73d983712dSmrg
74d983712dSmrg/* Optional functions */
754b9470b1Smrgstatic void TsengFreeScreen(FREE_SCREEN_ARGS_DECL);
76d983712dSmrg
77d983712dSmrg/* If driver-specific config file entries are needed, this must be defined */
78d983712dSmrg/*static Bool   TsengParseConfig(ParseInfoPtr raw); */
79d983712dSmrg
80d983712dSmrg/* Internally used functions (some are defined in tseng.h) */
81d983712dSmrgstatic Bool TsengMapMem(ScrnInfoPtr pScrn);
82d983712dSmrgstatic Bool TsengUnmapMem(ScrnInfoPtr pScrn);
83d983712dSmrgstatic void TsengUnlock(ScrnInfoPtr pScrn);
84d983712dSmrgstatic void TsengLock(ScrnInfoPtr pScrn);
85d983712dSmrg
86d983712dSmrg/*
87d983712dSmrg * This is intentionally screen-independent.  It indicates the binding
88d983712dSmrg * choice made in the first PreInit.
89d983712dSmrg */
90d983712dSmrgstatic int pix24bpp = 0;
91d983712dSmrg
92d983712dSmrg#define TSENG_NAME "TSENG"
93d983712dSmrg#define TSENG_DRIVER_NAME "tseng"
94d983712dSmrg#define TSENG_MAJOR_VERSION 1
95d983712dSmrg#define TSENG_MINOR_VERSION 1
96d983712dSmrg#define TSENG_PATCHLEVEL 0
97d983712dSmrg#define TSENG_VERSION (TSENG_MAJOR_VERSION << 24) | (TSENG_MINOR_VERSION << 16) | TSENG_PATCHLEVEL
98d983712dSmrg
99d983712dSmrg/* CRTC timing limits */
100d983712dSmrg#define Tseng_HMAX (4096-8)
101d983712dSmrg#define Tseng_VMAX (2048-1)
102d983712dSmrg
103d983712dSmrg/*
104d983712dSmrg * This contains the functions needed by the server after loading the
105d983712dSmrg * driver module.  It must be supplied, and gets added the driver list by
106d983712dSmrg * the Module Setup funtion in the dynamic case.  In the static case a
107d983712dSmrg * reference to this is compiled in, and this requires that the name of
108d983712dSmrg * this DriverRec be an upper-case version of the driver name.
109d983712dSmrg */
110d983712dSmrg
111d983712dSmrg_X_EXPORT DriverRec TSENG =
112d983712dSmrg{
113d983712dSmrg    TSENG_VERSION,
114d983712dSmrg    TSENG_DRIVER_NAME,
115d983712dSmrg    TsengIdentify,
116d983712dSmrg    TsengProbe,
117d983712dSmrg    TsengAvailableOptions,
118d983712dSmrg    NULL,
119d983712dSmrg    0
120d983712dSmrg};
121d983712dSmrg
122d983712dSmrg/* sub-revisions are now dealt with in the ChipRev variable */
123d983712dSmrgstatic SymTabRec TsengChipsets[] =
124d983712dSmrg{
125d983712dSmrg    {ET4000, "ET4000W32p"},
126d983712dSmrg    {ET6000, "ET6000"},
127d983712dSmrg    {-1, NULL}
128d983712dSmrg};
129d983712dSmrg
130d983712dSmrg/* Convert PCI ID to chipset name */
131d983712dSmrgstatic PciChipsets TsengPciChipsets[] =
132d983712dSmrg{
133d983712dSmrg    {ET4000, PCI_CHIP_ET4000_W32P_A, RES_SHARED_VGA},
134d983712dSmrg    {ET4000, PCI_CHIP_ET4000_W32P_B, RES_SHARED_VGA},
135d983712dSmrg    {ET4000, PCI_CHIP_ET4000_W32P_C, RES_SHARED_VGA},
136d983712dSmrg    {ET4000, PCI_CHIP_ET4000_W32P_D, RES_SHARED_VGA},
137d983712dSmrg    {ET6000, PCI_CHIP_ET6000,        RES_SHARED_VGA},
138d983712dSmrg    {-1,     -1,                     RES_UNDEFINED}
139d983712dSmrg};
140d983712dSmrg
141d983712dSmrgtypedef enum {
142d983712dSmrg    OPTION_HIBIT_HIGH,
143d983712dSmrg    OPTION_HIBIT_LOW,
144d983712dSmrg    OPTION_SW_CURSOR,
145d983712dSmrg    OPTION_HW_CURSOR,
146d983712dSmrg    OPTION_PCI_BURST,
147d983712dSmrg    OPTION_SLOW_DRAM,
148d983712dSmrg    OPTION_MED_DRAM,
149d983712dSmrg    OPTION_FAST_DRAM,
150d983712dSmrg    OPTION_W32_INTERLEAVE,
151d983712dSmrg    OPTION_NOACCEL,
152d983712dSmrg    OPTION_SHOWCACHE,
153d983712dSmrg    OPTION_PCI_RETRY
154d983712dSmrg} TsengOpts;
155d983712dSmrg
156d983712dSmrgstatic const OptionInfoRec TsengOptions[] =
157d983712dSmrg{
158d983712dSmrg    {OPTION_HIBIT_HIGH, "hibit_high", OPTV_BOOLEAN,
159d983712dSmrg	{0}, FALSE},
160d983712dSmrg    {OPTION_HIBIT_LOW, "hibit_low", OPTV_BOOLEAN,
161d983712dSmrg	{0}, FALSE},
162d983712dSmrg    {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN,
163d983712dSmrg	{0}, FALSE},
164d983712dSmrg    {OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN,
165d983712dSmrg	{0}, FALSE},
166d983712dSmrg    {OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN,
167d983712dSmrg	{0}, FALSE},
168d983712dSmrg    {OPTION_SLOW_DRAM, "slow_dram", OPTV_BOOLEAN,
169d983712dSmrg	{0}, FALSE},
170d983712dSmrg    {OPTION_MED_DRAM, "med_dram", OPTV_BOOLEAN,
171d983712dSmrg	{0}, FALSE},
172d983712dSmrg    {OPTION_FAST_DRAM, "fast_dram", OPTV_BOOLEAN,
173d983712dSmrg	{0}, FALSE},
174d983712dSmrg    {OPTION_W32_INTERLEAVE, "w32_interleave", OPTV_BOOLEAN,
175d983712dSmrg	{0}, FALSE},
176d983712dSmrg    {OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN,
177d983712dSmrg	{0}, FALSE},
178d983712dSmrg    {OPTION_SHOWCACHE, "ShowCache", OPTV_BOOLEAN,
179d983712dSmrg	{0}, FALSE},
180d983712dSmrg    {OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN,
181d983712dSmrg	{0}, FALSE},
182d983712dSmrg    {-1, NULL, OPTV_NONE,
183d983712dSmrg	{0}, FALSE}
184d983712dSmrg};
185d983712dSmrg
186d983712dSmrg#ifdef XFree86LOADER
187d983712dSmrg
188d983712dSmrgstatic MODULESETUPPROTO(tsengSetup);
189d983712dSmrg
190d983712dSmrgstatic XF86ModuleVersionInfo tsengVersRec =
191d983712dSmrg{
192d983712dSmrg    "tseng",
193d983712dSmrg    MODULEVENDORSTRING,
194d983712dSmrg    MODINFOSTRING1,
195d983712dSmrg    MODINFOSTRING2,
196d983712dSmrg    XORG_VERSION_CURRENT,
197d983712dSmrg    TSENG_MAJOR_VERSION, TSENG_MINOR_VERSION, TSENG_PATCHLEVEL,
198d983712dSmrg    ABI_CLASS_VIDEODRV,		       /* This is a video driver */
199d983712dSmrg    ABI_VIDEODRV_VERSION,
200d983712dSmrg    MOD_CLASS_VIDEODRV,
201d983712dSmrg    {0, 0, 0, 0}
202d983712dSmrg};
203d983712dSmrg
204d983712dSmrg/*
205d983712dSmrg * This is the module init data for XFree86 modules.
206d983712dSmrg *
207d983712dSmrg * Its name has to be the driver name followed by ModuleData.
208d983712dSmrg */
209d983712dSmrg_X_EXPORT XF86ModuleData tsengModuleData = { &tsengVersRec, tsengSetup, NULL };
210d983712dSmrg
211d983712dSmrgstatic pointer
212d983712dSmrgtsengSetup(pointer module, pointer opts, int *errmaj, int *errmin)
213d983712dSmrg{
214d983712dSmrg    static Bool setupDone = FALSE;
215d983712dSmrg
216d983712dSmrg    if (!setupDone) {
217d983712dSmrg	setupDone = TRUE;
218d983712dSmrg	xf86AddDriver(&TSENG, module, 0);
219d983712dSmrg
220d983712dSmrg	/*
221d983712dSmrg	 * The return value must be non-NULL on success even though there
222d983712dSmrg	 * is no TearDownProc.
223d983712dSmrg	 */
224d983712dSmrg	return (pointer) 1;
225d983712dSmrg    } else {
226d983712dSmrg	if (errmaj)
227d983712dSmrg	    *errmaj = LDR_ONCEONLY;
228d983712dSmrg	return NULL;
229d983712dSmrg    }
230d983712dSmrg}
231d983712dSmrg
232d983712dSmrg#endif /* XFree86LOADER */
233d983712dSmrg
234d983712dSmrgstatic Bool
235d983712dSmrgTsengGetRec(ScrnInfoPtr pScrn)
236d983712dSmrg{
237d983712dSmrg    TsengPtr pTseng;
238d983712dSmrg
239d983712dSmrg    PDEBUG("	TsengGetRec\n");
240d983712dSmrg
241d983712dSmrg    /*
242d983712dSmrg     * Allocate an TsengRec, and hook it into pScrn->driverPrivate.
243d983712dSmrg     * pScrn->driverPrivate is initialised to NULL, so we can check if
244d983712dSmrg     * the allocation has already been done.
245d983712dSmrg     */
246d983712dSmrg    if (pScrn->driverPrivate != NULL)
247d983712dSmrg	return TRUE;
248d983712dSmrg
249d983712dSmrg    pScrn->driverPrivate = xnfcalloc(sizeof(TsengRec), 1);
250d983712dSmrg
251d983712dSmrg
252d983712dSmrg    /* Initialise it here when needed (or possible) */
253d983712dSmrg    pTseng = TsengPTR(pScrn);
254d983712dSmrg
255d983712dSmrg    pTseng->SavedReg.RAMDAC = NULL;
256d983712dSmrg
257d983712dSmrg    return TRUE;
258d983712dSmrg}
259d983712dSmrg
260d983712dSmrgstatic void
261d983712dSmrgTsengFreeRec(ScrnInfoPtr pScrn)
262d983712dSmrg{
263d983712dSmrg    TsengPtr pTseng;
264d983712dSmrg
265d983712dSmrg    PDEBUG("	TsengFreeRec\n");
266d983712dSmrg
267d983712dSmrg    if (pScrn->driverPrivate == NULL)
268d983712dSmrg	return;
269d983712dSmrg
270d983712dSmrg    pTseng = TsengPTR(pScrn);
271d983712dSmrg
272d983712dSmrg    if (pTseng->SavedReg.RAMDAC)
2734b9470b1Smrg        free(pTseng->SavedReg.RAMDAC);
274d983712dSmrg
2754b9470b1Smrg    free(pScrn->driverPrivate);
276d983712dSmrg    pScrn->driverPrivate = NULL;
277d983712dSmrg}
278d983712dSmrg
279d983712dSmrgstatic const OptionInfoRec *
280d983712dSmrgTsengAvailableOptions(int chipid, int busid)
281d983712dSmrg{
282d983712dSmrg    return TsengOptions;
283d983712dSmrg}
284d983712dSmrg
285d983712dSmrgstatic void
286d983712dSmrgTsengIdentify(int flags)
287d983712dSmrg{
288d983712dSmrg    xf86Msg(X_INFO, TSENG_NAME ": driver for TsengLabs ET4000W32p, ET6000 and"
289d983712dSmrg            " ET6100 chips.\n");
290d983712dSmrg}
291d983712dSmrg
292d983712dSmrg/* unlock ET4000 using KEY register */
293d983712dSmrgstatic void
294d983712dSmrgTsengUnlock(ScrnInfoPtr pScrn)
295d983712dSmrg{
296d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
297d983712dSmrg    CARD8 tmp;
298d983712dSmrg
299d983712dSmrg    PDEBUG("	TsengUnlock\n");
300d983712dSmrg
301d983712dSmrg    vgaHWHerculesSecondPage(hwp, TRUE);
302d983712dSmrg    vgaHWWriteModeControl(hwp, 0xA0);
303d983712dSmrg
304d983712dSmrg    tmp = hwp->readCrtc(hwp, 0x11);
305d983712dSmrg    hwp->writeCrtc(hwp, 0x11, tmp & 0x7F);
306d983712dSmrg}
307d983712dSmrg
308d983712dSmrg/* lock ET4000 using KEY register. FIXME: should restore old lock status instead */
309d983712dSmrgstatic void
310d983712dSmrgTsengLock(ScrnInfoPtr pScrn)
311d983712dSmrg{
312d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
313d983712dSmrg    CARD8 tmp;
314d983712dSmrg
315d983712dSmrg    PDEBUG("	TsengLock\n");
316d983712dSmrg
317d983712dSmrg    tmp = hwp->readCrtc(hwp, 0x11);
318d983712dSmrg    hwp->writeCrtc(hwp, 0x11, tmp | 0x80);
319d983712dSmrg
320d983712dSmrg    vgaHWWriteModeControl(hwp, 0x00);
321d983712dSmrg    vgaHWWriteModeControl(hwp, 0x29);
322d983712dSmrg    vgaHWHerculesSecondPage(hwp, FALSE);
323d983712dSmrg}
324d983712dSmrg
325d983712dSmrgstatic Bool
326d983712dSmrgTsengProbe(DriverPtr drv, int flags)
327d983712dSmrg{
328d983712dSmrg    int i;
329d983712dSmrg    GDevPtr *devSections;
330d983712dSmrg    int numDevSections;
331d983712dSmrg    int numUsed;
332d983712dSmrg    int *usedChips = NULL;
333d983712dSmrg    Bool foundScreen = FALSE;
334d983712dSmrg
335d983712dSmrg
336d983712dSmrg    PDEBUG("	TsengProbe\n");
337d983712dSmrg    /*
338d983712dSmrg     * The aim here is to find all cards that this driver can handle,
339d983712dSmrg     * and for the ones not already claimed by another driver, claim the
340d983712dSmrg     * slot, and allocate a ScrnInfoRec.
341d983712dSmrg     *
342d983712dSmrg     * This should be a minimal probe, and it should under no circumstances
343d983712dSmrg     * change the state of the hardware.  Because a device is found, don't
344d983712dSmrg     * assume that it will be used.  Don't do any initialisations other than
345d983712dSmrg     * the required ScrnInfoRec initialisations.  Don't allocate any new
346d983712dSmrg     * data structures.
347d983712dSmrg     */
348d983712dSmrg
349d983712dSmrg    /*
350d983712dSmrg     * Find the config file Device sections that match this
351d983712dSmrg     * driver, and return if there are none.
352d983712dSmrg     */
353d983712dSmrg    if ((numDevSections = xf86MatchDevice(TSENG_DRIVER_NAME,
354d983712dSmrg		&devSections)) <= 0) {
355d983712dSmrg	return FALSE;
356d983712dSmrg    }
357d983712dSmrg
358962c3257Smrg#ifndef XSERVER_LIBPCIACCESS
359d983712dSmrg    /* PCI only driver now. */
360d983712dSmrg    if (!xf86GetPciVideoInfo())
361d983712dSmrg        return FALSE;
362962c3257Smrg#endif
363d983712dSmrg
364d983712dSmrg    /* XXX maybe this can go some time soon */
365d983712dSmrg    /*
366d983712dSmrg     * for the Tseng server, there can only be one matching
367d983712dSmrg     * device section. So issue a warning if more than one show up.
368d983712dSmrg     * Multiple Tseng cards in the same machine are not possible.
369d983712dSmrg     */
370d983712dSmrg    numUsed = xf86MatchPciInstances(TSENG_NAME, PCI_VENDOR_TSENG,
371d983712dSmrg                                    TsengChipsets, TsengPciChipsets,
372d983712dSmrg                                    devSections,numDevSections, drv,
373d983712dSmrg                                    &usedChips);
374d983712dSmrg    if (numUsed > 0) {
375d983712dSmrg        if (flags & PROBE_DETECT)
376d983712dSmrg            foundScreen = TRUE;
377d983712dSmrg        else for (i = 0; i < numUsed; i++) {
378d983712dSmrg            /* Allocate a ScrnInfoRec  */
379d983712dSmrg            ScrnInfoPtr pScrn = NULL;
380d983712dSmrg            if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
381d983712dSmrg                                             TsengPciChipsets,NULL,
382d983712dSmrg                                             NULL,NULL,NULL,NULL))) {
383d983712dSmrg                pScrn->driverVersion = TSENG_VERSION;
384d983712dSmrg                pScrn->driverName = TSENG_DRIVER_NAME;
385d983712dSmrg                pScrn->name = TSENG_NAME;
386d983712dSmrg                pScrn->Probe = TsengProbe;
387d983712dSmrg                pScrn->PreInit = TsengPreInit;
388d983712dSmrg                pScrn->ScreenInit = TsengScreenInit;
389d983712dSmrg                pScrn->SwitchMode = TsengSwitchMode;
390d983712dSmrg                pScrn->AdjustFrame = TsengAdjustFrame;
391d983712dSmrg                pScrn->EnterVT = TsengEnterVT;
392d983712dSmrg                pScrn->LeaveVT = TsengLeaveVT;
393d983712dSmrg                pScrn->FreeScreen = TsengFreeScreen;
394d983712dSmrg                pScrn->ValidMode = TsengValidMode;
395d983712dSmrg
396d983712dSmrg                foundScreen = TRUE;
397d983712dSmrg            }
398d983712dSmrg        }
3994b9470b1Smrg        free(usedChips);
400d983712dSmrg    }
401d983712dSmrg
4024b9470b1Smrg    free(devSections);
403d983712dSmrg    return foundScreen;
404d983712dSmrg}
405d983712dSmrg
406d983712dSmrg/* The PCI part of TsengPreInit() */
407d983712dSmrgstatic Bool
408d983712dSmrgTsengPreInitPCI(ScrnInfoPtr pScrn)
409d983712dSmrg{
410d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
411d983712dSmrg
412d983712dSmrg    PDEBUG("	TsengPreInitPCI\n");
413d983712dSmrg
414d983712dSmrg    /* This is PCI, we should be able to trust it */
415d983712dSmrg
416d983712dSmrg    /* Set up ChipType, ChipRev and pScrn->chipset.
417d983712dSmrg     * This last one is usually not done manually, but
418d983712dSmrg     * it's for informative use only anyway. */
419962c3257Smrg    switch (PCI_DEV_DEVICE_ID(pTseng->PciInfo)) {
420d983712dSmrg    case PCI_CHIP_ET4000_W32P_A:
421d983712dSmrg	pTseng->ChipType = ET4000;
422d983712dSmrg	pTseng->ChipRev = REV_A;
423d983712dSmrg        pScrn->chipset = "ET4000/W32P (rev A)";
424d983712dSmrg	break;
425d983712dSmrg    case PCI_CHIP_ET4000_W32P_B:
426d983712dSmrg	pTseng->ChipType = ET4000;
427d983712dSmrg	pTseng->ChipRev = REV_B;
428d983712dSmrg	pScrn->chipset = "ET4000/W32P (rev B)";
429d983712dSmrg        break;
430d983712dSmrg    case PCI_CHIP_ET4000_W32P_C:
431d983712dSmrg	pTseng->ChipType = ET4000;
432d983712dSmrg	pTseng->ChipRev = REV_C;
433d983712dSmrg        pScrn->chipset = "ET4000/W32P (rev C)";
434d983712dSmrg	break;
435d983712dSmrg    case PCI_CHIP_ET4000_W32P_D:
436d983712dSmrg	pTseng->ChipType = ET4000;
437d983712dSmrg	pTseng->ChipRev = REV_D;
438d983712dSmrg        pScrn->chipset = "ET4000/W32P (rev D)";
439d983712dSmrg	break;
440d983712dSmrg    case PCI_CHIP_ET6000:
441d983712dSmrg	pTseng->ChipType = ET6000;
442d983712dSmrg
443962c3257Smrg        if (PCI_DEV_REVISION(pTseng->PciInfo) < 0x70) {
444d983712dSmrg            pScrn->chipset = "ET6000";
445d983712dSmrg            pTseng->ChipRev = REV_ET6000;
446d983712dSmrg        } else {
447d983712dSmrg            pScrn->chipset = "ET6100";
448d983712dSmrg            pTseng->ChipRev = REV_ET6100;
449d983712dSmrg        }
450d983712dSmrg	break;
451d983712dSmrg    default:
452d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unknown Tseng PCI ID: %X\n",
453962c3257Smrg                   PCI_DEV_DEVICE_ID(pTseng->PciInfo));
454d983712dSmrg	return FALSE;
455d983712dSmrg    }
456d983712dSmrg
457d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chipset: \"%s\"\n", pScrn->chipset);
458d983712dSmrg
459962c3257Smrg#ifndef XSERVER_LIBPCIACCESS
460d983712dSmrg    pTseng->PciTag = pciTag(pTseng->PciInfo->bus, pTseng->PciInfo->device,
461d983712dSmrg	pTseng->PciInfo->func);
462962c3257Smrg#endif
463d983712dSmrg
464d983712dSmrg    /* only the ET6000 implements a PCI IO address */
465d983712dSmrg    if (pTseng->ChipType == ET6000) {
466962c3257Smrg        if (!PCI_REGION_BASE(pTseng->PciInfo, 1, REGION_IO)) {
467d983712dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
468d983712dSmrg                       "No valid PCI I/O address in PCI config space\n");
469d983712dSmrg            return FALSE;
470d983712dSmrg        }
471d983712dSmrg
472962c3257Smrg        pTseng->ET6000IOAddress = PCI_REGION_BASE(pTseng->PciInfo, 1, REGION_IO);
473d983712dSmrg
474d983712dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "ET6000 PCI I/O registers at 0x%lX\n",
475d983712dSmrg                   (unsigned long)pTseng->ET6000IOAddress);
476d983712dSmrg    }
477d983712dSmrg
478d983712dSmrg    return TRUE;
479d983712dSmrg}
480d983712dSmrg
481d983712dSmrg/*
482d983712dSmrg * The 8*32kb ET6000 MDRAM granularity causes the more general probe to
483d983712dSmrg * detect too much memory in some configurations, because that code has a
484d983712dSmrg * 8-bank (=256k) granularity. E.g. it fails to recognize 2.25 MB of memory
485d983712dSmrg * (detects 2.5 instead). This function goes to check if the RAM is actually
486d983712dSmrg * there. MDRAM comes in multiples of 4 banks (16, 24, 32, 36, 40, 64, 72,
487d983712dSmrg * 80, ... 32kb-banks), so checking each 64k block should be enough granularity.
488d983712dSmrg *
489d983712dSmrg * No more than the amount of refreshed RAM is checked. Non-refreshed RAM
490d983712dSmrg * won't work anyway.
491d983712dSmrg *
492d983712dSmrg * The same code could be used on other Tseng chips, or even on ANY
493d983712dSmrg * VGA board, but probably only in case of trouble.
494d983712dSmrg *
495d983712dSmrg * FIXME: this should be done using linear memory
496d983712dSmrg */
497d983712dSmrg#define VIDMEM ((volatile CARD32*)check_vgabase)
498d983712dSmrg#define SEGSIZE (64)		       /* kb */
499d983712dSmrg
500d983712dSmrg#define ET6K_SETSEG(seg) \
501d983712dSmrg    vgaHWWriteBank(hwp, ((seg) & 0x30) | ((seg) >> 4));\
502d983712dSmrg    vgaHWWriteSegment(hwp, ((seg) & 0x0f) | ((seg) << 4));
503d983712dSmrg
504d983712dSmrgstatic int
505d983712dSmrget6000_check_videoram(ScrnInfoPtr pScrn, int ram)
506d983712dSmrg{
507d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
508d983712dSmrg    unsigned char oldSegSel1, oldSegSel2, oldGR5, oldGR6, oldSEQ2, oldSEQ4;
509d983712dSmrg    int segment, i;
510d983712dSmrg    int real_ram = 0;
511d983712dSmrg    pointer check_vgabase;
512d983712dSmrg    Bool fooled = FALSE;
513d983712dSmrg    int save_vidmem;
514d983712dSmrg
515d983712dSmrg    PDEBUG("	et6000_check_videoram\n");
516d983712dSmrg    if (ram > 4096) {
517d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
518d983712dSmrg	    "Detected more than 4096 kb of video RAM. Clipped to 4096kb\n");
519d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
520d983712dSmrg	    "    (Tseng VGA chips can only use 4096kb).\n");
521d983712dSmrg	ram = 4096;
522d983712dSmrg    }
523d983712dSmrg    if (!vgaHWMapMem(pScrn)) {
524d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
525d983712dSmrg	    "Could not map VGA memory to check for video memory.\n");
526d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
527d983712dSmrg	    "    Detected amount may be wrong.\n");
528d983712dSmrg	return ram;
529d983712dSmrg    }
530d983712dSmrg    check_vgabase = (VGAHWPTR(pScrn)->Base);
531d983712dSmrg
532d983712dSmrg    /*
533d983712dSmrg     * We need to set the VGA controller in VGA graphics mode, or else we won't
534d983712dSmrg     * be able to access the full 4MB memory range. First, we save the
535d983712dSmrg     * registers we modify, of course.
536d983712dSmrg     */
537d983712dSmrg
538d983712dSmrg    oldSegSel1 = vgaHWReadSegment(hwp);
539d983712dSmrg    oldSegSel2 = vgaHWReadBank(hwp);
540d983712dSmrg
541d983712dSmrg    oldGR5 = hwp->readGr(hwp, 0x05);
542d983712dSmrg    oldGR6 = hwp->readGr(hwp, 0x06);
543d983712dSmrg
544d983712dSmrg    oldSEQ2 = hwp->readSeq(hwp, 0x02);
545d983712dSmrg    oldSEQ4 = hwp->readSeq(hwp, 0x04);
546d983712dSmrg
547d983712dSmrg    /* set graphics mode */
548d983712dSmrg    hwp->writeGr(hwp, 0x06, 0x05);
549d983712dSmrg    hwp->writeGr(hwp, 0x05, 0x40);
550d983712dSmrg    hwp->writeSeq(hwp, 0x02, 0x0F);
551d983712dSmrg    hwp->writeSeq(hwp, 0x04, 0x0E);
552d983712dSmrg
553d983712dSmrg    /*
554d983712dSmrg     * count down from presumed amount of memory in SEGSIZE steps, and
555d983712dSmrg     * look at each segment for real RAM.
556d983712dSmrg     *
557d983712dSmrg     * To select a segment, we cannot use ET4000W32SetReadWrite(), since
558d983712dSmrg     * that requires the ScreenPtr, which we don't have here.
559d983712dSmrg     */
560d983712dSmrg
561d983712dSmrg    for (segment = (ram / SEGSIZE) - 1; segment >= 0; segment--) {
562d983712dSmrg	/* select the segment */
563d983712dSmrg	ET6K_SETSEG(segment);
564d983712dSmrg
565d983712dSmrg	/* save contents of memory probing location */
566d983712dSmrg	save_vidmem = *(VIDMEM);
567d983712dSmrg
568d983712dSmrg	/* test with pattern */
569d983712dSmrg	*VIDMEM = 0xAAAA5555;
570d983712dSmrg	if (*VIDMEM != 0xAAAA5555) {
571d983712dSmrg	    *VIDMEM = save_vidmem;
572d983712dSmrg	    continue;
573d983712dSmrg	}
574d983712dSmrg	/* test with inverted pattern */
575d983712dSmrg	*VIDMEM = 0x5555AAAA;
576d983712dSmrg	if (*VIDMEM != 0x5555AAAA) {
577d983712dSmrg	    *VIDMEM = save_vidmem;
578d983712dSmrg	    continue;
579d983712dSmrg	}
580d983712dSmrg	/*
581d983712dSmrg	 * If we get here, the memory seems to be writable/readable
582d983712dSmrg	 * Now check if we aren't fooled by address wrapping (mirroring)
583d983712dSmrg	 */
584d983712dSmrg	fooled = FALSE;
585d983712dSmrg	for (i = segment - 1; i >= 0; i--) {
586d983712dSmrg	    /* select the segment */
587d983712dSmrg	    ET6K_SETSEG(i);
588d983712dSmrg
589d983712dSmrg            /* again? */
590d983712dSmrg	    vgaHWWriteBank(hwp, (i & 0x30) | (i >> 4));
591d983712dSmrg	    vgaHWWriteSegment(hwp, (i & 0x0f) | (i << 4));
592d983712dSmrg
593d983712dSmrg	    if (*VIDMEM == 0x5555AAAA) {
594d983712dSmrg		/*
595d983712dSmrg		 * Seems like address wrap, but there could of course be
596d983712dSmrg		 * 0x5555AAAA in here by accident, so we check with another
597d983712dSmrg		 * pattern again.
598d983712dSmrg		 */
599d983712dSmrg		ET6K_SETSEG(segment);
600d983712dSmrg		/* test with other pattern again */
601d983712dSmrg		*VIDMEM = 0xAAAA5555;
602d983712dSmrg		ET6K_SETSEG(i);
603d983712dSmrg		if (*VIDMEM == 0xAAAA5555) {
604d983712dSmrg		    /* now we're sure: this is not real memory */
605d983712dSmrg		    fooled = TRUE;
606d983712dSmrg		    break;
607d983712dSmrg		}
608d983712dSmrg	    }
609d983712dSmrg	}
610d983712dSmrg	if (!fooled) {
611d983712dSmrg	    real_ram = (segment + 1) * SEGSIZE;
612d983712dSmrg	    break;
613d983712dSmrg	}
614d983712dSmrg	/* restore old contents again */
615d983712dSmrg	ET6K_SETSEG(segment);
616d983712dSmrg	*VIDMEM = save_vidmem;
617d983712dSmrg    }
618d983712dSmrg
619d983712dSmrg    /* restore original register contents */
620d983712dSmrg    vgaHWWriteSegment(hwp, oldSegSel1);
621d983712dSmrg    vgaHWWriteBank(hwp, oldSegSel2);
622d983712dSmrg
623d983712dSmrg    hwp->writeGr(hwp, 0x05, oldGR5);
624d983712dSmrg    hwp->writeGr(hwp, 0x06, oldGR6);
625d983712dSmrg    hwp->writeSeq(hwp, 0x02, oldSEQ2);
626d983712dSmrg    hwp->writeSeq(hwp, 0x04, oldSEQ4);
627d983712dSmrg
628d983712dSmrg    vgaHWUnmapMem(pScrn);
629d983712dSmrg    return real_ram;
630d983712dSmrg}
631d983712dSmrg
632d983712dSmrg/*
633d983712dSmrg * Handle amount of allowed memory: some combinations can't use all
634d983712dSmrg * available memory. Should we still allow the user to override this?
635d983712dSmrg *
636d983712dSmrg * This must be called AFTER the decision has been made to use linear mode
637d983712dSmrg * and/or acceleration, or the memory limit code won't be able to work.
638d983712dSmrg */
639d983712dSmrg
640d983712dSmrgstatic int
641d983712dSmrgTsengDoMemLimit(ScrnInfoPtr pScrn, int ram, int limit, char *reason)
642d983712dSmrg{
643d983712dSmrg    if (ram > limit) {
644d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Only %d kb of memory can be used %s.\n",
645d983712dSmrg	    limit, reason);
646d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Reducing video memory to %d kb.\n", limit);
647d983712dSmrg	ram = limit;
648d983712dSmrg    }
649d983712dSmrg    return ram;
650d983712dSmrg}
651d983712dSmrg
652d983712dSmrgstatic int
653d983712dSmrgTsengLimitMem(ScrnInfoPtr pScrn, int ram)
654d983712dSmrg{
655d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
656d983712dSmrg
657d983712dSmrg    if (pTseng->UseAccel) {
658d983712dSmrg	if (pTseng->ChipType == ET4000) {
659d983712dSmrg	    /* <= W32p_ab :
660d983712dSmrg	     *   2 MB direct access + 2*512kb via apertures MBP0 and MBP1
661d983712dSmrg	     * == W32p_cd :
662d983712dSmrg	     *   2*1MB via apertures MBP0 and MBP1
663d983712dSmrg	     */
664d983712dSmrg	    if ((pTseng->ChipRev == REV_C) || (pTseng->ChipRev == REV_D))
665d983712dSmrg		ram = TsengDoMemLimit(pScrn, ram, 2048,
666d983712dSmrg				      "in linear + accelerated mode "
667d983712dSmrg				      "on W32p rev c and d");
668d983712dSmrg
669d983712dSmrg	    ram = TsengDoMemLimit(pScrn, ram, 2048 + 1024,
670d983712dSmrg				  "in linear + accelerated mode "
671d983712dSmrg				  "on W32/W32i/W32p");
672d983712dSmrg
673d983712dSmrg	    /*
674d983712dSmrg	     * upper 516kb of 4MB linear map used for
675d983712dSmrg	     *  "externally mapped registers"
676d983712dSmrg	     */
677d983712dSmrg	    ram = TsengDoMemLimit(pScrn, ram, 4096 - 516,
678d983712dSmrg				  "in linear + accelerated mode "
679d983712dSmrg				  "on W32/W32i/W32p");
680d983712dSmrg	} else {
681d983712dSmrg	    /*
682d983712dSmrg	     * upper 8kb used for externally mapped and
683d983712dSmrg	     * memory mapped registers
684d983712dSmrg	     */
685d983712dSmrg	    ram = TsengDoMemLimit(pScrn, ram, 4096 - 8,
686d983712dSmrg				  "in linear + accelerated mode "
687d983712dSmrg				  "on ET6000/6100");
688d983712dSmrg	}
689d983712dSmrg    }
690d983712dSmrg    ram = TsengDoMemLimit(pScrn, ram, 4096, "on any Tseng card");
691d983712dSmrg    return ram;
692d983712dSmrg}
693d983712dSmrg
694d983712dSmrg/*
695d983712dSmrg * TsengDetectMem --
696d983712dSmrg *      try to find amount of video memory installed.
697d983712dSmrg *
698d983712dSmrg */
699d983712dSmrgstatic int
700d983712dSmrgTsengDetectMem(ScrnInfoPtr pScrn)
701d983712dSmrg{
702d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
703d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
704d983712dSmrg    unsigned char config;
705d983712dSmrg    int ramtype = 0;
706d983712dSmrg    int ram = 0;
707d983712dSmrg
708d983712dSmrg    PDEBUG("	TsengDetectMem\n");
709d983712dSmrg    if (pTseng->ChipType == ET6000) {
710d983712dSmrg	ramtype = hwp->readST00(hwp) & 0x03;
711d983712dSmrg	switch (ramtype) {
712d983712dSmrg	case 0x03:		       /* MDRAM */
713d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
714d983712dSmrg		"Video memory type: Multibank DRAM (MDRAM).\n");
715d983712dSmrg	    ram = ((ET6000IORead(pTseng, 0x47) & 0x07) + 1) * 8 * 32;	/* number of 8 32kb banks  */
716d983712dSmrg	    if (ET6000IORead(pTseng, 0x45) & 0x04) {
717d983712dSmrg		ram <<= 1;
718d983712dSmrg	    }
719d983712dSmrg	    /*
720d983712dSmrg	     * 8*32kb MDRAM refresh control granularity in the ET6000 fails to
721d983712dSmrg	     * recognize 2.25 MB of memory (detects 2.5 instead)
722d983712dSmrg	     */
723d983712dSmrg	    ram = et6000_check_videoram(pScrn, ram);
724d983712dSmrg	    break;
725d983712dSmrg	case 0x00:		       /* DRAM -- VERY unlikely on ET6000 cards, IMPOSSIBLE on ET6100 */
726d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
727d983712dSmrg		"Video memory type: Standard DRAM.\n");
728d983712dSmrg	    ram = 1024 << (ET6000IORead(pTseng, 0x45) & 0x03);
729d983712dSmrg	    break;
730d983712dSmrg	default:		       /* unknown RAM type */
731d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
732d983712dSmrg		"Unknown ET6000 video memory type %d -- assuming 1 MB (unless specified)\n",
733d983712dSmrg		ramtype);
734d983712dSmrg	    ram = 1024;
735d983712dSmrg	}
736d983712dSmrg    } else {
737d983712dSmrg	config = hwp->readCrtc(hwp, 0x37);
738d983712dSmrg
739d983712dSmrg	ram = 128 << (config & 0x03);
740d983712dSmrg
741d983712dSmrg	if (config & 0x80)
742d983712dSmrg	    ram <<= 1;
743d983712dSmrg
744d983712dSmrg	/* Check for interleaving on W32i/p. */
745d983712dSmrg        config = hwp->readCrtc(hwp, 0x32);
746d983712dSmrg        if (config & 0x80) {
747d983712dSmrg            ram <<= 1;
748d983712dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
749d983712dSmrg                       "Video memory type: Interleaved DRAM.\n");
750d983712dSmrg        } else {
751d983712dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
752d983712dSmrg                       "Video memory type: Standard DRAM.\n");
753d983712dSmrg        }
754d983712dSmrg    }
755d983712dSmrg    return ram;
756d983712dSmrg}
757d983712dSmrg
758d983712dSmrgstatic Bool
759d983712dSmrgTsengProcessHibit(ScrnInfoPtr pScrn)
760d983712dSmrg{
761d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
762d983712dSmrg    MessageType from = X_CONFIG;
763d983712dSmrg    int hibit_mode_width;
764d983712dSmrg
765d983712dSmrg    PDEBUG("	TsengProcessHibit\n");
766d983712dSmrg    if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_HIGH)) {
767d983712dSmrg	if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_LOW)) {
768d983712dSmrg	    xf86Msg(X_ERROR, "\nOptions \"hibit_high\" and \"hibit_low\" are incompatible;\n");
769d983712dSmrg	    xf86Msg(X_ERROR, "    specify only one (not both) in X configuration file\n");
770d983712dSmrg	    return FALSE;
771d983712dSmrg	}
772d983712dSmrg	pTseng->save_divide = 0x40;
773d983712dSmrg    } else if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_HIGH)) {
774d983712dSmrg	pTseng->save_divide = 0;
775d983712dSmrg    } else {
776d983712dSmrg        vgaHWPtr hwp = VGAHWPTR(pScrn);
777d983712dSmrg
778d983712dSmrg	from = X_PROBED;
779d983712dSmrg
780d983712dSmrg	/* first check to see if hibit is probed from low-res mode */
781d983712dSmrg	hibit_mode_width = hwp->readCrtc(hwp, 0x01) + 1;
782d983712dSmrg
783d983712dSmrg	if (hibit_mode_width > 82) {
784d983712dSmrg	    xf86Msg(X_WARNING, "Non-standard VGA text or graphics mode while probing for hibit:\n");
785d983712dSmrg	    xf86Msg(X_WARNING, "    probed 'hibit' value may be wrong.\n");
786d983712dSmrg	    xf86Msg(X_WARNING, "    Preferably run probe from 80x25 textmode,\n");
787d983712dSmrg	    xf86Msg(X_WARNING, "    or specify correct value in X configuration file.\n");
788d983712dSmrg	}
789d983712dSmrg
790d983712dSmrg	/* Check for initial state of divide flag */
791d983712dSmrg	pTseng->save_divide = hwp->readSeq(hwp, 0x07) & 0x40;
792d983712dSmrg    }
793d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "Initial ET4000 hibit state: %s\n",
794d983712dSmrg	pTseng->save_divide & 0x40 ? "high" : "low");
795d983712dSmrg    return TRUE;
796d983712dSmrg}
797d983712dSmrg
798d983712dSmrgstatic Bool
799d983712dSmrgTsengProcessOptions(ScrnInfoPtr pScrn)
800d983712dSmrg{
801d983712dSmrg    MessageType from;
802d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
803d983712dSmrg
804d983712dSmrg    PDEBUG("	TsengProcessOptions\n");
805d983712dSmrg
806d983712dSmrg    /* Collect all of the relevant option flags (fill in pScrn->options) */
807d983712dSmrg    xf86CollectOptions(pScrn, NULL);
808d983712dSmrg
809d983712dSmrg    /* Process the options */
8104b9470b1Smrg    if (!(pTseng->Options = malloc(sizeof(TsengOptions))))
811d983712dSmrg	return FALSE;
812d983712dSmrg    memcpy(pTseng->Options, TsengOptions, sizeof(TsengOptions));
813d983712dSmrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pTseng->Options);
814d983712dSmrg
815d983712dSmrg    from = X_DEFAULT;
816d983712dSmrg    pTseng->HWCursor = FALSE;	       /* default */
817d983712dSmrg    if (xf86GetOptValBool(pTseng->Options, OPTION_HW_CURSOR, &pTseng->HWCursor))
818d983712dSmrg	from = X_CONFIG;
819d983712dSmrg    if (xf86ReturnOptValBool(pTseng->Options, OPTION_SW_CURSOR, FALSE)) {
820d983712dSmrg	from = X_CONFIG;
821d983712dSmrg	pTseng->HWCursor = FALSE;
822d983712dSmrg    }
823d983712dSmrg    if ((pTseng->ChipType == ET4000) && pTseng->HWCursor) {
824d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, from,
825d983712dSmrg		"Hardware Cursor not supported on this chipset\n");
826d983712dSmrg	pTseng->HWCursor = FALSE;
827d983712dSmrg    }
828d983712dSmrg
829d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
830d983712dSmrg	pTseng->HWCursor ? "HW" : "SW");
831d983712dSmrg
832d983712dSmrg    if (pScrn->bitsPerPixel >= 8) {
833d983712dSmrg        pTseng->UseAccel = TRUE;
834d983712dSmrg	if (xf86ReturnOptValBool(pTseng->Options, OPTION_NOACCEL, FALSE)) {
835d983712dSmrg	    pTseng->UseAccel = FALSE;
836d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
837d983712dSmrg	}
838d983712dSmrg    } else
839d983712dSmrg	pTseng->UseAccel = FALSE;  /* 1bpp and 4bpp are always non-accelerated */
840d983712dSmrg
841d983712dSmrg    pTseng->SlowDram = FALSE;
842d983712dSmrg    if (xf86IsOptionSet(pTseng->Options, OPTION_SLOW_DRAM)) {
843d983712dSmrg	pTseng->SlowDram = TRUE;
844d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using slow DRAM access\n");
845d983712dSmrg    }
846d983712dSmrg    pTseng->MedDram = FALSE;
847d983712dSmrg    if (xf86IsOptionSet(pTseng->Options, OPTION_MED_DRAM)) {
848d983712dSmrg	pTseng->MedDram = TRUE;
849d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using Medium-speed DRAM access\n");
850d983712dSmrg    }
851d983712dSmrg    pTseng->FastDram = FALSE;
852d983712dSmrg    if (xf86IsOptionSet(pTseng->Options, OPTION_FAST_DRAM)) {
853d983712dSmrg	pTseng->FastDram = TRUE;
854d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using fast DRAM access\n");
855d983712dSmrg    }
856d983712dSmrg    if ((pTseng->SetW32Interleave =
857d983712dSmrg	xf86GetOptValBool(pTseng->Options, OPTION_W32_INTERLEAVE, &pTseng->W32Interleave)) )
858d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing W32p memory interleave %s.\n",
859d983712dSmrg	    pTseng->W32Interleave ? "ON" : "OFF");
860d983712dSmrg    if ((pTseng->SetPCIBurst =
861d983712dSmrg	xf86GetOptValBool(pTseng->Options, OPTION_PCI_BURST, &pTseng->PCIBurst)) )
862d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing PCI burst mode %s.\n",
863d983712dSmrg	    pTseng->PCIBurst ? "ON" : "OFF");
864d983712dSmrg
865d983712dSmrg    pTseng->ShowCache = FALSE;
866d983712dSmrg    if (xf86ReturnOptValBool(pTseng->Options, OPTION_SHOWCACHE, FALSE)) {
867d983712dSmrg	pTseng->ShowCache = TRUE;
868d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "(for debugging only:) Visible off-screen memory\n");
869d983712dSmrg    }
870d983712dSmrg
871d983712dSmrg    pTseng->UsePCIRetry = FALSE;
872d983712dSmrg    if (xf86ReturnOptValBool(pTseng->Options, OPTION_PCI_RETRY, FALSE)) {
873d983712dSmrg	pTseng->UsePCIRetry = TRUE;
874d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n");
875d983712dSmrg    }
876d983712dSmrg    return TRUE;
877d983712dSmrg}
878d983712dSmrg
879d983712dSmrgstatic Bool
880d983712dSmrgTsengGetFbAddress(ScrnInfoPtr pScrn)
881d983712dSmrg{
882d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
883d983712dSmrg
884d983712dSmrg    PDEBUG("	TsengGetFbAddress\n");
885d983712dSmrg
886d983712dSmrg    /* base0 is the framebuffer and base1 is the PCI IO space. */
8874b9470b1Smrg    if (!PCI_REGION_BASE(pTseng->PciInfo, 0, REGION_MEM)) {
888d983712dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
889d983712dSmrg                   "No valid Framebuffer address in PCI config space;\n");
890d983712dSmrg        return FALSE;
891d983712dSmrg    } else
892962c3257Smrg        pTseng->FbAddress = PCI_REGION_BASE(pTseng->PciInfo, 0, REGION_MEM);
893d983712dSmrg
894d983712dSmrg
895d03ff4acSmrg#ifndef XSERVER_LIBPCIACCESS
896d983712dSmrg    if (xf86RegisterResources(pTseng->pEnt->index,NULL,ResNone)) {
897d983712dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot register FB memory.\n");
898d983712dSmrg        return FALSE;
899d983712dSmrg    }
900d03ff4acSmrg#endif
901d983712dSmrg
902d983712dSmrg    /* The W32 linear map address space is always 4Mb (mainly because the
903d983712dSmrg     * memory-mapped registers are located near the top of the 4MB area).
904d983712dSmrg     * The ET6000 maps out 16 Meg, but still uses only 4Mb of that.
905d983712dSmrg     * However, since all mmap()-ed space is also reflected in the "ps"
906d983712dSmrg     * listing for the Xserver, many users will be worried by a server that
907d983712dSmrg     * always eats 16MB of memory, even if it's not "real" memory, just
908d983712dSmrg     * address space. Not mapping all of the 16M may be a potential problem
909d983712dSmrg     * though: if another board is mapped on top of the remaining part of
910d983712dSmrg     * the 16M... Boom!
911d983712dSmrg     */
912d983712dSmrg    if (pTseng->ChipType == ET6000)
913d983712dSmrg	pTseng->FbMapSize = 16384 * 1024;
914d983712dSmrg    else
915d983712dSmrg	pTseng->FbMapSize = 4096 * 1024;
916d983712dSmrg
917d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Framebuffer at 0x%lX\n",
918d983712dSmrg               (unsigned long)pTseng->FbAddress);
919d983712dSmrg
920d983712dSmrg    return TRUE;
921d983712dSmrg}
922d983712dSmrg
923d983712dSmrgstatic Bool
924d983712dSmrgTsengPreInit(ScrnInfoPtr pScrn, int flags)
925d983712dSmrg{
926d983712dSmrg    TsengPtr pTseng;
927d983712dSmrg    MessageType from;
928d983712dSmrg    int i;
929d983712dSmrg
930d983712dSmrg    if (flags & PROBE_DETECT) return FALSE;
931d983712dSmrg
932d983712dSmrg    PDEBUG("	TsengPreInit\n");
933d983712dSmrg
934d983712dSmrg    /*
935d983712dSmrg     * Note: This function is only called once at server startup, and
936d983712dSmrg     * not at the start of each server generation.  This means that
937d983712dSmrg     * only things that are persistent across server generations can
938d983712dSmrg     * be initialised here.  xf86Screens[] is (pScrn is a pointer to one
939d983712dSmrg     * of these).  Privates allocated using xf86AllocateScrnInfoPrivateIndex()
940d983712dSmrg     * are too, and should be used for data that must persist across
941d983712dSmrg     * server generations.
942d983712dSmrg     *
943d983712dSmrg     * Per-generation data should be allocated with
944d983712dSmrg     * AllocateScreenPrivateIndex() from the ScreenInit() function.
945d983712dSmrg     */
946d983712dSmrg
947d983712dSmrg    /* The vgahw module should be loaded here when needed */
948d983712dSmrg
949d983712dSmrg    /* This driver doesn't expect more than one entity per screen */
950d983712dSmrg    if (pScrn->numEntities > 1)
951d983712dSmrg	    return FALSE;
952d983712dSmrg
953d983712dSmrg    /* Allocate the TsengRec driverPrivate */
954d983712dSmrg    if (!TsengGetRec(pScrn)) {
955d983712dSmrg	return FALSE;
956d983712dSmrg    }
957d983712dSmrg    pTseng = TsengPTR(pScrn);
958d983712dSmrg
959d983712dSmrg    /* This is the general case */
960d983712dSmrg    pTseng->pEnt = xf86GetEntityInfo(*pScrn->entityList);
961d983712dSmrg
962d983712dSmrg#if 1
963d983712dSmrg    if (xf86LoadSubModule(pScrn, "int10")) {
964d983712dSmrg 	xf86Int10InfoPtr pInt;
965d983712dSmrg#if 1
966d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
967d983712dSmrg	pInt = xf86InitInt10(pTseng->pEnt->index);
968d983712dSmrg	xf86FreeInt10(pInt);
969d983712dSmrg#endif
970d983712dSmrg    }
971d983712dSmrg#endif
972d983712dSmrg
973d983712dSmrg    if (!xf86LoadSubModule(pScrn, "vgahw"))
974d983712dSmrg	return FALSE;
975d983712dSmrg    /*
976d983712dSmrg     * Allocate a vgaHWRec
977d983712dSmrg     */
978d983712dSmrg    if (!vgaHWGetHWRec(pScrn))
979d983712dSmrg	return FALSE;
980d983712dSmrg
981d983712dSmrg    vgaHWGetIOBase(VGAHWPTR(pScrn));
982d983712dSmrg    /*
983d983712dSmrg     * Since, the capabilities are determined by the chipset, the very first
984d983712dSmrg     * thing to do is to figure out the chipset and its capabilities.
985d983712dSmrg     */
986d983712dSmrg
987d983712dSmrg    TsengUnlock(pScrn);
988d983712dSmrg
989d983712dSmrg    pTseng->PciInfo = xf86GetPciInfoForEntity(pTseng->pEnt->index);
990d983712dSmrg    if (!TsengPreInitPCI(pScrn)) {
991d983712dSmrg        TsengFreeRec(pScrn);
992d983712dSmrg        return FALSE;
993d983712dSmrg    }
994d983712dSmrg
995d983712dSmrg    if (!TsengRAMDACProbe(pScrn)) {
996d983712dSmrg        TsengFreeRec(pScrn);
997d983712dSmrg	return FALSE;
998d983712dSmrg    }
999d983712dSmrg
1000d983712dSmrg    pScrn->progClock = TRUE;
1001d983712dSmrg
1002d983712dSmrg    /*
1003d983712dSmrg     * Now we can check what depth we support.
1004d983712dSmrg     */
1005d983712dSmrg
1006d983712dSmrg    /* Set pScrn->monitor */
1007d983712dSmrg    pScrn->monitor = pScrn->confScreen->monitor;
1008d983712dSmrg
1009d983712dSmrg    /*
1010d983712dSmrg     * The first thing we should figure out is the depth, bpp, etc.
1011d983712dSmrg     * Our default depth is 8, so pass it to the helper function.
1012d983712dSmrg     * Our preference for depth 24 is 24bpp, so tell it that too.
1013d983712dSmrg     */
1014d983712dSmrg    if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb | Support32bppFb |
1015d983712dSmrg                         SupportConvert32to24 | PreferConvert32to24)) {
1016d983712dSmrg	return FALSE;
1017d983712dSmrg    } else {
1018d983712dSmrg        switch (pScrn->depth) {
1019d983712dSmrg        case 8:
1020d983712dSmrg        case 16:
1021d983712dSmrg        case 24:
1022d983712dSmrg        case 32:
1023d983712dSmrg            /* OK */
1024d983712dSmrg            break;
1025d983712dSmrg        default:
1026d983712dSmrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1027d983712dSmrg                       "Given depth (%d) is not supported by this driver\n",
1028d983712dSmrg                       pScrn->depth);
1029d983712dSmrg            return FALSE;
1030d983712dSmrg        }
1031d983712dSmrg    }
1032d983712dSmrg    xf86PrintDepthBpp(pScrn);
1033d983712dSmrg
1034d983712dSmrg    /* Get the depth24 pixmap format */
1035d983712dSmrg    if (pScrn->depth == 24 && pix24bpp == 0)
1036d983712dSmrg	pix24bpp = xf86GetBppFromDepth(pScrn, 24);
1037d983712dSmrg
1038d983712dSmrg    if (pScrn->bitsPerPixel > 8)
1039d983712dSmrg	pTseng->Bytesperpixel = pScrn->bitsPerPixel / 8;
1040d983712dSmrg    else
1041d983712dSmrg	pTseng->Bytesperpixel = 1;  /* this is fake for < 8bpp, but simplifies other code */
1042d983712dSmrg
1043d983712dSmrg    /* hardware limits */
1044d983712dSmrg    pScrn->maxHValue = Tseng_HMAX;
1045d983712dSmrg    pScrn->maxVValue = Tseng_VMAX;
1046d983712dSmrg
1047d983712dSmrg    /*
1048d983712dSmrg     * This must happen after pScrn->display has been set because
1049d983712dSmrg     * xf86SetWeight references it.
1050d983712dSmrg     */
1051d983712dSmrg
1052d983712dSmrg    /* Set weight/mask/offset for depth > 8 */
1053d983712dSmrg    if (pScrn->depth > 8) {
1054d983712dSmrg	/* The defaults are OK for us */
1055d983712dSmrg	rgb zeros = {0, 0, 0};
1056d983712dSmrg
1057d983712dSmrg	if (!xf86SetWeight(pScrn, zeros, zeros)) {
1058d983712dSmrg	    return FALSE;
1059d983712dSmrg	} else {
1060d983712dSmrg	    /* XXX check that weight returned is supported */
1061d983712dSmrg	    ;
1062d983712dSmrg	}
1063d983712dSmrg    }
1064d983712dSmrg
1065d983712dSmrg    /* Set the default visual. */
1066d983712dSmrg    if (!xf86SetDefaultVisual(pScrn, -1))
1067d983712dSmrg	return FALSE;
1068d983712dSmrg
1069d983712dSmrg    /* The gamma fields must be initialised when using the new cmap code */
1070d983712dSmrg    if (pScrn->depth > 1) {
1071d983712dSmrg	Gamma zeros = {0.0, 0.0, 0.0};
1072d983712dSmrg
1073d983712dSmrg	if (!xf86SetGamma(pScrn, zeros)) {
1074d983712dSmrg	    return FALSE;
1075d983712dSmrg	}
1076d983712dSmrg    }
1077d983712dSmrg
1078d983712dSmrg    /* Set the bits per RGB for 8bpp mode */
1079d983712dSmrg    if (pScrn->depth == 8) {
1080d983712dSmrg	/* Default to 6, because most Tseng chips/RAMDACs don't support it */
1081d983712dSmrg	pScrn->rgbBits = 6;
1082d983712dSmrg    }
1083d983712dSmrg    if (!TsengProcessOptions(pScrn))   /* must be done _after_ we know what chip this is */
1084d983712dSmrg	return FALSE;
1085d983712dSmrg
1086d983712dSmrg    if (!TsengGetFbAddress(pScrn))
1087d983712dSmrg        return FALSE;
1088d983712dSmrg
1089d983712dSmrg    pScrn->memPhysBase = pTseng->FbAddress;
1090d983712dSmrg    pScrn->fbOffset = 0;
1091d983712dSmrg
1092d983712dSmrg    if (pTseng->UseAccel)
1093d983712dSmrg	VGAHWPTR(pScrn)->MapSize = 0x20000;  /* accelerator apertures and MMIO */
1094d983712dSmrg    else
1095d983712dSmrg	VGAHWPTR(pScrn)->MapSize = 0x10000;
1096d983712dSmrg
1097d03ff4acSmrg#ifndef XSERVER_LIBPCIACCESS
1098d983712dSmrg    /*
1099d983712dSmrg     * XXX At least part of this range does appear to be disabled,
1100d983712dSmrg     * but to play safe, it is marked as "unused" for now.
1101d983712dSmrg     * Changed this to "disable". Otherwise it might interfere with DGA.
1102d983712dSmrg     */
1103d983712dSmrg    xf86SetOperatingState(resVgaMem, pTseng->pEnt->index, ResDisableOpr);
1104d03ff4acSmrg#endif
1105d983712dSmrg    /* hibit processing (TsengProcessOptions() must have been called first) */
1106d983712dSmrg    pTseng->save_divide = 0x40;	       /* default */
1107d983712dSmrg    if (pTseng->ChipType == ET4000) {
1108d983712dSmrg	if (!TsengProcessHibit(pScrn))
1109d983712dSmrg	    return FALSE;
1110d983712dSmrg    }
1111d983712dSmrg    /*
1112d983712dSmrg     * If the user has specified the amount of memory in the XF86Config
1113d983712dSmrg     * file, we respect that setting.
1114d983712dSmrg     */
1115d983712dSmrg    if (pTseng->pEnt->device->videoRam != 0) {
1116d983712dSmrg	pScrn->videoRam = pTseng->pEnt->device->videoRam;
1117d983712dSmrg	from = X_CONFIG;
1118d983712dSmrg    } else {
1119d983712dSmrg	from = X_PROBED;
1120d983712dSmrg	pScrn->videoRam = TsengDetectMem(pScrn);
1121d983712dSmrg    }
1122d983712dSmrg    pScrn->videoRam = TsengLimitMem(pScrn, pScrn->videoRam);
1123d983712dSmrg
1124d983712dSmrg    xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte.\n",
1125d983712dSmrg               pScrn->videoRam);
1126d983712dSmrg
1127d983712dSmrg     TsengSetupClockRange(pScrn);
1128d983712dSmrg
1129d983712dSmrg    /*
1130d983712dSmrg     * xf86ValidateModes will check that the mode HTotal and VTotal values
1131d983712dSmrg     * don't exceed the chipset's limit if pScrn->maxHValue and
1132d983712dSmrg     * pScrn->maxVValue are set.  Since our TsengValidMode() already takes
1133d983712dSmrg     * care of this, we don't worry about setting them here.
1134d983712dSmrg     */
1135d983712dSmrg
1136d983712dSmrg    /* Select valid modes from those available */
1137d983712dSmrg    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
1138d983712dSmrg	pScrn->display->modes, &pTseng->clockRange,
1139d983712dSmrg	NULL, 32, pScrn->maxHValue, 8*pTseng->Bytesperpixel, /* H limits */
1140d983712dSmrg	0, pScrn->maxVValue,	       /* V limits */
1141d983712dSmrg	pScrn->display->virtualX,
1142d983712dSmrg	pScrn->display->virtualY,
1143d983712dSmrg	pTseng->FbMapSize,
1144d983712dSmrg	LOOKUP_BEST_REFRESH);	       /* LOOKUP_CLOSEST_CLOCK | LOOKUP_CLKDIV2 when no programmable clock ? */
1145d983712dSmrg
1146d983712dSmrg    if (i == -1) {
1147d983712dSmrg	TsengFreeRec(pScrn);
1148d983712dSmrg	return FALSE;
1149d983712dSmrg    }
1150d983712dSmrg    /* Prune the modes marked as invalid */
1151d983712dSmrg    xf86PruneDriverModes(pScrn);
1152d983712dSmrg
1153d983712dSmrg    if (i == 0 || pScrn->modes == NULL) {
1154d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1155d983712dSmrg	TsengFreeRec(pScrn);
1156d983712dSmrg	return FALSE;
1157d983712dSmrg    }
1158d983712dSmrg    /*
1159d983712dSmrg     * Set the CRTC parameters for all of the modes based on the type
1160d983712dSmrg     * of mode, and the chipset's interlace requirements.
1161d983712dSmrg     *
1162d983712dSmrg     * Calling this is required if the mode->Crtc* values are used by the
1163d983712dSmrg     * driver and if the driver doesn't provide code to set them.  They
1164d983712dSmrg     * are not pre-initialised at all.
1165d983712dSmrg     */
1166d983712dSmrg    xf86SetCrtcForModes(pScrn, 0);
1167d983712dSmrg
1168d983712dSmrg    /* Set the current mode to the first in the list */
1169d983712dSmrg    pScrn->currentMode = pScrn->modes;
1170d983712dSmrg
1171d983712dSmrg    /* Print the list of modes being used */
1172d983712dSmrg    xf86PrintModes(pScrn);
1173d983712dSmrg
1174d983712dSmrg    /* Set display resolution */
1175d983712dSmrg    xf86SetDpi(pScrn, 0, 0);
1176d983712dSmrg
1177d983712dSmrg    /* Load bpp-specific modules */
1178d983712dSmrg    switch (pScrn->bitsPerPixel) {
1179d983712dSmrg    case 1:
1180d983712dSmrg	if (xf86LoadSubModule(pScrn, "xf1bpp") == NULL) {
1181d983712dSmrg	  TsengFreeRec(pScrn);
1182d983712dSmrg	  return FALSE;
1183d983712dSmrg	}
1184d983712dSmrg	break;
1185d983712dSmrg    case 4:
1186d983712dSmrg	if (xf86LoadSubModule(pScrn, "xf4bpp") == NULL) {
1187d983712dSmrg	  TsengFreeRec(pScrn);
1188d983712dSmrg	  return FALSE;
1189d983712dSmrg	}
1190d983712dSmrg	break;
1191d983712dSmrg    default:
1192d983712dSmrg	if (xf86LoadSubModule(pScrn, "fb") == NULL) {
1193d983712dSmrg	  TsengFreeRec(pScrn);
1194d983712dSmrg	  return FALSE;
1195d983712dSmrg	}
1196d983712dSmrg	break;
1197d983712dSmrg    }
1198d983712dSmrg
1199d983712dSmrg    /* Load XAA if needed */
1200d983712dSmrg    if (pTseng->UseAccel) {
1201d983712dSmrg	if (!xf86LoadSubModule(pScrn, "xaa")) {
1202d983712dSmrg	    TsengFreeRec(pScrn);
1203d983712dSmrg	    return FALSE;
1204d983712dSmrg	}
1205d983712dSmrg    }
1206d983712dSmrg    /* Load ramdac if needed */
1207d983712dSmrg    if (pTseng->HWCursor) {
1208d983712dSmrg	if (!xf86LoadSubModule(pScrn, "ramdac")) {
1209d983712dSmrg	    TsengFreeRec(pScrn);
1210d983712dSmrg	    return FALSE;
1211d983712dSmrg	}
1212d983712dSmrg    }
1213d983712dSmrg/*    TsengLock(pScrn); */
1214d983712dSmrg
1215d983712dSmrg    return TRUE;
1216d983712dSmrg}
1217d983712dSmrg
1218d983712dSmrgstatic void
12194b9470b1SmrgTsengSetupAccelMemory(ScreenPtr pScreen)
1220d983712dSmrg{
12214b9470b1Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1222d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1223d983712dSmrg    int offscreen_videoram, videoram_end, req_videoram;
1224d983712dSmrg    int i;
1225d983712dSmrg    int v;
1226d983712dSmrg
1227d983712dSmrg    /* XXX Hack to suppress messages in subsequent generations. */
1228d983712dSmrg    if (serverGeneration == 1)
1229d983712dSmrg	v = 1;
1230d983712dSmrg    else
1231d983712dSmrg	v = 100;
1232d983712dSmrg    /*
1233d983712dSmrg     * The accelerator requires free off-screen video memory to operate. The
1234d983712dSmrg     * more there is, the more it can accelerate.
1235d983712dSmrg     */
1236d983712dSmrg
1237d983712dSmrg    videoram_end = pScrn->videoRam * 1024;
1238d983712dSmrg    offscreen_videoram = videoram_end -
1239d983712dSmrg	pScrn->displayWidth * pScrn->virtualY * pTseng->Bytesperpixel;
12404b9470b1Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, v, "Available off-screen memory: %d bytes.\n",
1241d983712dSmrg	offscreen_videoram);
1242d983712dSmrg
1243d983712dSmrg    /*
1244d983712dSmrg     * The HW cursor requires 1kb of off-screen memory, aligned to 1kb
1245d983712dSmrg     * (256 DWORDS). Setting up its memory first ensures the alignment.
1246d983712dSmrg     */
1247d983712dSmrg    if (pTseng->HWCursor) {
1248d983712dSmrg	req_videoram = 1024;
1249d983712dSmrg	if (offscreen_videoram < req_videoram) {
1250d983712dSmrg	    xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
1251d983712dSmrg		"Hardware Cursor disabled. It requires %d bytes of free video memory\n",
1252d983712dSmrg		req_videoram);
1253d983712dSmrg	    pTseng->HWCursor = FALSE;
1254d983712dSmrg	    pTseng->HWCursorBufferOffset = 0;
1255d983712dSmrg	} else {
1256d983712dSmrg	    offscreen_videoram -= req_videoram;
1257d983712dSmrg	    videoram_end -= req_videoram;
1258d983712dSmrg	    pTseng->HWCursorBufferOffset = videoram_end;
1259d983712dSmrg	}
1260d983712dSmrg    } else {
1261d983712dSmrg	pTseng->HWCursorBufferOffset = 0;
1262d983712dSmrg    }
1263d983712dSmrg
1264d983712dSmrg    /*
1265d983712dSmrg     * Acceleration memory setup. Do this only if acceleration is enabled.
1266d983712dSmrg     */
1267d983712dSmrg    if (!pTseng->UseAccel) return;
1268d983712dSmrg
1269d983712dSmrg    /*
1270d983712dSmrg     * Basic acceleration needs storage for FG, BG and PAT colors in
1271d983712dSmrg     * off-screen memory. Each color requires 2(ping-pong)*8 bytes.
1272d983712dSmrg     */
1273d983712dSmrg    req_videoram = 2 * 8 * 3;
1274d983712dSmrg    if (offscreen_videoram < req_videoram) {
1275d983712dSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
1276d983712dSmrg	    "Acceleration disabled. It requires AT LEAST %d bytes of free video memory\n",
1277d983712dSmrg	    req_videoram);
1278d983712dSmrg	pTseng->UseAccel = FALSE;
1279d983712dSmrg	pTseng->AccelColorBufferOffset = 0;
1280d983712dSmrg	goto end_memsetup;	      /* no basic acceleration means none at all */
1281d983712dSmrg    } else {
1282d983712dSmrg	offscreen_videoram -= req_videoram;
1283d983712dSmrg	videoram_end -= req_videoram;
1284d983712dSmrg	pTseng->AccelColorBufferOffset = videoram_end;
1285d983712dSmrg    }
1286d983712dSmrg
1287d983712dSmrg    /*
1288d983712dSmrg     * Color expansion (using triple buffering) requires 3 non-expanded
1289d983712dSmrg     * scanlines, DWORD padded.
1290d983712dSmrg     */
1291d983712dSmrg    req_videoram = 3 * ((pScrn->virtualX + 31) / 32) * 4;
1292d983712dSmrg    if (offscreen_videoram < req_videoram) {
1293d983712dSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
1294d983712dSmrg	    "Accelerated color expansion disabled (%d more bytes of free video memory required)\n",
1295d983712dSmrg	    req_videoram - offscreen_videoram);
1296d983712dSmrg	pTseng->AccelColorExpandBufferOffsets[0] = 0;
1297d983712dSmrg    } else {
1298d983712dSmrg	offscreen_videoram -= req_videoram;
1299d983712dSmrg	for (i = 0; i < 3; i++) {
1300d983712dSmrg	    videoram_end -= req_videoram / 3;
1301d983712dSmrg	    pTseng->AccelColorExpandBufferOffsets[i] = videoram_end;
1302d983712dSmrg	}
1303d983712dSmrg    }
1304d983712dSmrg
1305d983712dSmrg    /*
1306d983712dSmrg     * XAA ImageWrite support needs two entire line buffers. The
1307d983712dSmrg     * current code assumes buffer 1 lies in the same 8kb aperture as
1308d983712dSmrg     * buffer 0.
1309d983712dSmrg     *
1310d983712dSmrg     * [ FIXME: aren't we forgetting the DWORD padding here ? ]
1311d983712dSmrg     * [ FIXME: why here double-buffering and in colexp triple-buffering? ]
1312d983712dSmrg     */
1313d983712dSmrg    req_videoram = 2 * (pScrn->virtualX * pTseng->Bytesperpixel);
1314d983712dSmrg
1315d983712dSmrg    if (offscreen_videoram < req_videoram) {
1316d983712dSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
1317d983712dSmrg	    "Accelerated ImageWrites disabled (%d more bytes of free video memory required)\n",
1318d983712dSmrg	    req_videoram - offscreen_videoram);
1319d983712dSmrg	pTseng->AccelImageWriteBufferOffsets[0] = 0;
1320d983712dSmrg    } else {
1321d983712dSmrg	offscreen_videoram -= req_videoram;
1322d983712dSmrg	for (i = 0; i < 2; i++) {
1323d983712dSmrg	    videoram_end -= req_videoram / 2;
1324d983712dSmrg	    pTseng->AccelImageWriteBufferOffsets[i] = videoram_end;
1325d983712dSmrg	}
1326d983712dSmrg    }
1327d983712dSmrg
13284b9470b1Smrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, v,
1329d983712dSmrg	"Remaining off-screen memory available for pixmap cache: %d bytes.\n",
1330d983712dSmrg	offscreen_videoram);
1331d983712dSmrg
1332d983712dSmrgend_memsetup:
1333d983712dSmrg    pScrn->videoRam = videoram_end / 1024;
1334d983712dSmrg}
1335d983712dSmrg
1336d983712dSmrgstatic Bool
13374b9470b1SmrgTsengScreenInit(SCREEN_INIT_ARGS_DECL)
1338d983712dSmrg{
1339d983712dSmrg    ScrnInfoPtr pScrn;
1340d983712dSmrg    TsengPtr pTseng;
1341d983712dSmrg    int ret;
1342d983712dSmrg    VisualPtr visual;
1343d983712dSmrg
1344d983712dSmrg    PDEBUG("	TsengScreenInit\n");
1345d983712dSmrg
1346d983712dSmrg    /*
1347d983712dSmrg     * First get the ScrnInfoRec
1348d983712dSmrg     */
13494b9470b1Smrg    pScrn = xf86ScreenToScrn(pScreen);
1350d983712dSmrg
1351d983712dSmrg    pTseng = TsengPTR(pScrn);
1352d983712dSmrg    /* Map the Tseng memory areas */
1353d983712dSmrg    if (!TsengMapMem(pScrn))
1354d983712dSmrg	return FALSE;
1355d983712dSmrg
1356d983712dSmrg    /* Save the current state */
1357d983712dSmrg    TsengSave(pScrn);
1358d983712dSmrg
1359d983712dSmrg    /* Initialise the first mode */
1360d983712dSmrg    TsengModeInit(pScrn, pScrn->currentMode);
1361d983712dSmrg
1362d983712dSmrg    /* Darken the screen for aesthetic reasons and set the viewport */
1363d983712dSmrg    TsengSaveScreen(pScreen, SCREEN_SAVER_ON);
1364d983712dSmrg
13654b9470b1Smrg    TsengAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
1366d983712dSmrg    /* XXX Fill the screen with black */
1367d983712dSmrg
1368d983712dSmrg    /*
1369d983712dSmrg     * Reset visual list.
1370d983712dSmrg     */
1371d983712dSmrg    miClearVisualTypes();
1372d983712dSmrg
1373d983712dSmrg    /* Setup the visuals we support. */
1374d983712dSmrg
1375d983712dSmrg    /*
1376d983712dSmrg     * For bpp > 8, the default visuals are not acceptable because we only
1377d983712dSmrg     * support TrueColor and not DirectColor.  To deal with this, call
1378d983712dSmrg     * miSetVisualTypes for each visual supported.
1379d983712dSmrg     */
1380d983712dSmrg    if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
1381d983712dSmrg			  pScrn->rgbBits, pScrn->defaultVisual))
1382d983712dSmrg      return FALSE;
1383d983712dSmrg
1384d983712dSmrg    miSetPixmapDepths ();
1385d983712dSmrg
1386d983712dSmrg    /*
1387d983712dSmrg     * Call the framebuffer layer's ScreenInit function, and fill in other
1388d983712dSmrg     * pScreen fields.
1389d983712dSmrg     */
1390d983712dSmrg
1391d983712dSmrg    switch (pScrn->bitsPerPixel) {
1392962c3257Smrg#if HAVE_XF1BPP
1393d983712dSmrg    case 1:
1394d983712dSmrg	ret = xf1bppScreenInit(pScreen, pTseng->FbBase,
1395d983712dSmrg			pScrn->virtualX, pScrn->virtualY,
1396d983712dSmrg			pScrn->xDpi, pScrn->yDpi,
1397d983712dSmrg			pScrn->displayWidth);
1398d983712dSmrg	break;
1399962c3257Smrg#endif
1400962c3257Smrg#if HAVE_XF4BPP
1401d983712dSmrg    case 4:
1402d983712dSmrg	ret = xf4bppScreenInit(pScreen, pTseng->FbBase,
1403d983712dSmrg			pScrn->virtualX, pScrn->virtualY,
1404d983712dSmrg			pScrn->xDpi, pScrn->yDpi,
1405d983712dSmrg			pScrn->displayWidth);
1406d983712dSmrg	break;
1407962c3257Smrg#endif
1408d983712dSmrg    default:
1409d983712dSmrg        ret  = fbScreenInit(pScreen, pTseng->FbBase,
1410d983712dSmrg			pScrn->virtualX, pScrn->virtualY,
1411d983712dSmrg			pScrn->xDpi, pScrn->yDpi,
1412d983712dSmrg			pScrn->displayWidth, pScrn->bitsPerPixel);
1413d983712dSmrg	break;
1414d983712dSmrg    }
1415d983712dSmrg
1416d983712dSmrg    if (!ret)
1417d983712dSmrg	return FALSE;
1418d983712dSmrg
1419d983712dSmrg    xf86SetBlackWhitePixels(pScreen);
1420d983712dSmrg
1421d983712dSmrg    if (pScrn->bitsPerPixel > 8) {
1422d983712dSmrg	/* Fixup RGB ordering */
1423d983712dSmrg	visual = pScreen->visuals + pScreen->numVisuals;
1424d983712dSmrg	while (--visual >= pScreen->visuals) {
1425d983712dSmrg	    if ((visual->class | DynamicClass) == DirectColor) {
1426d983712dSmrg		visual->offsetRed = pScrn->offset.red;
1427d983712dSmrg		visual->offsetGreen = pScrn->offset.green;
1428d983712dSmrg		visual->offsetBlue = pScrn->offset.blue;
1429d983712dSmrg		visual->redMask = pScrn->mask.red;
1430d983712dSmrg		visual->greenMask = pScrn->mask.green;
1431d983712dSmrg		visual->blueMask = pScrn->mask.blue;
1432d983712dSmrg	    }
1433d983712dSmrg	}
1434d983712dSmrg    }
1435d983712dSmrg
1436962c3257Smrg#if HAVE_XF1BPP
1437d983712dSmrg    /* must be after RGB ordering fixed */
1438d983712dSmrg    if (pScrn->bitsPerPixel > 4)
1439962c3257Smrg#endif
1440d983712dSmrg	fbPictureInit(pScreen, 0, 0);
1441d983712dSmrg
1442d983712dSmrg    if (pScrn->depth >= 8)
1443d983712dSmrg        TsengDGAInit(pScreen);
1444d983712dSmrg
1445d983712dSmrg    /*
1446d983712dSmrg     * Initialize the acceleration interface.
1447d983712dSmrg     */
14484b9470b1Smrg    TsengSetupAccelMemory(pScreen);
1449d983712dSmrg    if (pTseng->UseAccel) {
1450d983712dSmrg	tseng_init_acl(pScrn);	/* set up accelerator */
1451d983712dSmrg	if (!TsengXAAInit(pScreen)) {	/* set up XAA interface */
1452d983712dSmrg	    return FALSE;
1453d983712dSmrg	}
1454d983712dSmrg    }
1455d983712dSmrg
1456d983712dSmrg    miInitializeBackingStore(pScreen);
1457d983712dSmrg    xf86SetSilkenMouse(pScreen);
1458d983712dSmrg    /* Initialise cursor functions */
1459d983712dSmrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1460d983712dSmrg
1461d983712dSmrg    /* Hardware Cursor layer */
1462d983712dSmrg    if (pTseng->HWCursor) {
1463d983712dSmrg	if (!TsengHWCursorInit(pScreen))
1464d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1465d983712dSmrg		"Hardware cursor initialization failed\n");
1466d983712dSmrg    }
1467d983712dSmrg
1468d983712dSmrg    /* Initialise default colourmap */
1469d983712dSmrg    if (!miCreateDefColormap(pScreen))
1470d983712dSmrg	return FALSE;
1471d983712dSmrg
1472d983712dSmrg    if (pScrn->depth == 4 || pScrn->depth == 8) { /* fb and xf4bpp */
1473d983712dSmrg	vgaHWHandleColormaps(pScreen);
1474d983712dSmrg    }
1475d03ff4acSmrg#ifndef XSERVER_LIBPCIACCESS
1476d983712dSmrg    pScrn->racIoFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
1477d983712dSmrg    pScrn->racMemFlags = pScrn->racIoFlags;
1478d03ff4acSmrg#endif
1479d983712dSmrg    /* Wrap the current CloseScreen and SaveScreen functions */
1480d983712dSmrg    pScreen->SaveScreen = TsengSaveScreen;
1481d983712dSmrg
1482d983712dSmrg    /* Support for DPMS, the ET4000W32Pc and newer uses a different and
1483d983712dSmrg     * simpler method than the older cards.
1484d983712dSmrg     */
1485d983712dSmrg    if ((pTseng->ChipType == ET4000) &&
1486d983712dSmrg        ((pTseng->ChipRev == REV_A) || (pTseng->ChipRev == REV_B)))
1487d983712dSmrg        xf86DPMSInit(pScreen, (DPMSSetProcPtr)TsengHVSyncDPMSSet, 0);
1488d983712dSmrg    else
1489d983712dSmrg	xf86DPMSInit(pScreen, (DPMSSetProcPtr)TsengCrtcDPMSSet, 0);
1490d983712dSmrg
1491d983712dSmrg    pTseng->CloseScreen = pScreen->CloseScreen;
1492d983712dSmrg    pScreen->CloseScreen = TsengCloseScreen;
1493d983712dSmrg
1494d983712dSmrg    /* Report any unused options (only for the first generation) */
1495d983712dSmrg    if (serverGeneration == 1) {
1496d983712dSmrg	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1497d983712dSmrg    }
1498d983712dSmrg    /* Done */
1499d983712dSmrg    return TRUE;
1500d983712dSmrg}
1501d983712dSmrg
1502d983712dSmrgstatic Bool
15034b9470b1SmrgTsengEnterVT(VT_FUNC_ARGS_DECL)
1504d983712dSmrg{
15054b9470b1Smrg    SCRN_INFO_PTR(arg);
1506d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1507d983712dSmrg
1508d983712dSmrg    PDEBUG("	TsengEnterVT\n");
1509d983712dSmrg
1510d983712dSmrg    vgaHWUnlock(VGAHWPTR(pScrn));
1511d983712dSmrg    TsengUnlock(pScrn);
1512d983712dSmrg
1513d983712dSmrg    if (!TsengModeInit(pScrn, pScrn->currentMode))
1514d983712dSmrg        return FALSE;
1515d983712dSmrg    if (pTseng->UseAccel) {
1516d983712dSmrg	tseng_init_acl(pScrn);	/* set up accelerator */
1517d983712dSmrg    }
1518d983712dSmrg    return TRUE;
1519d983712dSmrg}
1520d983712dSmrg
1521d983712dSmrgstatic void
15224b9470b1SmrgTsengLeaveVT(VT_FUNC_ARGS_DECL)
1523d983712dSmrg{
15244b9470b1Smrg    SCRN_INFO_PTR(arg);
1525d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1526d983712dSmrg
1527d983712dSmrg    PDEBUG("	TsengLeaveVT\n");
1528d983712dSmrg    TsengRestore(pScrn, &(VGAHWPTR(pScrn)->SavedReg),
1529d983712dSmrg		 &pTseng->SavedReg,VGA_SR_ALL);
1530d983712dSmrg
1531d983712dSmrg    TsengLock(pScrn);
1532d983712dSmrg    vgaHWLock(VGAHWPTR(pScrn));
1533d983712dSmrg}
1534d983712dSmrg
1535d983712dSmrgstatic Bool
15364b9470b1SmrgTsengCloseScreen(CLOSE_SCREEN_ARGS_DECL)
1537d983712dSmrg{
15384b9470b1Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1539d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1540d983712dSmrg
1541d983712dSmrg    PDEBUG("	TsengCloseScreen\n");
1542d983712dSmrg
1543d983712dSmrg    if (pScrn->vtSema) {
1544d983712dSmrg    TsengRestore(pScrn, &(VGAHWPTR(pScrn)->SavedReg),
1545d983712dSmrg		 &(pTseng->SavedReg),VGA_SR_ALL);
1546d983712dSmrg    TsengUnmapMem(pScrn);
1547d983712dSmrg    }
15484b9470b1Smrg#ifdef HAVE_XAA_H
1549d983712dSmrg    if (pTseng->AccelInfoRec)
1550d983712dSmrg	XAADestroyInfoRec(pTseng->AccelInfoRec);
15514b9470b1Smrg#endif
1552d983712dSmrg    if (pTseng->CursorInfoRec)
1553d983712dSmrg	xf86DestroyCursorInfoRec(pTseng->CursorInfoRec);
1554d983712dSmrg
1555d983712dSmrg    pScrn->vtSema = FALSE;
1556d983712dSmrg
1557d983712dSmrg    pScreen->CloseScreen = pTseng->CloseScreen;
15584b9470b1Smrg    return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
1559d983712dSmrg}
1560d983712dSmrg
1561d983712dSmrg/*
1562d983712dSmrg * SaveScreen --
1563d983712dSmrg *
1564d983712dSmrg *   perform a sequencer reset.
1565d983712dSmrg *
1566d983712dSmrg * The ET4000 "Video System Configuration 1" register (CRTC index 0x36),
1567d983712dSmrg * which is used to set linear memory mode and MMU-related stuff, is
1568d983712dSmrg * partially reset to "0" when TS register index 0 bit 1 is set (synchronous
1569d983712dSmrg * reset): bits 3..5 are reset during a sync. reset.
1570d983712dSmrg *
1571d983712dSmrg * We therefor do _not_ call vgaHWSaveScreen here, since it does a sequencer
1572d983712dSmrg * reset. Instead, we do the same as in vgaHWSaveScreen except for the seq. reset.
1573d983712dSmrg *
1574d983712dSmrg * If this is not done, the higher level code will not be able to access the
1575d983712dSmrg * framebuffer (because it is temporarily in banked mode instead of linear
1576d983712dSmrg * mode) as long as SaveScreen is active (=in between a
1577d983712dSmrg * SaveScreen(FALSE)/SaveScreen(TRUE) pair)
1578d983712dSmrg */
1579d983712dSmrg
1580d983712dSmrgstatic Bool
1581d983712dSmrgTsengSaveScreen(ScreenPtr pScreen, int mode)
1582d983712dSmrg{
15834b9470b1Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1584d983712dSmrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
1585d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1586d983712dSmrg    Bool unblank;
1587d983712dSmrg
1588d983712dSmrg    PDEBUG("	TsengSaveScreen\n");
1589d983712dSmrg
1590d983712dSmrg    unblank = xf86IsUnblank(mode);
1591d983712dSmrg
1592d983712dSmrg    if (pTseng->ChipType == ET6000) {
1593d983712dSmrg	return vgaHWSaveScreen(pScreen, unblank);
1594d983712dSmrg    } else {
1595d983712dSmrg       if (unblank)
1596d983712dSmrg	  SetTimeSinceLastInputEvent();
1597d983712dSmrg
1598d983712dSmrg       if (pScrn->vtSema) {
1599d983712dSmrg           /* vgaHWBlankScreen without seq reset */
1600d983712dSmrg           CARD8 scrn;
1601d983712dSmrg
1602d983712dSmrg           scrn = hwp->readSeq(hwp, 0x01);
1603d983712dSmrg
1604d983712dSmrg           if (unblank)
1605d983712dSmrg               scrn &= 0xDF; /* enable screen */
1606d983712dSmrg           else
1607d983712dSmrg               scrn |= 0x20; /* blank screen */
1608d983712dSmrg
1609d983712dSmrg           hwp->writeSeq(hwp, 0x01, scrn); /* change mode */
1610d983712dSmrg       }
1611d983712dSmrg       return (TRUE);
1612d983712dSmrg    }
1613d983712dSmrg}
1614d983712dSmrg
1615d983712dSmrgstatic Bool
1616d983712dSmrgTsengMapMem(ScrnInfoPtr pScrn)
1617d983712dSmrg{
1618d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1619d983712dSmrg
1620d983712dSmrg    PDEBUG("	TsengMapMem\n");
1621d983712dSmrg
1622d983712dSmrg    /* Map the VGA memory */
1623d983712dSmrg
1624d983712dSmrg    if (!vgaHWMapMem(pScrn)) {
1625d983712dSmrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1626d983712dSmrg	    "Could not mmap standard VGA memory aperture.\n");
1627d983712dSmrg	return FALSE;
1628d983712dSmrg    }
1629d983712dSmrg
1630962c3257Smrg#ifndef XSERVER_LIBPCIACCESS
1631d983712dSmrg    pTseng->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
1632d983712dSmrg                                   pTseng->PciTag,
1633d983712dSmrg                                   (unsigned long)pTseng->FbAddress,
1634d983712dSmrg                                   pTseng->FbMapSize);
1635962c3257Smrg#else
1636962c3257Smrg    {
1637962c3257Smrg      void** result = (void**)&pTseng->FbBase;
1638962c3257Smrg      int err = pci_device_map_range(pTseng->PciInfo,
1639962c3257Smrg				     pTseng->FbAddress,
1640962c3257Smrg				     pTseng->FbMapSize,
1641962c3257Smrg				     PCI_DEV_MAP_FLAG_WRITABLE |
1642962c3257Smrg				     PCI_DEV_MAP_FLAG_WRITE_COMBINE,
1643962c3257Smrg				     result);
1644962c3257Smrg
1645962c3257Smrg      if (err)
1646962c3257Smrg	return FALSE;
1647962c3257Smrg    }
1648962c3257Smrg#endif
1649d983712dSmrg    if (pTseng->FbBase == NULL) {
1650d983712dSmrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1651d983712dSmrg                   "Could not mmap linear video memory.\n");
1652d983712dSmrg        return FALSE;
1653d983712dSmrg    }
1654d983712dSmrg
1655d983712dSmrg    /* need some sanity here */
1656d983712dSmrg    if (pTseng->UseAccel) {
1657962c3257Smrg#ifndef XSERVER_LIBPCIACCESS
1658d983712dSmrg        pTseng->MMioBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
1659d983712dSmrg                                         pTseng->PciTag,
1660d983712dSmrg                                         (unsigned long)pTseng->FbAddress,
1661d983712dSmrg                                         pTseng->FbMapSize);
1662962c3257Smrg#else
1663962c3257Smrg	pTseng->MMioBase = pTseng->FbBase;
1664962c3257Smrg#endif
1665d983712dSmrg        if (!pTseng->MMioBase) {
1666d983712dSmrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1667d983712dSmrg		       "Could not mmap mmio memory.\n");
1668d983712dSmrg	    return FALSE;
1669d983712dSmrg        }
1670d983712dSmrg        pTseng->MMioBase += 0x3FFF00L;
1671d983712dSmrg    }
1672d983712dSmrg
1673d983712dSmrg    if (pTseng->FbBase == NULL)
1674d983712dSmrg	return FALSE;
1675d983712dSmrg
1676d983712dSmrg    return TRUE;
1677d983712dSmrg}
1678d983712dSmrg
1679d983712dSmrgstatic Bool
1680d983712dSmrgTsengUnmapMem(ScrnInfoPtr pScrn)
1681d983712dSmrg{
1682d983712dSmrg    TsengPtr pTseng = TsengPTR(pScrn);
1683d983712dSmrg
1684d983712dSmrg    PDEBUG("	TsengUnmapMem\n");
1685d983712dSmrg
1686962c3257Smrg#ifndef XSERVER_LIBPCIACCESS
1687d983712dSmrg    xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pTseng->FbBase, pTseng->FbMapSize);
1688962c3257Smrg#else
1689962c3257Smrg    pci_device_unmap_range(pTseng->PciInfo, pTseng->FbBase, pTseng->FbMapSize);
1690962c3257Smrg#endif
1691d983712dSmrg
1692d983712dSmrg    vgaHWUnmapMem(pScrn);
1693d983712dSmrg
1694d983712dSmrg    pTseng->FbBase = NULL;
1695d983712dSmrg
1696d983712dSmrg    return TRUE;
1697d983712dSmrg}
1698d983712dSmrg
1699d983712dSmrgstatic void
17004b9470b1SmrgTsengFreeScreen(FREE_SCREEN_ARGS_DECL)
1701d983712dSmrg{
17024b9470b1Smrg    SCRN_INFO_PTR(arg);
1703d983712dSmrg    PDEBUG("	TsengFreeScreen\n");
1704d983712dSmrg    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
17054b9470b1Smrg        vgaHWFreeHWRec(pScrn);
17064b9470b1Smrg    TsengFreeRec(pScrn);
1707d983712dSmrg}
1708d983712dSmrg
1709d983712dSmrgstatic Bool
17104b9470b1SmrgTsengSwitchMode(SWITCH_MODE_ARGS_DECL)
1711d983712dSmrg{
17124b9470b1Smrg    SCRN_INFO_PTR(arg);
1713d983712dSmrg    PDEBUG("	TsengSwitchMode\n");
17144b9470b1Smrg    return TsengModeInit(pScrn, mode);
1715d983712dSmrg}
1716