#include "tseng.h"
#include "tseng_acl.h"
#include "mipointer.h"
#include "mibstore.h"
#include "fb.h"
#include "xf86RAC.h"
#include "xf86Resources.h"
#include "xf86int10.h"
#include "xf86xv.h"
#include "Xv.h"
static const OptionInfoRec * TsengAvailableOptions(int chipid, int busid);
static void TsengIdentify(int flags);
static Bool TsengProbe(DriverPtr drv, int flags);
static Bool TsengPreInit(ScrnInfoPtr pScrn, int flags);
static Bool TsengScreenInit(int Index, ScreenPtr pScreen, int argc,
char **argv);
static Bool TsengEnterVT(int scrnIndex, int flags);
static void TsengLeaveVT(int scrnIndex, int flags);
static Bool TsengCloseScreen(int scrnIndex, ScreenPtr pScreen);
static Bool TsengSaveScreen(ScreenPtr pScreen, int mode);
static Bool TsengSwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
static void TsengFreeScreen(int scrnIndex, int flags);
static ModeStatus TsengValidMode(int scrnIndex, DisplayModePtr mode,
Bool verbose, int flags);
static Bool TsengMapMem(ScrnInfoPtr pScrn);
static Bool TsengUnmapMem(ScrnInfoPtr pScrn);
static void TsengSave(ScrnInfoPtr pScrn);
static void TsengRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, TsengRegPtr tsengReg, int flags);
static void TsengUnlock(void);
static void TsengLock(void);
static Bool ET4000DetailedProbe(t_tseng_type * chiptype, t_w32_revid * rev);
static int pix24bpp = 0;
#define VERSION 4000
#define TSENG_NAME "TSENG"
#define TSENG_DRIVER_NAME "tseng"
#define TSENG_MAJOR_VERSION 1
#define TSENG_MINOR_VERSION 0
#define TSENG_PATCHLEVEL 0
#define Tseng_HMAX (4096-8)
#define Tseng_VMAX (2048-1)
DriverRec TSENG =
{
VERSION,
TSENG_DRIVER_NAME,
TsengIdentify,
TsengProbe,
TsengAvailableOptions,
NULL,
0
};
static SymTabRec TsengChipsets[] =
{
{TYPE_ET4000, "ET4000"},
{TYPE_ET4000W32, "ET4000W32"},
{TYPE_ET4000W32I, "ET4000W32i"},
{TYPE_ET4000W32P, "ET4000W32p"},
{TYPE_ET6000, "ET6000"},
{TYPE_ET6100, "ET6100"},
{TYPE_TSENG, ""},
{-1, NULL}
};
static PciChipsets TsengPciChipsets[] =
{
{TYPE_ET4000W32P, PCI_CHIP_ET4000_W32P_A, RES_SHARED_VGA},
{TYPE_ET4000W32P, PCI_CHIP_ET4000_W32P_B, RES_SHARED_VGA},
{TYPE_ET4000W32P, PCI_CHIP_ET4000_W32P_C, RES_SHARED_VGA},
{TYPE_ET4000W32P, PCI_CHIP_ET4000_W32P_D, RES_SHARED_VGA},
{TYPE_ET6000, PCI_CHIP_ET6000, RES_SHARED_VGA},
{-1, -1, RES_UNDEFINED}
};
static IsaChipsets TsengIsaChipsets[] =
{
{TYPE_ET4000, RES_EXCLUSIVE_VGA},
{TYPE_ET4000W32, RES_EXCLUSIVE_VGA},
{TYPE_ET4000W32I, RES_EXCLUSIVE_VGA},
{TYPE_TSENG, RES_EXCLUSIVE_VGA},
{-1, RES_UNDEFINED}
};
typedef enum {
OPTION_HIBIT_HIGH,
OPTION_HIBIT_LOW,
OPTION_SW_CURSOR,
OPTION_HW_CURSOR,
OPTION_PCI_BURST,
OPTION_SLOW_DRAM,
OPTION_MED_DRAM,
OPTION_FAST_DRAM,
OPTION_W32_INTERLEAVE,
OPTION_NOACCEL,
OPTION_NOCLOCKCHIP,
OPTION_LINEAR,
OPTION_SHOWCACHE,
OPTION_LEGEND,
OPTION_PCI_RETRY,
OPTION_SET_MCLK
} TsengOpts;
static const OptionInfoRec TsengOptions[] =
{
{OPTION_HIBIT_HIGH, "hibit_high", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_HIBIT_LOW, "hibit_low", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_PCI_BURST, "pci_burst", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_SLOW_DRAM, "slow_dram", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_MED_DRAM, "med_dram", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_FAST_DRAM, "fast_dram", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_W32_INTERLEAVE, "w32_interleave", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_NOCLOCKCHIP, "NoClockchip", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_LINEAR, "Linear", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_SHOWCACHE, "ShowCache", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_LEGEND, "Legend", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_PCI_RETRY, "PciRetry", OPTV_BOOLEAN,
{0}, FALSE},
{OPTION_SET_MCLK, "SetMClk", OPTV_FREQ,
{0}, FALSE},
{-1, NULL, OPTV_NONE,
{0}, FALSE}
};
static const char *int10Symbols[] = {
"xf86FreeInt10",
"xf86InitInt10",
NULL
};
static const char *vgaHWSymbols[] = {
"vgaHWFreeHWRec",
"vgaHWGetHWRec",
"vgaHWGetIOBase",
"vgaHWGetIndex",
"vgaHWHandleColormaps",
"vgaHWInit",
"vgaHWLock",
"vgaHWMapMem",
"vgaHWProtect",
"vgaHWRestore",
"vgaHWSave",
"vgaHWSaveScreen",
"vgaHWUnlock",
"vgaHWUnmapMem",
NULL
};
#ifdef XFree86LOADER
static const char* miscfbSymbols[] = {
"xf1bppScreenInit",
"xf4bppScreenInit",
NULL
};
#endif
static const char* fbSymbols[] = {
"fbPictureInit",
"fbScreenInit",
NULL
};
static const char *ramdacSymbols[] = {
"xf86CreateCursorInfoRec",
"xf86DestroyCursorInfoRec",
"xf86InitCursor",
NULL
};
static const char *xaaSymbols[] = {
"XAACreateInfoRec",
"XAADestroyInfoRec",
"XAAInit",
NULL
};
#ifdef XFree86LOADER
static MODULESETUPPROTO(tsengSetup);
static XF86ModuleVersionInfo tsengVersRec =
{
"tseng",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XF86_VERSION_CURRENT,
TSENG_MAJOR_VERSION, TSENG_MINOR_VERSION, TSENG_PATCHLEVEL,
ABI_CLASS_VIDEODRV,
ABI_VIDEODRV_VERSION,
MOD_CLASS_VIDEODRV,
{0, 0, 0, 0}
};
XF86ModuleData tsengModuleData = { &tsengVersRec, tsengSetup, NULL };
static pointer
tsengSetup(pointer module, pointer opts, int *errmaj, int *errmin)
{
static Bool setupDone = FALSE;
if (!setupDone) {
setupDone = TRUE;
xf86AddDriver(&TSENG, module, 0);
LoaderRefSymLists(vgaHWSymbols, miscfbSymbols, fbSymbols, xaaSymbols,
int10Symbols, ramdacSymbols, NULL);
return (pointer) 1;
} else {
if (errmaj)
*errmaj = LDR_ONCEONLY;
return NULL;
}
}
#endif
static Bool
TsengGetRec(ScrnInfoPtr pScrn)
{
PDEBUG(" TsengGetRec\n");
if (pScrn->driverPrivate != NULL)
return TRUE;
pScrn->driverPrivate = xnfcalloc(sizeof(TsengRec), 1);
return TRUE;
}
static void
TsengFreeRec(ScrnInfoPtr pScrn)
{
PDEBUG(" TsengFreeRec\n");
if (pScrn->driverPrivate == NULL)
return;
xfree(pScrn->driverPrivate);
pScrn->driverPrivate = NULL;
}
static Bool
TsengPCI2Type(ScrnInfoPtr pScrn, int ChipID)
{
TsengPtr pTseng = TsengPTR(pScrn);
switch (ChipID) {
case PCI_CHIP_ET4000_W32P_A:
pTseng->ChipType = TYPE_ET4000W32P;
pTseng->ChipRev = W32REVID_A;
break;
case PCI_CHIP_ET4000_W32P_B:
pTseng->ChipType = TYPE_ET4000W32P;
pTseng->ChipRev = W32REVID_B;
break;
case PCI_CHIP_ET4000_W32P_C:
pTseng->ChipType = TYPE_ET4000W32P;
pTseng->ChipRev = W32REVID_C;
break;
case PCI_CHIP_ET4000_W32P_D:
pTseng->ChipType = TYPE_ET4000W32P;
pTseng->ChipRev = W32REVID_D;
break;
case PCI_CHIP_ET6000:
pTseng->ChipType = TYPE_ET6000;
pTseng->ChipRev = pTseng->PciInfo->chipRev;
if (pTseng->ChipRev >= ET6100REVID)
pTseng->ChipType = TYPE_ET6100;
break;
default:
xf86Msg(X_ERROR, "%s: Unknown Tseng PCI ID: %X\n", TSENG_NAME, ChipID);
return FALSE;
}
return TRUE;
}
static const OptionInfoRec *
TsengAvailableOptions(int chipid, int busid)
{
return TsengOptions;
}
static void
TsengIdentify(int flags)
{
PDEBUG(" TsengIdentify\n");
xf86PrintChipsets(TSENG_NAME, "driver for Tseng Labs chipsets",
TsengChipsets);
}
static void
TsengAssignFPtr(ScrnInfoPtr pScrn)
{
pScrn->driverVersion = VERSION;
pScrn->driverName = TSENG_DRIVER_NAME;
pScrn->name = TSENG_NAME;
pScrn->Probe = TsengProbe;
pScrn->PreInit = TsengPreInit;
pScrn->ScreenInit = TsengScreenInit;
pScrn->SwitchMode = TsengSwitchMode;
pScrn->AdjustFrame = TsengAdjustFrame;
pScrn->EnterVT = TsengEnterVT;
pScrn->LeaveVT = TsengLeaveVT;
pScrn->FreeScreen = TsengFreeScreen;
pScrn->ValidMode = TsengValidMode;
}
static void
TsengUnlock(void)
{
unsigned char temp;
int iobase = VGAHW_GET_IOBASE();
PDEBUG(" TsengUnlock\n");
outb(0x3BF, 0x03);
outb(iobase + 8, 0xA0);
outb(iobase + 4, 0x11);
temp = inb(iobase + 5);
outb(iobase + 5, temp & 0x7F);
}
static void
TsengLock(void)
{
unsigned char temp;
int iobase = VGAHW_GET_IOBASE();
PDEBUG(" TsengLock\n");
outb(iobase + 4, 0x11);
temp = inb(iobase + 5);
outb(iobase + 5, temp | 0x80);
outb(iobase + 8, 0x00);
outb(0x3D8, 0x29);
outb(0x3BF, 0x01);
}
#if 1
static Bool
ET4000MinimalProbe(void)
{
unsigned char origVal, newVal;
int iobase;
PDEBUG(" ET4000MinimalProbe\n");
iobase = VGAHW_GET_IOBASE();
(void) inb(iobase + 0x0A);
TsengUnlock();
outb(0x3C0, 0x16 | 0x20);
origVal = inb(0x3C1);
outb(0x3C0, origVal ^ 0x10);
outb(0x3C0, 0x16 | 0x20);
newVal = inb(0x3C1);
outb(0x3C0, origVal);
if (newVal != (origVal ^ 0x10)) {
return (FALSE);
}
outb(iobase + 0x04, 0x33);
origVal = inb(iobase + 0x05);
outb(iobase + 0x05, origVal ^ 0x0F);
newVal = inb(iobase + 0x05);
outb(iobase + 0x05, origVal);
if (newVal != (origVal ^ 0x0F)) {
return (FALSE);
}
return TRUE;
}
#endif
static int
TsengFindIsaDevice(GDevPtr dev)
{
if (ET4000MinimalProbe())
return TYPE_TSENG;
return -1;
}
static Bool
TsengProbe(DriverPtr drv, int flags)
{
int i;
GDevPtr *devSections;
int numDevSections;
int numUsed;
int *usedChips = NULL;
Bool foundScreen = FALSE;
PDEBUG(" TsengProbe\n");
if ((numDevSections = xf86MatchDevice(TSENG_DRIVER_NAME,
&devSections)) <= 0) {
return FALSE;
}
numUsed = 0;
if (xf86GetPciVideoInfo() != NULL) {
numUsed = xf86MatchPciInstances(TSENG_NAME, PCI_VENDOR_TSENG,
TsengChipsets, TsengPciChipsets,
devSections,numDevSections, drv,
&usedChips);
if (numUsed > 0) {
if (flags & PROBE_DETECT)
foundScreen = TRUE;
else for (i = 0; i < numUsed; i++) {
ScrnInfoPtr pScrn = NULL;
if ((pScrn = xf86ConfigPciEntity(pScrn,0,usedChips[i],
TsengPciChipsets,NULL,
NULL,NULL,NULL,NULL))) {
TsengAssignFPtr(pScrn);
foundScreen = TRUE;
}
}
xfree(usedChips);
}
}
numUsed = xf86MatchIsaInstances(TSENG_NAME, TsengChipsets,
TsengIsaChipsets,drv, TsengFindIsaDevice, devSections,
numDevSections, &usedChips);
if (numUsed > 0) {
if (flags & PROBE_DETECT)
foundScreen = TRUE;
else for (i = 0; i < numUsed; i++) {
ScrnInfoPtr pScrn = NULL;
if ((pScrn = xf86ConfigIsaEntity(pScrn,0,usedChips[i],
TsengIsaChipsets,NULL,
NULL,NULL,NULL,NULL))) {
TsengAssignFPtr(pScrn);
foundScreen = TRUE;
}
}
xfree(usedChips);
}
xfree(devSections);
return foundScreen;
}
static Bool
TsengPreInitPCI(ScrnInfoPtr pScrn)
{
MessageType from;
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengPreInitPCI\n");
if (pTseng->pEnt->device->chipset && *pTseng->pEnt->device->chipset) {
pScrn->chipset = pTseng->pEnt->device->chipset;
pTseng->ChipType =
(t_tseng_type)xf86StringToToken(TsengChipsets, pScrn->chipset);
from = X_CONFIG;
} else if (pTseng->pEnt->device->chipID >= 0) {
if (!TsengPCI2Type(pScrn, pTseng->pEnt->device->chipID))
return FALSE;
pScrn->chipset = (char *)xf86TokenToString(TsengChipsets, pTseng->ChipType);
from = X_CONFIG;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
pTseng->ChipType);
} else {
from = X_PROBED;
if (!TsengPCI2Type(pScrn, pTseng->PciInfo->chipType))
return FALSE;
pScrn->chipset = (char *)xf86TokenToString(TsengChipsets, pTseng->ChipType);
}
if (pTseng->pEnt->device->chipRev >= 0) {
pTseng->ChipRev = pTseng->pEnt->device->chipRev;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
pTseng->ChipRev);
if ((pTseng->ChipType == TYPE_ET6000) && (pTseng->ChipRev >= ET6100REVID))
pTseng->ChipType = TYPE_ET6100;
} else {
t_tseng_type dum_chiptype;
t_w32_revid rev;
if (Is_ET6K) {
pTseng->ChipRev = pTseng->PciInfo->chipRev;
} else {
ET4000DetailedProbe(&dum_chiptype, &rev);
pTseng->ChipRev = rev;
}
}
if (Is_ET6K) {
xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
} else {
char ch_rev;
switch (pTseng->ChipRev) {
case W32REVID_A:
ch_rev = 'A';
break;
case W32REVID_B:
ch_rev = 'B';
break;
case W32REVID_C:
ch_rev = 'C';
break;
case W32REVID_D:
ch_rev = 'D';
break;
default:
ch_rev = 'X';
}
xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\" (rev %c)\n",
pScrn->chipset, ch_rev);
}
pTseng->PciTag = pciTag(pTseng->PciInfo->bus, pTseng->PciInfo->device,
pTseng->PciInfo->func);
if (Is_ET6K) {
if (pTseng->pEnt->device->IOBase != 0) {
pTseng->IOAddress = pTseng->pEnt->device->IOBase;
from = X_CONFIG;
} else {
if ((pTseng->PciInfo->ioBase[1]) != 0) {
pTseng->IOAddress = pTseng->PciInfo->ioBase[1];
from = X_PROBED;
} else {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"No valid PCI I/O address in PCI config space\n");
return FALSE;
}
}
xf86DrvMsg(pScrn->scrnIndex, from, "PCI I/O registers at 0x%lX\n",
(unsigned long)pTseng->IOAddress);
}
pTseng->LinFbAddressMask = 0xFF000000;
return TRUE;
}
static Bool
ET4000DetailedProbe(t_tseng_type * chiptype, t_w32_revid * rev)
{
unsigned char temp, origVal, newVal;
PDEBUG(" ET4000DetailedProbe\n");
origVal = inb(0x3cb);
outb(0x3cb, 0x33);
newVal = inb(0x3cb);
outb(0x3cb, origVal);
if (newVal != 0x33) {
*chiptype = TYPE_ET4000;
*rev = TSENGNOREV;
return TRUE;
}
outb(0x217a, 0xec);
temp = inb(0x217b) >> 4;
switch (temp) {
case 0:
*chiptype = TYPE_ET4000W32;
break;
case 1:
*chiptype = TYPE_ET4000W32I;
*rev = W32REVID_A;
break;
case 3:
*chiptype = TYPE_ET4000W32I;
*rev = W32REVID_B;
break;
case 11:
*chiptype = TYPE_ET4000W32I;
*rev = W32REVID_C;
break;
case 2:
*chiptype = TYPE_ET4000W32P;
*rev = W32REVID_A;
break;
case 5:
*chiptype = TYPE_ET4000W32P;
*rev = W32REVID_B;
break;
case 6:
*chiptype = TYPE_ET4000W32P;
*rev = W32REVID_D;
break;
case 7:
*chiptype = TYPE_ET4000W32P;
*rev = W32REVID_C;
break;
default:
return (FALSE);
}
return (TRUE);
}
static void
TsengFindNonPciBusType(ScrnInfoPtr pScrn)
{
unsigned char bus;
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengFindNonPciBusType\n");
pTseng->Bustype = T_BUS_ISA;
pTseng->Linmem_1meg = FALSE;
pTseng->LinFbAddressMask = 0;
switch (pTseng->ChipType) {
case TYPE_ET4000:
break;
case TYPE_ET4000W32:
case TYPE_ET4000W32I:
outb(0x217A, 0xEF);
bus = inb(0x217B) & 0x60;
switch (bus) {
case 0x40:
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected W32/W32i bus type: MCA\n");
pTseng->Bustype = T_BUS_MCA;
pTseng->LinFbAddressMask = 0x01C00000;
break;
case 0x60:
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected W32/W32i bus type: Local Bus\n");
pTseng->Bustype = T_BUS_VLB;
pTseng->LinFbAddressMask = 0x07C00000;
break;
case 0x00:
case 0x20:
default:
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected W32/W32i bus type (0x%02X): ISA\n", bus);
pTseng->Bustype = T_BUS_ISA;
pTseng->LinFbAddressMask = 0x00C00000;
break;
}
break;
case TYPE_ET4000W32P:
outb(0x217A, 0xEF);
bus = inb(0x217B) >> 3;
switch (bus) {
case 0x1C:
pTseng->Bustype = T_BUS_VLB;
pTseng->LinFbAddressMask = 0x3FC00000;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected W32p bus type: Local Buffered Bus\n");
pTseng->Linmem_1meg = TRUE;
break;
case 0x13:
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected W32p bus type: Local Bus (option 1a)\n");
pTseng->Bustype = T_BUS_VLB;
if (pTseng->ChipRev == W32REVID_A)
pTseng->LinFbAddressMask = 0x07C00000;
else
pTseng->LinFbAddressMask = 0x1FC00000;
break;
case 0x11:
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected W32p bus type: Local Bus (option 1b)\n");
pTseng->Bustype = T_BUS_VLB;
pTseng->LinFbAddressMask = 0x00C00000;
pTseng->Linmem_1meg = TRUE;
break;
case 0x08:
case 0x0B:
default:
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected W32p bus type: Local Bus (option 2)\n");
pTseng->Bustype = T_BUS_VLB;
pTseng->LinFbAddressMask = 0x3FC00000;
break;
}
if (Is_W32p_cd && (pTseng->LinFbAddressMask == 0x3FC00000))
pTseng->LinFbAddressMask |= 0xC0000000;
break;
case TYPE_ET6000:
case TYPE_ET6100:
pTseng->Bustype = T_BUS_PCI;
pTseng->LinFbAddressMask = 0xFF000000;
break;
case TYPE_TSENG:
break;
}
}
static Bool
TsengPreInitNoPCI(ScrnInfoPtr pScrn)
{
MessageType from;
t_w32_revid rev = TSENGNOREV;
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengPreInitNoPCI\n");
if (pTseng->pEnt->device->chipset && *pTseng->pEnt->device->chipset) {
pScrn->chipset = pTseng->pEnt->device->chipset;
pTseng->ChipType =
(t_tseng_type)xf86StringToToken(TsengChipsets, pScrn->chipset);
from = X_CONFIG;
} else if (pTseng->pEnt->device->chipID > 0) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "ChipID override only possible for PCI cards\n");
return FALSE;
} else {
from = X_PROBED;
if (!ET4000DetailedProbe(&(pTseng->ChipType), &rev)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Unknown Tseng chip detected. Try chipset override.\n");
return FALSE;
}
pScrn->chipset = (char *)xf86TokenToString(TsengChipsets, pTseng->ChipType);
}
if (pTseng->pEnt->device->chipRev >= 0) {
pTseng->ChipRev = pTseng->pEnt->device->chipRev;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
pTseng->ChipRev);
} else {
pTseng->ChipRev = rev;
}
xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset);
TsengFindNonPciBusType(pScrn);
return TRUE;
}
#define VIDMEM ((volatile CARD32*)check_vgabase)
#define SEGSIZE (64)
#define ET6K_SETSEG(seg) \
outb(0x3CB, ((seg) & 0x30) | ((seg) >> 4)); \
outb(0x3CD, ((seg) & 0x0f) | ((seg) << 4));
static int
et6000_check_videoram(ScrnInfoPtr pScrn, int ram)
{
unsigned char oldSegSel1, oldSegSel2, oldGR5, oldGR6, oldSEQ2, oldSEQ4;
int segment, i;
int real_ram = 0;
pointer check_vgabase;
Bool fooled = FALSE;
int save_vidmem;
PDEBUG(" et6000_check_videoram\n");
if (ram > 4096) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Detected more than 4096 kb of video RAM. Clipped to 4096kb\n");
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
" (Tseng VGA chips can only use 4096kb).\n");
ram = 4096;
}
if (!vgaHWMapMem(pScrn)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Could not map VGA memory to check for video memory.\n");
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
" Detected amount may be wrong.\n");
return ram;
}
check_vgabase = (VGAHWPTR(pScrn)->Base);
oldSegSel1 = inb(0x3CD);
oldSegSel2 = inb(0x3CB);
outb(0x3CE, 5);
oldGR5 = inb(0x3CF);
outb(0x3CE, 6);
oldGR6 = inb(0x3CF);
outb(0x3C4, 2);
oldSEQ2 = inb(0x3C5);
outb(0x3C4, 4);
oldSEQ4 = inb(0x3C5);
outb(0x3CE, 6);
outb(0x3CF, 5);
outb(0x3CE, 5);
outb(0x3CF, 0x40);
outb(0x3C4, 2);
outb(0x3C5, 0x0f);
outb(0x3C4, 4);
outb(0x3C5, 0x0e);
for (segment = (ram / SEGSIZE) - 1; segment >= 0; segment--) {
ET6K_SETSEG(segment);
save_vidmem = *(VIDMEM);
*VIDMEM = 0xAAAA5555;
if (*VIDMEM != 0xAAAA5555) {
*VIDMEM = save_vidmem;
continue;
}
*VIDMEM = 0x5555AAAA;
if (*VIDMEM != 0x5555AAAA) {
*VIDMEM = save_vidmem;
continue;
}
fooled = FALSE;
for (i = segment - 1; i >= 0; i--) {
ET6K_SETSEG(i);
outb(0x3CB, (i & 0x30) | (i >> 4));
outb(0x3CD, (i & 0x0f) | (i << 4));
if (*VIDMEM == 0x5555AAAA) {
ET6K_SETSEG(segment);
*VIDMEM = 0xAAAA5555;
ET6K_SETSEG(i);
if (*VIDMEM == 0xAAAA5555) {
fooled = TRUE;
break;
}
}
}
if (!fooled) {
real_ram = (segment + 1) * SEGSIZE;
break;
}
ET6K_SETSEG(segment);
*VIDMEM = save_vidmem;
}
outb(0x3CD, oldSegSel1);
outb(0x3CB, oldSegSel2);
outb(0x3CE, 5);
outb(0x3CF, oldGR5);
outb(0x3CE, 6);
outb(0x3CF, oldGR6);
outb(0x3C4, 2);
outb(0x3C5, oldSEQ2);
outb(0x3C4, 4);
outb(0x3C5, oldSEQ4);
vgaHWUnmapMem(pScrn);
return real_ram;
}
static int
TsengDoMemLimit(ScrnInfoPtr pScrn, int ram, int limit, char *reason)
{
if (ram > limit) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Only %d kb of memory can be used %s.\n",
limit, reason);
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Reducing video memory to %d kb.\n", limit);
ram = limit;
}
return ram;
}
static int
TsengLimitMem(ScrnInfoPtr pScrn, int ram)
{
TsengPtr pTseng = TsengPTR(pScrn);
if (pTseng->UseLinMem && pTseng->Linmem_1meg) {
ram = TsengDoMemLimit(pScrn, ram, 1024,
"in linear mode on "
"this VGA board/bus configuration");
}
if (pTseng->UseAccel && pTseng->UseLinMem) {
if (Is_W32_any) {
if (Is_W32p_cd)
ram = TsengDoMemLimit(pScrn, ram, 2048,
"in linear + accelerated mode "
"on W32p rev c and d");
ram = TsengDoMemLimit(pScrn, ram, 2048 + 1024,
"in linear + accelerated mode "
"on W32/W32i/W32p");
ram = TsengDoMemLimit(pScrn, ram, 4096 - 516,
"in linear + accelerated mode "
"on W32/W32i/W32p");
}
if (Is_ET6K) {
ram = TsengDoMemLimit(pScrn, ram, 4096 - 8,
"in linear + accelerated mode "
"on ET6000/6100");
}
}
ram = TsengDoMemLimit(pScrn, ram, 4096, "on any Tseng card");
return ram;
}
static int
TsengDetectMem(ScrnInfoPtr pScrn)
{
unsigned char config;
int ramtype = 0;
int ram = 0;
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengDetectMem\n");
if (Is_ET6K) {
ramtype = inb(0x3C2) & 0x03;
switch (ramtype) {
case 0x03:
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Video memory type: Multibank DRAM (MDRAM).\n");
ram = ((inb(pTseng->IOAddress + 0x47) & 0x07) + 1) * 8 * 32;
if (inb(pTseng->IOAddress + 0x45) & 0x04) {
ram <<= 1;
}
ram = et6000_check_videoram(pScrn, ram);
break;
case 0x00:
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Video memory type: Standard DRAM.\n");
ram = 1024 << (inb(pTseng->IOAddress + 0x45) & 0x03);
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Unknown ET6000 video memory type %d -- assuming 1 MB (unless specified)\n",
ramtype);
ram = 1024;
}
} else {
int iobase = VGAHWPTR(pScrn)->IOBase;
outb(iobase + 0x04, 0x37);
config = inb(iobase + 0x05);
ram = 128 << (config & 0x03);
if (config & 0x80)
ram <<= 1;
if (Is_W32i || Is_W32p) {
outb(iobase + 0x04, 0x32);
config = inb(iobase + 0x05);
if (config & 0x80) {
ram <<= 1;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Video memory type: Interleaved DRAM.\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Video memory type: Standard DRAM.\n");
}
}
}
return ram;
}
static Bool
TsengProcessHibit(ScrnInfoPtr pScrn)
{
MessageType from = X_CONFIG;
int hibit_mode_width;
int iobase;
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengProcessHibit\n");
if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_HIGH)) {
if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_LOW)) {
xf86Msg(X_ERROR, "\nOptions \"hibit_high\" and \"hibit_low\" are incompatible;\n");
xf86Msg(X_ERROR, " specify only one (not both) in XFree86 configuration file\n");
return FALSE;
}
pTseng->save_divide = 0x40;
} else if (xf86IsOptionSet(pTseng->Options, OPTION_HIBIT_HIGH)) {
pTseng->save_divide = 0;
} else {
from = X_PROBED;
iobase = VGAHWPTR(pScrn)->IOBase;
outb(iobase + 4, 1);
hibit_mode_width = inb(iobase + 5) + 1;
if (hibit_mode_width > 82) {
xf86Msg(X_WARNING, "Non-standard VGA text or graphics mode while probing for hibit:\n");
xf86Msg(X_WARNING, " probed 'hibit' value may be wrong.\n");
xf86Msg(X_WARNING, " Preferably run probe from 80x25 textmode,\n");
xf86Msg(X_WARNING, " or specify correct value in XFree86 configuration file.\n");
}
outb(0x3C4, 7);
pTseng->save_divide = inb(0x3C5) & 0x40;
}
xf86DrvMsg(pScrn->scrnIndex, from, "Initial ET4000 hibit state: %s\n",
pTseng->save_divide & 0x40 ? "high" : "low");
return TRUE;
}
static Bool
TsengProcessOptions(ScrnInfoPtr pScrn)
{
MessageType from;
double real;
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengProcessOptions\n");
xf86CollectOptions(pScrn, NULL);
if (!(pTseng->Options = xalloc(sizeof(TsengOptions))))
return FALSE;
memcpy(pTseng->Options, TsengOptions, sizeof(TsengOptions));
xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pTseng->Options);
from = X_DEFAULT;
pTseng->HWCursor = FALSE;
if (xf86GetOptValBool(pTseng->Options, OPTION_HW_CURSOR, &pTseng->HWCursor))
from = X_CONFIG;
if (xf86ReturnOptValBool(pTseng->Options, OPTION_SW_CURSOR, FALSE)) {
from = X_CONFIG;
pTseng->HWCursor = FALSE;
}
if (pTseng->HWCursor && !Is_ET6K) {
xf86DrvMsg(pScrn->scrnIndex, from,
"Hardware Cursor not supported on this chipset\n");
pTseng->HWCursor = FALSE;
}
xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
pTseng->HWCursor ? "HW" : "SW");
if (pScrn->bitsPerPixel >= 8) {
if (pTseng->ChipType != TYPE_ET4000)
pTseng->UseAccel = TRUE;
if (xf86ReturnOptValBool(pTseng->Options, OPTION_NOACCEL, FALSE)) {
pTseng->UseAccel = FALSE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
}
} else
pTseng->UseAccel = FALSE;
pTseng->SlowDram = FALSE;
if (xf86IsOptionSet(pTseng->Options, OPTION_SLOW_DRAM)) {
pTseng->SlowDram = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using slow DRAM access\n");
}
pTseng->MedDram = FALSE;
if (xf86IsOptionSet(pTseng->Options, OPTION_MED_DRAM)) {
pTseng->MedDram = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using Medium-speed DRAM access\n");
}
pTseng->FastDram = FALSE;
if (xf86IsOptionSet(pTseng->Options, OPTION_FAST_DRAM)) {
pTseng->FastDram = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using fast DRAM access\n");
}
if ((pTseng->SetW32Interleave =
xf86GetOptValBool(pTseng->Options, OPTION_W32_INTERLEAVE, &pTseng->W32Interleave)) )
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing W32p memory interleave %s.\n",
pTseng->W32Interleave ? "ON" : "OFF");
if ((pTseng->SetPCIBurst =
xf86GetOptValBool(pTseng->Options, OPTION_PCI_BURST, &pTseng->PCIBurst)) )
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing PCI burst mode %s.\n",
pTseng->PCIBurst ? "ON" : "OFF");
from = X_CONFIG;
if (xf86GetOptValBool(pTseng->Options, OPTION_LINEAR, &pTseng->UseLinMem)) {
if (pTseng->UseLinMem) {
if (!CHIP_SUPPORTS_LINEAR) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Linear memory not supported on chipset \"%s\".\n",
pScrn->chipset);
pTseng->UseLinMem = FALSE;
} else if (!xf86LinearVidMem()) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"This operating system does not support a linear framebuffer.\n");
pTseng->UseLinMem = FALSE;
}
}
} else {
from = X_DEFAULT;
if (pTseng->PciTag)
pTseng->UseLinMem = TRUE;
else
pTseng->UseLinMem = FALSE;
}
xf86DrvMsg(pScrn->scrnIndex, from, "Using %s Memory.\n",
(pTseng->UseLinMem) ? "linear" : "banked");
pTseng->ShowCache = FALSE;
if (xf86ReturnOptValBool(pTseng->Options, OPTION_SHOWCACHE, FALSE)) {
pTseng->ShowCache = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "(for debugging only:) Visible off-screen memory\n");
}
pTseng->Legend = FALSE;
if (xf86ReturnOptValBool(pTseng->Options, OPTION_LEGEND, FALSE)) {
pTseng->Legend = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using Legend pixel clock selection.\n");
}
pTseng->NoClockchip = FALSE;
if (xf86ReturnOptValBool(pTseng->Options, OPTION_NOCLOCKCHIP, FALSE)) {
pTseng->NoClockchip = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Disabling clockchip programming.\n");
}
if (pTseng->NoClockchip)
pScrn->progClock = FALSE;
pTseng->UsePCIRetry = FALSE;
if (xf86ReturnOptValBool(pTseng->Options, OPTION_PCI_RETRY, FALSE)) {
pTseng->UsePCIRetry = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI retry enabled\n");
}
pTseng->MemClk = 0;
if (xf86GetOptValFreq(pTseng->Options, OPTION_SET_MCLK, OPTUNITS_MHZ, &real))
pTseng->MemClk = (int)(real * 1000.0);
return TRUE;
}
static Bool
TsengGetLinFbAddress(ScrnInfoPtr pScrn)
{
MessageType from;
TsengPtr pTseng = TsengPTR(pScrn);
resRange range[] = { {ResExcMemBlock|ResBus,0,0},_END };
PDEBUG(" TsengGetLinFbAddress\n");
if (pTseng->pEnt->device->MemBase != 0) {
pTseng->LinFbAddress = pTseng->pEnt->device->MemBase;
from = X_CONFIG;
if ((pTseng->LinFbAddress & (~pTseng->LinFbAddressMask)) != 0) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"MemBase out of range. Must be <= 0x%lx on 0x%lx boundary.\n",
pTseng->LinFbAddressMask, ~(pTseng->LinFbAddressMask | 0xFF000000) + 1);
pTseng->LinFbAddress &= ~pTseng->LinFbAddressMask;
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, " Clipping MemBase to: 0x%lx.\n",
pTseng->LinFbAddress);
range[0].rBegin = pTseng->LinFbAddress;
range[0].rEnd = pTseng->LinFbAddress + 16 * 1024 * 1024;
if (xf86RegisterResources(pTseng->pEnt->index,range,ResNone)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
" Cannot register linear memory."
" Using banked mode instead.\n");
pTseng->UseLinMem = FALSE;
return TRUE;
}
}
} else {
from = X_PROBED;
if (pTseng->PciTag) {
if ((pTseng->PciInfo->memBase[0]) != 0) {
pTseng->LinFbAddress = pTseng->PciInfo->memBase[0];
} else {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"No valid Framebuffer address in PCI config space;\n");
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
" Falling back to banked mode.\n");
pTseng->UseLinMem = FALSE;
return TRUE;
}
if (xf86RegisterResources(pTseng->pEnt->index,NULL,ResNone)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
" Cannot register linear memory."
" Using banked mode instead.\n");
pTseng->UseLinMem = FALSE;
return TRUE;
}
} else {
#define DEFAULT_LIN_MEMBASE ( (256 + 128 + 64 + 32 + 16 + 8 + 4) * 1024*1024 )
#define DEFAULT_LIN_MEMBASE_PCI (DEFAULT_LIN_MEMBASE & 0xFF000000)
switch (pTseng->ChipType) {
case TYPE_ET4000W32:
case TYPE_ET4000W32I:
case TYPE_ET4000W32P:
pTseng->LinFbAddress = DEFAULT_LIN_MEMBASE;
if (pTseng->LinFbAddress > pTseng->LinFbAddressMask)
pTseng->LinFbAddress = pTseng->LinFbAddressMask - 4 * 1024 * 1024;
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"TsengNonPciLinMem(): Internal error. This should not happen: please report to XFree86@XFree86.Org\n");
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
" Falling back to banked mode.\n");
pTseng->UseLinMem = FALSE;
return TRUE;
}
pTseng->LinFbAddress &= pTseng->LinFbAddressMask;
if (pTseng->LinFbAddress < 4096 * 1024) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Invalid MemBase for linear mode:\n");
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
" please define a non-zero MemBase in XF86Config.\n");
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
" See README.tseng or tseng.sgml for more information.\n");
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
" Using banked mode instead.\n");
pTseng->UseLinMem = FALSE;
return TRUE;
}
range[0].type |= ResBios;
range[0].rBegin = pTseng->LinFbAddress;
range[0].rEnd = pTseng->LinFbAddress + 16 * 1024 * 1024;
if (xf86RegisterResources(pTseng->pEnt->index,range,ResNone)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
" Cannot register linear memory."
" Using banked mode instead.\n");
pTseng->UseLinMem = FALSE;
return TRUE;
}
}
}
if (Is_ET6K)
pTseng->FbMapSize = 16384 * 1024;
else
pTseng->FbMapSize = 4096 * 1024;
xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n",
(unsigned long)pTseng->LinFbAddress);
return TRUE;
}
static Bool
TsengPreInit(ScrnInfoPtr pScrn, int flags)
{
TsengPtr pTseng;
MessageType from;
int i;
if (flags & PROBE_DETECT) return FALSE;
PDEBUG(" TsengPreInit\n");
if (pScrn->numEntities > 1)
return FALSE;
if (!TsengGetRec(pScrn)) {
return FALSE;
}
pTseng = TsengPTR(pScrn);
pTseng->pEnt = xf86GetEntityInfo(*pScrn->entityList);
#if 1
if (xf86LoadSubModule(pScrn, "int10")) {
xf86Int10InfoPtr pInt;
xf86LoaderReqSymLists(int10Symbols, NULL);
#if 1
xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
pInt = xf86InitInt10(pTseng->pEnt->index);
xf86FreeInt10(pInt);
#endif
}
#endif
if (!xf86LoadSubModule(pScrn, "vgahw"))
return FALSE;
xf86LoaderReqSymLists(vgaHWSymbols, NULL);
if (!vgaHWGetHWRec(pScrn))
return FALSE;
vgaHWGetIOBase(VGAHWPTR(pScrn));
TsengUnlock();
if (pTseng->pEnt->location.type == BUS_PCI) {
pTseng->PciInfo = xf86GetPciInfoForEntity(pTseng->pEnt->index);
if (!TsengPreInitPCI(pScrn)) {
TsengFreeRec(pScrn);
return FALSE;
}
} else if (!TsengPreInitNoPCI(pScrn)) {
TsengFreeRec(pScrn);
return FALSE;
}
if (!Check_Tseng_Ramdac(pScrn))
return FALSE;
if (!Tseng_check_clockchip(pScrn)) {
return FALSE;
}
pScrn->monitor = pScrn->confScreen->monitor;
if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support24bppFb | Support32bppFb |
SupportConvert32to24 | PreferConvert32to24)) {
return FALSE;
} else {
Bool CanDo16bpp = FALSE, CanDo24bpp = FALSE, CanDo32bpp = FALSE;
Bool CanDoThis = FALSE;
switch (pTseng->DacInfo.DacType) {
case ET6000_DAC:
case ICS5341_DAC:
case STG1703_DAC:
case STG1702_DAC:
CanDo16bpp = TRUE;
CanDo24bpp = TRUE;
CanDo32bpp = TRUE;
break;
case ATT20C490_DAC:
case ATT20C491_DAC:
case ATT20C492_DAC:
case ATT20C493_DAC:
case ICS5301_DAC:
case MUSIC4910_DAC:
CanDo16bpp = TRUE;
CanDo24bpp = TRUE;
break;
case CH8398_DAC:
CanDo16bpp = TRUE;
CanDo24bpp = TRUE;
break;
case STG1700_DAC:
CanDo16bpp = TRUE;
CanDo32bpp = TRUE;
break;
default:
break;
}
switch (pScrn->depth) {
case 1:
case 4:
case 8:
CanDoThis = TRUE;
break;
case 16:
CanDoThis = CanDo16bpp;
break;
case 24:
CanDoThis = (CanDo24bpp || CanDo32bpp);
break;
}
if (!CanDoThis) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Given depth (%d) is not supported by this chipset/RAMDAC\n",
pScrn->depth);
return FALSE;
}
if ((pScrn->bitsPerPixel == 32) && (!CanDo32bpp)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Given bpp (%d) is not supported by this chipset/RAMDAC\n",
pScrn->bitsPerPixel);
return FALSE;
}
}
xf86PrintDepthBpp(pScrn);
if (pScrn->depth == 24 && pix24bpp == 0)
pix24bpp = xf86GetBppFromDepth(pScrn, 24);
if (pScrn->bitsPerPixel > 8)
pTseng->Bytesperpixel = pScrn->bitsPerPixel / 8;
else
pTseng->Bytesperpixel = 1;
pScrn->maxHValue = Tseng_HMAX;
pScrn->maxVValue = Tseng_VMAX;
if (pScrn->depth > 8) {
rgb zeros = {0, 0, 0};
rgb mask;
if ((pScrn->depth == 24) && (pScrn->bitsPerPixel == 24))
mask = pTseng->DacInfo.rgb24packed;
else
mask = zeros;
if (!xf86SetWeight(pScrn, zeros, mask)) {
return FALSE;
} else {
;
}
}
if (!xf86SetDefaultVisual(pScrn, -1))
return FALSE;
if (pScrn->depth > 1) {
Gamma zeros = {0.0, 0.0, 0.0};
if (!xf86SetGamma(pScrn, zeros)) {
return FALSE;
}
}
if (pScrn->depth == 8) {
pScrn->rgbBits = 6;
}
if (!TsengProcessOptions(pScrn))
return FALSE;
if (pTseng->UseLinMem) {
if (!TsengGetLinFbAddress(pScrn))
return FALSE;
}
if (pTseng->UseAccel)
VGAHWPTR(pScrn)->MapSize = 0x20000;
else
VGAHWPTR(pScrn)->MapSize = 0x10000;
if (pTseng->UseLinMem) {
xf86SetOperatingState(resVgaMem, pTseng->pEnt->index, ResDisableOpr);
}
pTseng->save_divide = 0x40;
if (!Is_ET6K) {
if (!TsengProcessHibit(pScrn))
return FALSE;
}
if (pTseng->pEnt->device->videoRam != 0) {
pScrn->videoRam = pTseng->pEnt->device->videoRam;
from = X_CONFIG;
} else {
from = X_PROBED;
pScrn->videoRam = TsengDetectMem(pScrn);
}
pScrn->videoRam = TsengLimitMem(pScrn, pScrn->videoRam);
xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte.\n",
pScrn->videoRam);
tseng_clock_setup(pScrn);
i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
pScrn->display->modes, pTseng->clockRange[0],
NULL, 32, pScrn->maxHValue, 8*pTseng->Bytesperpixel,
0, pScrn->maxVValue,
pScrn->display->virtualX,
pScrn->display->virtualY,
pTseng->FbMapSize,
LOOKUP_BEST_REFRESH);
if (i == -1) {
TsengFreeRec(pScrn);
return FALSE;
}
xf86PruneDriverModes(pScrn);
if (i == 0 || pScrn->modes == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
TsengFreeRec(pScrn);
return FALSE;
}
xf86SetCrtcForModes(pScrn, 0);
pScrn->currentMode = pScrn->modes;
xf86PrintModes(pScrn);
xf86SetDpi(pScrn, 0, 0);
switch (pScrn->bitsPerPixel) {
case 1:
if (xf86LoadSubModule(pScrn, "xf1bpp") == NULL) {
TsengFreeRec(pScrn);
return FALSE;
}
xf86LoaderReqSymbols("xf1bppScreenInit", NULL);
break;
case 4:
if (xf86LoadSubModule(pScrn, "xf4bpp") == NULL) {
TsengFreeRec(pScrn);
return FALSE;
}
xf86LoaderReqSymbols("xf4bppScreenInit", NULL);
break;
default:
if (xf86LoadSubModule(pScrn, "fb") == NULL) {
TsengFreeRec(pScrn);
return FALSE;
}
xf86LoaderReqSymLists(fbSymbols, NULL);
break;
}
if (pTseng->UseAccel) {
if (!xf86LoadSubModule(pScrn, "xaa")) {
TsengFreeRec(pScrn);
return FALSE;
}
xf86LoaderReqSymLists(xaaSymbols, NULL);
}
if (pTseng->HWCursor) {
if (!xf86LoadSubModule(pScrn, "ramdac")) {
TsengFreeRec(pScrn);
return FALSE;
}
xf86LoaderReqSymLists(ramdacSymbols, NULL);
}
return TRUE;
}
static void
TsengSetupAccelMemory(int scrnIndex, ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
TsengPtr pTseng = TsengPTR(pScrn);
int offscreen_videoram, videoram_end, req_videoram;
int i;
int v;
if (serverGeneration == 1)
v = 1;
else
v = 100;
videoram_end = pScrn->videoRam * 1024;
offscreen_videoram = videoram_end -
pScrn->displayWidth * pScrn->virtualY * pTseng->Bytesperpixel;
xf86DrvMsgVerb(scrnIndex, X_INFO, v, "Available off-screen memory: %d bytes.\n",
offscreen_videoram);
if (pTseng->HWCursor) {
req_videoram = 1024;
if (offscreen_videoram < req_videoram) {
xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
"Hardware Cursor disabled. It requires %d bytes of free video memory\n",
req_videoram);
pTseng->HWCursor = FALSE;
pTseng->HWCursorBufferOffset = 0;
} else {
offscreen_videoram -= req_videoram;
videoram_end -= req_videoram;
pTseng->HWCursorBufferOffset = videoram_end;
}
} else {
pTseng->HWCursorBufferOffset = 0;
}
if (!pTseng->UseAccel) return;
req_videoram = 2 * 8 * 3;
if (offscreen_videoram < req_videoram) {
xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
"Acceleration disabled. It requires AT LEAST %d bytes of free video memory\n",
req_videoram);
pTseng->UseAccel = FALSE;
pTseng->AccelColorBufferOffset = 0;
goto end_memsetup;
} else {
offscreen_videoram -= req_videoram;
videoram_end -= req_videoram;
pTseng->AccelColorBufferOffset = videoram_end;
}
req_videoram = 3 * ((pScrn->virtualX + 31) / 32) * 4;
if (offscreen_videoram < req_videoram) {
xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
"Accelerated color expansion disabled (%d more bytes of free video memory required)\n",
req_videoram - offscreen_videoram);
pTseng->AccelColorExpandBufferOffsets[0] = 0;
} else {
offscreen_videoram -= req_videoram;
for (i = 0; i < 3; i++) {
videoram_end -= req_videoram / 3;
pTseng->AccelColorExpandBufferOffsets[i] = videoram_end;
}
}
req_videoram = 2 * (pScrn->virtualX * pTseng->Bytesperpixel);
if ((req_videoram > 8192) && (!pTseng->UseLinMem)) {
xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
"Accelerated ImageWrites disabled (banked %dbpp virtual width must be <= %d)\n",
pScrn->bitsPerPixel, 8192 / (2 * pTseng->Bytesperpixel));
pTseng->AccelImageWriteBufferOffsets[0] = 0;
} else if (offscreen_videoram < req_videoram) {
xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, v,
"Accelerated ImageWrites disabled (%d more bytes of free video memory required)\n",
req_videoram - offscreen_videoram);
pTseng->AccelImageWriteBufferOffsets[0] = 0;
} else {
offscreen_videoram -= req_videoram;
for (i = 0; i < 2; i++) {
videoram_end -= req_videoram / 2;
pTseng->AccelImageWriteBufferOffsets[i] = videoram_end;
}
}
xf86DrvMsgVerb(scrnIndex, X_INFO, v,
"Remaining off-screen memory available for pixmap cache: %d bytes.\n",
offscreen_videoram);
end_memsetup:
pScrn->videoRam = videoram_end / 1024;
}
static Bool
TsengScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
{
ScrnInfoPtr pScrn;
TsengPtr pTseng;
int ret;
VisualPtr visual;
PDEBUG(" TsengScreenInit\n");
pScrn = xf86Screens[pScreen->myNum];
pTseng = TsengPTR(pScrn);
if (!TsengMapMem(pScrn))
return FALSE;
TsengSave(pScrn);
TsengModeInit(pScrn, pScrn->currentMode);
TsengSaveScreen(pScreen, SCREEN_SAVER_ON);
TsengAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
miClearVisualTypes();
if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
pScrn->rgbBits, pScrn->defaultVisual))
return FALSE;
miSetPixmapDepths ();
switch (pScrn->bitsPerPixel) {
case 1:
ret = xf1bppScreenInit(pScreen, pTseng->FbBase,
pScrn->virtualX, pScrn->virtualY,
pScrn->xDpi, pScrn->yDpi,
pScrn->displayWidth);
break;
case 4:
ret = xf4bppScreenInit(pScreen, pTseng->FbBase,
pScrn->virtualX, pScrn->virtualY,
pScrn->xDpi, pScrn->yDpi,
pScrn->displayWidth);
break;
default:
ret = fbScreenInit(pScreen, pTseng->FbBase,
pScrn->virtualX, pScrn->virtualY,
pScrn->xDpi, pScrn->yDpi,
pScrn->displayWidth, pScrn->bitsPerPixel);
break;
}
if (!ret)
return FALSE;
xf86SetBlackWhitePixels(pScreen);
if (pScrn->bitsPerPixel > 8) {
visual = pScreen->visuals + pScreen->numVisuals;
while (--visual >= pScreen->visuals) {
if ((visual->class | DynamicClass) == DirectColor) {
visual->offsetRed = pScrn->offset.red;
visual->offsetGreen = pScrn->offset.green;
visual->offsetBlue = pScrn->offset.blue;
visual->redMask = pScrn->mask.red;
visual->greenMask = pScrn->mask.green;
visual->blueMask = pScrn->mask.blue;
}
}
}
if (pScrn->bitsPerPixel > 4)
fbPictureInit(pScreen, 0, 0);
if (pScrn->depth >= 8)
TsengDGAInit(pScreen);
if (!pTseng->UseLinMem) {
if (!Is_stdET4K && (pScrn->videoRam > 1024)) {
pTseng->BankInfo.SetSourceBank = ET4000W32SetRead;
pTseng->BankInfo.SetDestinationBank = ET4000W32SetWrite;
pTseng->BankInfo.SetSourceAndDestinationBanks = ET4000W32SetReadWrite;
} else {
pTseng->BankInfo.SetSourceBank = ET4000SetRead;
pTseng->BankInfo.SetDestinationBank = ET4000SetWrite;
pTseng->BankInfo.SetSourceAndDestinationBanks = ET4000SetReadWrite;
}
pTseng->BankInfo.pBankA = pTseng->FbBase;
pTseng->BankInfo.pBankB = pTseng->FbBase;
pTseng->BankInfo.BankSize = 0x10000;
pTseng->BankInfo.nBankDepth = (pScrn->depth == 4) ? 1 : pScrn->depth;
if (!miInitializeBanking(pScreen, pScrn->virtualX, pScrn->virtualY,
pScrn->displayWidth, &pTseng->BankInfo)) {
return FALSE;
}
}
TsengSetupAccelMemory(scrnIndex, pScreen);
if (pTseng->UseAccel) {
tseng_init_acl(pScrn);
if (!TsengXAAInit(pScreen)) {
return FALSE;
}
}
miInitializeBackingStore(pScreen);
xf86SetSilkenMouse(pScreen);
miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
if (pTseng->HWCursor) {
if (!TsengHWCursorInit(pScreen))
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Hardware cursor initialization failed\n");
}
if (!miCreateDefColormap(pScreen))
return FALSE;
if (pScrn->depth == 4 || pScrn->depth == 8) {
vgaHWHandleColormaps(pScreen);
}
pScrn->racIoFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT;
pScrn->racMemFlags = pScrn->racIoFlags;
pScreen->SaveScreen = TsengSaveScreen;
if (Is_W32p_cd || Is_ET6K) {
xf86DPMSInit(pScreen, (DPMSSetProcPtr)TsengCrtcDPMSSet, 0);
} else {
xf86DPMSInit(pScreen, (DPMSSetProcPtr)TsengHVSyncDPMSSet, 0);
}
pTseng->CloseScreen = pScreen->CloseScreen;
pScreen->CloseScreen = TsengCloseScreen;
if (serverGeneration == 1) {
xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
}
return TRUE;
}
static Bool
TsengEnterVT(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengEnterVT\n");
vgaHWUnlock(VGAHWPTR(pScrn));
TsengUnlock();
if (!TsengModeInit(pScrn, pScrn->currentMode))
return FALSE;
if (pTseng->UseAccel) {
tseng_init_acl(pScrn);
}
return TRUE;
}
static void
TsengLeaveVT(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengLeaveVT\n");
TsengRestore(pScrn, &(VGAHWPTR(pScrn)->SavedReg),
&pTseng->SavedReg,VGA_SR_ALL);
TsengLock();
vgaHWLock(VGAHWPTR(pScrn));
}
static Bool
TsengCloseScreen(int scrnIndex, ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengCloseScreen\n");
if (pScrn->vtSema) {
TsengRestore(pScrn, &(VGAHWPTR(pScrn)->SavedReg),
&(pTseng->SavedReg),VGA_SR_ALL);
TsengUnmapMem(pScrn);
}
if (pTseng->AccelInfoRec)
XAADestroyInfoRec(pTseng->AccelInfoRec);
if (pTseng->CursorInfoRec)
xf86DestroyCursorInfoRec(pTseng->CursorInfoRec);
pScrn->vtSema = FALSE;
pScreen->CloseScreen = pTseng->CloseScreen;
return (*pScreen->CloseScreen) (scrnIndex, pScreen);
}
static Bool
TsengSaveScreen(ScreenPtr pScreen, int mode)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
TsengPtr pTseng = TsengPTR(pScrn);
Bool unblank;
PDEBUG(" TsengSaveScreen\n");
unblank = xf86IsUnblank(mode);
if (Is_ET6K) {
return vgaHWSaveScreen(pScreen, unblank);
} else {
if (unblank)
SetTimeSinceLastInputEvent();
if (pScrn->vtSema) {
TsengBlankScreen(pScrn, unblank);
}
return (TRUE);
}
}
static Bool
TsengMapMem(ScrnInfoPtr pScrn)
{
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengMapMem\n");
if (!vgaHWMapMem(pScrn)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Could not mmap standard VGA memory aperture.\n");
return FALSE;
}
if (pTseng->UseLinMem) {
pTseng->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
pTseng->PciTag,
(unsigned long)pTseng->LinFbAddress,
pTseng->FbMapSize);
if (pTseng->FbBase == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Could not mmap linear video memory.\n");
return FALSE;
}
if (pTseng->UseAccel) {
pTseng->MMioBase = xf86MapPciMem(pScrn->scrnIndex,
VIDMEM_MMIO,
pTseng->PciTag,
(unsigned long)pTseng->LinFbAddress,
pTseng->FbMapSize);
if (!pTseng->MMioBase) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Could not mmap mmio memory.\n");
return FALSE;
}
pTseng->MMioBase += 0x3FFF00L;
}
} else {
vgaHWPtr hwp = VGAHWPTR(pScrn);
pTseng->FbBase = hwp->Base;
if (pTseng->UseAccel) {
pTseng->MMioBase = xf86MapPciMem(pScrn->scrnIndex,
VIDMEM_MMIO,
pTseng->PciTag,
(unsigned long)hwp->MapPhys,
hwp->MapSize);
if (!pTseng->MMioBase) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Could not mmap mmio memory.\n");
return FALSE;
}
pTseng->MMioBase += 0x1FF00L;
}
}
if (pTseng->FbBase == NULL)
return FALSE;
return TRUE;
}
static Bool
TsengUnmapMem(ScrnInfoPtr pScrn)
{
TsengPtr pTseng = TsengPTR(pScrn);
PDEBUG(" TsengUnmapMem\n");
if (pTseng->UseLinMem) {
xf86UnMapVidMem(pScrn->scrnIndex, (pointer) pTseng->FbBase, pTseng->FbMapSize);
}
vgaHWUnmapMem(pScrn);
pTseng->FbBase = NULL;
return TRUE;
}
static void
TsengFreeScreen(int scrnIndex, int flags)
{
PDEBUG(" TsengFreeScreen\n");
if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
vgaHWFreeHWRec(xf86Screens[scrnIndex]);
TsengFreeRec(xf86Screens[scrnIndex]);
}
Bool
TsengModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
vgaHWPtr hwp;
TsengPtr pTseng = TsengPTR(pScrn);
TsengRegPtr new = &(pTseng->ModeReg);
TsengRegPtr initial = &(pTseng->SavedReg);
int row_offset;
int min_n2;
int hdiv = 1, hmul = 1;
PDEBUG(" TsengModeInit\n");
switch (mode->PrivFlags) {
case TSENG_MODE_PIXMUX:
case TSENG_MODE_DACBUS16:
hdiv = pTseng->clockRange[1]->ClockDivFactor;
hmul = pTseng->clockRange[1]->ClockMulFactor;
break;
default:
hdiv = pTseng->clockRange[0]->ClockDivFactor;
hmul = pTseng->clockRange[0]->ClockMulFactor;
}
if (!mode->CrtcHAdjusted) {
mode->CrtcHTotal = (mode->CrtcHTotal * hmul) / hdiv;
mode->CrtcHDisplay = (mode->CrtcHDisplay * hmul) / hdiv;
mode->CrtcHSyncStart = (mode->CrtcHSyncStart * hmul) / hdiv;
mode->CrtcHSyncEnd = (mode->CrtcHSyncEnd * hmul) / hdiv;
mode->CrtcHBlankStart = (mode->CrtcHBlankStart * hmul) / hdiv;
mode->CrtcHBlankEnd = (mode->CrtcHBlankEnd * hmul) / hdiv;
mode->CrtcHSkew = (mode->CrtcHSkew * hmul) / hdiv;
if (pScrn->bitsPerPixel == 24) {
int rgb_skew;
rgb_skew = (mode->CrtcHTotal / 8 - mode->CrtcHBlankEnd / 8 - 1) % 3;
mode->CrtcHBlankEnd += rgb_skew * 8 + 24;
if (mode->CrtcHBlankEnd > mode->CrtcHTotal)
mode->CrtcHBlankEnd -= 24;
}
mode->CrtcHAdjusted = TRUE;
}
if (pScrn->progClock)
mode->ClockIndex = 2;
hwp = VGAHWPTR(pScrn);
if (!vgaHWInit(pScrn, mode))
return (FALSE);
pScrn->vtSema = TRUE;
memcpy(new, initial, sizeof(TsengRegRec));
if (pScrn->bitsPerPixel < 8) {
if (Is_ET6K)
hwp->ModeReg.Sequencer[1] |= 0x04;
row_offset = hwp->ModeReg.CRTC[19];
} else {
hwp->ModeReg.Attribute[16] = 0x01;
row_offset = pScrn->displayWidth >> 3;
}
hwp->ModeReg.CRTC[20] = 0x60;
hwp->ModeReg.CRTC[23] = 0xAB;
new->ExtTS[6] = 0x00;
new->ExtTS[7] = 0xBC;
new->ExtCRTC[0x33] = 0x00;
new->ExtCRTC[0x35] = (mode->Flags & V_INTERLACE ? 0x80 : 0x00)
| 0x10
| ((mode->CrtcVSyncStart & 0x400) >> 7)
| (((mode->CrtcVDisplay - 1) & 0x400) >> 8)
| (((mode->CrtcVTotal - 2) & 0x400) >> 9)
| (((mode->CrtcVBlankStart - 1) & 0x400) >> 10);
if (pScrn->bitsPerPixel < 8)
new->ExtATC = 0x00;
else
new->ExtATC = 0x80;
if (pScrn->bitsPerPixel >= 8) {
if (pTseng->FastDram && !Is_ET6K) {
new->ExtCRTC[0x32] &= ~0x1F;
if (new->ExtCRTC[0x32] & 0x18)
new->ExtCRTC[0x32] |= 0x08;
new->ExtCRTC[0x32] &= ~0x20;
}
}
if (Is_W32i || Is_W32p) {
if (!pTseng->SlowDram)
new->ExtCRTC[0x34] = (new->ExtCRTC[0x34] & 0x7F) | 0x80;
if ((mode->Clock * pTseng->Bytesperpixel) > 80000)
new->ExtCRTC[0x37] = (new->ExtCRTC[0x37] & 0x7f) | 0x80;
if (pTseng->SetW32Interleave) {
if (pTseng->W32Interleave)
new->ExtCRTC[0x32] |= 0x80;
else
new->ExtCRTC[0x32] &= 0x7F;
}
}
if (Is_W32p) {
if (pTseng->SetPCIBurst) {
if (pTseng->PCIBurst)
new->ExtCRTC[0x34] |= 0x10;
else
new->ExtCRTC[0x34] &= 0xEF;
}
}
if (STG170x_programmable_clock || Gendac_programmable_clock) {
if (mode->PrivFlags == TSENG_MODE_PIXMUX)
min_n2 = 2;
else
min_n2 = 0;
TsengcommonCalcClock(mode->SynthClock, 1, 1, 31, min_n2, 3,
100000, pTseng->max_vco_freq,
&(new->pll.f2_M), &(new->pll.f2_N));
new->pll.w_idx = 0;
new->pll.r_idx = 0;
if (Gendac_programmable_clock && pTseng->MClkInfo.Set) {
TsengcommonCalcClock(pTseng->MClkInfo.MemClk, 1, 1, 31, 1, 3, 100000, pTseng->MaxClock * 2 + 1,
&(new->pll.MClkM), &(new->pll.MClkN));
}
} else if (ICD2061a_programmable_clock) {
#ifdef TODO
pTseng->icd2061_dwv = AltICD2061CalcClock(mode->SynthClock * 1000);
#endif
} else if (CH8398_programmable_clock) {
#ifdef TODO
Chrontel8391CalcClock(mode->SynthClock, &temp1, &temp2, &temp3);
new->pll.f2_N = (unsigned char)(temp2);
new->pll.f2_M = (unsigned char)(temp1 | (temp3 << 6));
new->pll.ctrl = (new->pll.ctrl | 0x90) & 0xF0;
new->pll.timingctrl &= 0x1F;
new->pll.r_idx = 0;
new->pll.w_idx = 0;
#endif
} else if (Is_ET6K) {
TsengcommonCalcClock(mode->SynthClock, 1, 1, 31, 1, 3, 100000,
pTseng->max_vco_freq,
&(new->pll.f2_M), &(new->pll.f2_N));
if (mode->Clock * pTseng->Bytesperpixel > 130000) {
new->ExtET6K[0x41] |= 0x10;
if (Is_ET6100)
new->ExtET6K[0x46] |= 0x04;
} else {
new->ExtET6K[0x41] &= ~0x10;
if (Is_ET6100)
new->ExtET6K[0x46] &= ~0x04;
}
if (pTseng->MClkInfo.Set) {
TsengcommonCalcClock(pTseng->MClkInfo.MemClk, 1, 1, 4, 1, 1,
100000, pTseng->MaxClock * 2,
&(new->pll.MClkM), &(new->pll.MClkN));
}
if (pTseng->FastDram)
new->ExtET6K[0x44] = 0x04;
else if (pTseng->MedDram)
new->ExtET6K[0x44] = 0x15;
else if (pTseng->SlowDram)
new->ExtET6K[0x44] = 0x35;
else
;
}
if (mode->ClockIndex >= 0) {
new->ExtCRTC[0x34] = (new->ExtCRTC[0x34] & 0xFD) |
((mode->ClockIndex & 0x04) >> 1);
new->ExtTS[7] = (new->ExtTS[7] & 0xBE);
if (!pScrn->progClock) {
new->ExtTS[7] |= (pTseng->save_divide ^ ((mode->ClockIndex & 0x08) << 3));
}
new->ExtCRTC[0x31] = ((mode->ClockIndex & 0x10) << 2) | (new->ExtCRTC[0x31] & 0x3F);
}
if (Is_ET6K) {
if (pTseng->UseLinMem) {
new->ExtET6K[0x13] = pTseng->LinFbAddress >> 24;
new->ExtET6K[0x40] |= 0x09;
} else {
new->ExtET6K[0x40] &= ~0x09;
}
} else {
if (pTseng->UseLinMem) {
new->ExtCRTC[0x36] |= 0x10;
if (Is_W32p || Is_ET6K)
new->ExtCRTC[0x30] = (pTseng->LinFbAddress >> 22) & 0xFF;
else
new->ExtCRTC[0x30] = ((pTseng->LinFbAddress >> 22) & 0x1F) ^ 0x1c;
hwp->ModeReg.Graphics[6] &= ~0x0C;
new->ExtIMACtrl &= ~0x01;
} else {
new->ExtCRTC[0x36] &= ~0x10;
if (pTseng->ChipType < TYPE_ET4000W32P)
new->ExtCRTC[0x30] = 0x1C;
else
new->ExtCRTC[0x30] = 0x00;
}
}
if (pScrn->bitsPerPixel >= 8) {
tseng_set_ramdac_bpp(pScrn, mode);
row_offset *= pTseng->Bytesperpixel;
}
hwp->ModeReg.CRTC[19] = row_offset;
new->ExtCRTC[0x3F] = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8)
| ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7)
| ((((mode->CrtcHBlankStart >> 3) - 1) & 0x100) >> 6)
| (((mode->CrtcHSyncStart >> 3) & 0x100) >> 4)
| ((row_offset & 0x200) >> 3)
| ((row_offset & 0x100) >> 1);
if (pTseng->UseAccel) {
if (Is_ET6K) {
if (pTseng->UseLinMem)
new->ExtET6K[0x40] |= 0x02;
else
new->ExtET6K[0x40] |= 0x06;
} else {
new->ExtCRTC[0x36] |= 0x28;
}
}
vgaHWUnlock(hwp);
TsengRestore(pScrn, &hwp->ModeReg, new, VGA_SR_MODE);
return TRUE;
}
static Bool
TsengSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
{
PDEBUG(" TsengSwitchMode\n");
return TsengModeInit(xf86Screens[scrnIndex], mode);
}
void
TsengAdjustFrame(int scrnIndex, int x, int y, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
TsengPtr pTseng = TsengPTR(pScrn);
int iobase = VGAHWPTR(pScrn)->IOBase;
int Base;
PDEBUG(" TsengAdjustFrame\n");
if (pTseng->ShowCache) {
if (y)
y += 256;
}
if (pScrn->bitsPerPixel < 8)
Base = (y * pScrn->displayWidth + x + 3) >> 3;
else {
Base = ((y * pScrn->displayWidth + x + 1) * pTseng->Bytesperpixel) >> 2;
Base -= (Base % pTseng->Bytesperpixel);
}
outw(iobase + 4, (Base & 0x00FF00) | 0x0C);
outw(iobase + 4, ((Base & 0x00FF) << 8) | 0x0D);
outw(iobase + 4, ((Base & 0x0F0000) >> 8) | 0x33);
}
static ModeStatus
TsengValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
{
PDEBUG(" TsengValidMode\n");
#ifdef FIXME
is this needed? xf86ValidMode gets HMAX and VMAX variables, so it could deal with this.
need to recheck hsize with mode->Htotal*mulFactor/divFactor
if (mode->HTotal > Tseng_HMAX) {
return MODE_BAD_HVALUE;
}
if (mode->VTotal > Tseng_VMAX) {
return MODE_BAD_VVALUE;
}
#endif
return MODE_OK;
}
static void
TsengSave(ScrnInfoPtr pScrn)
{
unsigned char temp, saveseg1 = 0, saveseg2 = 0;
TsengPtr pTseng = TsengPTR(pScrn);
vgaRegPtr vgaReg;
TsengRegPtr tsengReg;
int iobase = VGAHWPTR(pScrn)->IOBase;
PDEBUG(" TsengSave\n");
vgaReg = &VGAHWPTR(pScrn)->SavedReg;
tsengReg = &pTseng->SavedReg;
vgaHWSave(pScrn, vgaReg, VGA_SR_ALL);
outb(iobase + 4, 0x34);
temp = inb(iobase + 5);
tsengReg->ExtCRTC[0x34] = temp;
if (Is_stdET4K || Is_W32_W32i || Is_W32p_ab) {
#ifdef OLD_CODE
outb(iobase + 5, temp & 0x1F);
#else
outb(iobase + 5, temp & 0xCF);
#endif
}
saveseg1 = inb(0x3CD);
outb(0x3CD, 0x00);
if (!Is_stdET4K) {
saveseg2 = inb(0x3CB);
outb(0x3CB, 0x00);
}
tsengReg->ExtSegSel[0] = saveseg1;
tsengReg->ExtSegSel[1] = saveseg2;
outb(iobase + 4, 0x33);
tsengReg->ExtCRTC[0x33] = inb(iobase + 5);
outb(iobase + 4, 0x35);
tsengReg->ExtCRTC[0x35] = inb(iobase + 5);
if (Is_W32_any) {
outb(iobase + 4, 0x36);
tsengReg->ExtCRTC[0x36] = inb(iobase + 5);
outb(iobase + 4, 0x37);
tsengReg->ExtCRTC[0x37] = inb(iobase + 5);
outb(0x217a, 0xF7);
tsengReg->ExtIMACtrl = inb(0x217b);
}
if (!Is_ET6K) {
outb(iobase + 4, 0x32);
tsengReg->ExtCRTC[0x32] = inb(iobase + 5);
}
outb(0x3C4, 6);
tsengReg->ExtTS[6] = inb(0x3C5);
outb(0x3C4, 7);
tsengReg->ExtTS[7] = inb(0x3C5);
tsengReg->ExtTS[7] |= 0x14;
temp = inb(iobase + 0x0A);
outb(0x3C0, 0x36);
tsengReg->ExtATC = inb(0x3C1);
outb(0x3C0, tsengReg->ExtATC);
if (DAC_is_GenDAC) {
outb(iobase + 4, 0x31);
temp = inb(iobase + 5);
outb(iobase + 5, temp | 0x40);
tsengReg->pll.cmd_reg = inb(0x3c6);
tsengReg->pll.w_idx = inb(0x3c8);
tsengReg->pll.r_idx = inb(0x3c7);
if (Gendac_programmable_clock) {
outb(0x3c7, 2);
tsengReg->pll.f2_M = inb(0x3c9);
tsengReg->pll.f2_N = inb(0x3c9);
outb(0x3c7, 10);
#ifdef TODO
tsengReg->MClkInfo.MClkM = inb(0x3c9);
tsengReg->MClkInfo.MClkN = inb(0x3c9);
#endif
}
outb(0x3c7, 0x0e);
tsengReg->pll.ctrl = inb(0x3c9);
outb(iobase + 4, 0x31);
outb(iobase + 5, temp & ~0x40);
}
if ((pTseng->DacInfo.DacType == STG1702_DAC) || (pTseng->DacInfo.DacType == STG1703_DAC)
|| (pTseng->DacInfo.DacType == STG1700_DAC)) {
#ifdef TODO
tseng_dactopel();
tsengReg->pll.cmd_reg = tseng_getdaccomm();
if (STG170x_programmable_clock) {
tsengReg->pll.f2_M = STG1703getIndex(0x24);
tsengReg->pll.f2_N = inb(0x3c6);
}
tsengReg->pll.ctrl = STG1703getIndex(0x03);
tsengReg->pll.timingctrl = STG1703getIndex(0x05);
#endif
}
if (DAC_IS_CHRONTEL) {
tseng_dactopel();
tsengReg->pll.cmd_reg = tseng_getdaccomm();
if (CH8398_programmable_clock) {
inb(0x3c8);
inb(0x3c6);
inb(0x3c6);
inb(0x3c6);
inb(0x3c6);
inb(0x3c6);
tsengReg->pll.timingctrl = inb(0x3c6);
outb(iobase + 4, 0x31);
temp = inb(iobase + 5);
outb(iobase + 5, temp | (1 << 6));
tsengReg->pll.r_idx = inb(0x3c7);
tsengReg->pll.w_idx = inb(0x3c8);
outb(0x3c7, 10);
tsengReg->pll.f2_N = inb(0x3c9);
tsengReg->pll.f2_M = inb(0x3c9);
outb(0x3c7, tsengReg->pll.r_idx);
inb(0x3c8);
inb(0x3c8);
inb(0x3c8);
inb(0x3c8);
tsengReg->pll.ctrl = inb(0x3c8);
outb(iobase + 4, 0x31);
outb(iobase + 5, temp);
}
}
if (ET6000_programmable_clock) {
temp = inb(pTseng->IOAddress + 0x67);
outb(pTseng->IOAddress + 0x67, 2);
tsengReg->pll.f2_M = inb(pTseng->IOAddress + 0x69);
tsengReg->pll.f2_N = inb(pTseng->IOAddress + 0x69);
outb(pTseng->IOAddress + 0x67, 10);
tsengReg->pll.MClkM = inb(pTseng->IOAddress + 0x69);
tsengReg->pll.MClkN = inb(pTseng->IOAddress + 0x69);
outb(pTseng->IOAddress + 0x67, temp);
}
if (DAC_IS_ATT49x)
tsengReg->ATTdac_cmd = tseng_getdaccomm();
if (Is_ET6K) {
tsengReg->ExtET6K[0x13] = inb(pTseng->IOAddress + 0x13);
tsengReg->ExtET6K[0x40] = inb(pTseng->IOAddress + 0x40);
tsengReg->ExtET6K[0x58] = inb(pTseng->IOAddress + 0x58);
tsengReg->ExtET6K[0x41] = inb(pTseng->IOAddress + 0x41);
tsengReg->ExtET6K[0x44] = inb(pTseng->IOAddress + 0x44);
tsengReg->ExtET6K[0x46] = inb(pTseng->IOAddress + 0x46);
}
outb(iobase + 4, 0x30);
tsengReg->ExtCRTC[0x30] = inb(iobase + 5);
outb(iobase + 4, 0x31);
tsengReg->ExtCRTC[0x31] = inb(iobase + 5);
outb(iobase + 4, 0x3F);
tsengReg->ExtCRTC[0x3F] = inb(iobase + 5);
}
static void
TsengRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, TsengRegPtr tsengReg,
int flags)
{
TsengPtr pTseng;
unsigned char tmp;
int iobase = VGAHWPTR(pScrn)->IOBase;
PDEBUG(" TsengRestore\n");
pTseng = TsengPTR(pScrn);
TsengProtect(pScrn, TRUE);
outb(0x3CD, 0x00);
if (!Is_stdET4K)
outb(0x3CB, 0x00);
if (DAC_is_GenDAC) {
outb(iobase + 4, 0x31);
tmp = inb(iobase + 5);
outb(iobase + 5, tmp | 0x40);
outb(0x3c6, tsengReg->pll.cmd_reg);
if (Gendac_programmable_clock) {
outb(0x3c8, 2);
outb(0x3c9, tsengReg->pll.f2_M);
outb(0x3c9, tsengReg->pll.f2_N);
#ifdef TODO
if (pTseng->MClkInfo.Set) {
outb(0x3c7, 10);
outb(0x3c9, tsengReg->MClkM);
outb(0x3c9, tsengReg->MClkN);
}
#endif
}
outb(0x3c8, 0x0e);
outb(0x3c9, tsengReg->pll.ctrl);
outb(0x3c8, tsengReg->pll.w_idx);
outb(0x3c7, tsengReg->pll.r_idx);
outb(iobase + 4, 0x31);
outb(iobase + 5, tmp & ~0x40);
}
if (DAC_is_STG170x) {
#ifdef TODO
if (STG170x_programmable_clock) {
STG1703setIndex(0x24, tsengReg->pll.f2_M);
outb(0x3c6, tsengReg->pll.f2_N);
}
STG1703setIndex(0x03, tsengReg->pll.ctrl);
outb(0x3c6, tsengReg->pll.ctrl);
outb(0x3c6, tsengReg->pll.timingctrl);
usleep(500);
STG1703magic(0);
tseng_dactopel();
tseng_setdaccomm(tsengReg->pll.cmd_reg);
#endif
}
if (DAC_IS_CHRONTEL) {
tseng_dactopel();
tseng_setdaccomm(tsengReg->pll.cmd_reg);
inb(0x3c8);
inb(0x3c6);
inb(0x3c6);
inb(0x3c6);
inb(0x3c6);
inb(0x3c6);
outb(0x3c6, tsengReg->pll.timingctrl);
if (CH8398_programmable_clock) {
outb(iobase + 4, 0x31);
tmp = inb(iobase + 5);
outb(iobase + 5, tmp | (1 << 6));
outb(0x3c7, tsengReg->pll.r_idx);
outb(0x3c8, 10);
outb(0x3c9, tsengReg->pll.f2_N);
outb(0x3c9, tsengReg->pll.f2_M);
outb(0x3c8, tsengReg->pll.w_idx);
usleep(500);
inb(0x3c7);
inb(0x3c8);
inb(0x3c8);
inb(0x3c8);
inb(0x3c8);
outb(0x3c8, tsengReg->pll.ctrl);
outb(iobase + 4, 0x31);
outb(iobase + 5, (tmp & 0x3F));
}
}
if (ET6000_programmable_clock) {
tmp = inb(pTseng->IOAddress + 0x67);
outb(pTseng->IOAddress + 0x67, 2);
outb(pTseng->IOAddress + 0x69, tsengReg->pll.f2_M);
outb(pTseng->IOAddress + 0x69, tsengReg->pll.f2_N);
if (pTseng->MClkInfo.Set) {
if ((tsengReg->pll.MClkN & 0xf8) != 0x20) {
xf86Msg(X_ERROR, "Internal Error in MClk registers: MClkM=0x%x, MClkN=0x%x\n",
tsengReg->pll.MClkM, tsengReg->pll.MClkN);
} else {
outb(pTseng->IOAddress + 0x67, 10);
outb(pTseng->IOAddress + 0x69, tsengReg->pll.MClkM);
outb(pTseng->IOAddress + 0x69, tsengReg->pll.MClkN);
}
}
outb(pTseng->IOAddress + 0x67, tmp);
}
if (DAC_IS_ATT49x)
tseng_setdaccomm(tsengReg->ATTdac_cmd);
if (Is_ET6K) {
outb(pTseng->IOAddress + 0x13, tsengReg->ExtET6K[0x13]);
outb(pTseng->IOAddress + 0x40, tsengReg->ExtET6K[0x40]);
outb(pTseng->IOAddress + 0x58, tsengReg->ExtET6K[0x58]);
outb(pTseng->IOAddress + 0x41, tsengReg->ExtET6K[0x41]);
outb(pTseng->IOAddress + 0x44, tsengReg->ExtET6K[0x44]);
outb(pTseng->IOAddress + 0x46, tsengReg->ExtET6K[0x46]);
}
outw(iobase + 4, (tsengReg->ExtCRTC[0x3F] << 8) | 0x3F);
outw(iobase + 4, (tsengReg->ExtCRTC[0x30] << 8) | 0x30);
outw(iobase + 4, (tsengReg->ExtCRTC[0x31] << 8) | 0x31);
vgaHWRestore(pScrn, vgaReg, flags);
outw(0x3C4, (tsengReg->ExtTS[6] << 8) | 0x06);
outw(0x3C4, (tsengReg->ExtTS[7] << 8) | 0x07);
tmp = inb(iobase + 0x0A);
outb(0x3C0, 0x36);
outb(0x3C0, tsengReg->ExtATC);
outw(iobase + 4, (tsengReg->ExtCRTC[0x33] << 8) | 0x33);
outw(iobase + 4, (tsengReg->ExtCRTC[0x34] << 8) | 0x34);
outw(iobase + 4, (tsengReg->ExtCRTC[0x35] << 8) | 0x35);
if (Is_W32_any) {
outw(iobase + 4, (tsengReg->ExtCRTC[0x37] << 8) | 0x37);
outw(0x217a, (tsengReg->ExtIMACtrl << 8) | 0xF7);
}
if (!Is_ET6K) {
outw(iobase + 4, (tsengReg->ExtCRTC[0x32] << 8) | 0x32);
}
outb(0x3CD, tsengReg->ExtSegSel[0]);
if (pTseng->ChipType > TYPE_ET4000)
outb(0x3CB, tsengReg->ExtSegSel[1]);
#ifdef TODO
if (pTseng->Legend) {
if (tsengReg->ClockIndex >= 0) {
vgaProtect(TRUE);
(ClockSelect) (tsengReg->ClockIndex);
}
#endif
TsengProtect(pScrn, FALSE);
if (Is_W32_any) {
outw(iobase + 4, (tsengReg->ExtCRTC[0x36] << 8) | 0x36);
}
}
void
TsengBlankScreen(ScrnInfoPtr pScrn, Bool unblank)
{
unsigned char scrn;
PDEBUG(" TsengBlankScreen\n");
outb(0x3C4,1);
scrn = inb(0x3C5);
if(unblank) {
scrn &= 0xDF;
}else {
scrn |= 0x20;
}
outw(0x3C4, (scrn << 8) | 0x01);
}
void
TsengProtect(ScrnInfoPtr pScrn, Bool on)
{
PDEBUG(" TsengProtect\n");
vgaHWProtect(pScrn, on);
}
#ifdef OLD_DRIVER
#include "tseng_cursor.h"
extern vgaHWCursorRec vgaHWCursor;
static Bool
ET4000Probe()
{
int numClocks;
Bool autodetect = TRUE;
...
if (pScrn->bitsPerPixel >= 8) {
...
if ((pTseng->ChipType < TYPE_ET4000W32) || (pTseng->Linmem_1meg && pTseng->UseLinMem)) {
tseng_use_ACL = FALSE;
} else {
OFLG_SET(OPTION_NOACCEL, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_PCI_RETRY, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_SHOWCACHE, &TSENG.ChipOptionFlags);
tseng_use_ACL = !OFLG_ISSET(OPTION_NOACCEL, &vga256InfoRec.options);
}
...
#ifdef W32_HW_CURSOR_FIXED
if (pTseng->ChipType >= TYPE_ET4000W32P)
#else
if (Is_ET6K)
#endif
{
OFLG_SET(OPTION_HW_CURSOR, &TSENG.ChipOptionFlags);
}
}
else {
OFLG_CLR(OPTION_HW_CURSOR, &vga256InfoRec.options);
pTseng->UseLinMem = FALSE;
tseng_use_ACL = FALSE;
}
if (!Is_ET6K) {
OFLG_SET(OPTION_LEGEND, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_HIBIT_HIGH, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_HIBIT_LOW, &TSENG.ChipOptionFlags);
if (pScrn->bitsPerPixel >= 8) {
OFLG_SET(OPTION_PCI_BURST_ON, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_PCI_BURST_OFF, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_W32_INTERLEAVE_ON, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_W32_INTERLEAVE_OFF, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_SLOW_DRAM, &TSENG.ChipOptionFlags);
OFLG_SET(OPTION_FAST_DRAM, &TSENG.ChipOptionFlags);
}
if (pTseng->ChipType <= TYPE_ET4000W32) {
ErrorF("%s %s: option \"slow_dram\" is enabled by default on this card.\n",
XCONFIG_PROBED, vga256InfoRec.name);
OFLG_SET(OPTION_SLOW_DRAM, &vga256InfoRec.options);
}
...
vga256InfoRec.bankedMono = TRUE;
...
return (TRUE);
}
#endif