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