/* $XFree86: xc/programs/Xserver/hw/xfree86/accel/mach64/mach64.c,v 3.62.2.20 1999/10/12 17:18:42 hohndel Exp $ */ /* * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. * Copyright 1993,1994,1995,1996,1997 by Kevin E. Martin, Chapel Hill, North Carolina. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Thomas Roell not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Thomas Roell makes no representations * about the suitability of this software for any purpose. It is provided * "as is" without express or implied warranty. * * THOMAS ROELL, KEVIN E. MARTIN, AND RICKARD E. FAITH DISCLAIM ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHORS * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Thomas Roell, roell@informatik.tu-muenchen.de * * Rewritten for the 8514/A by Kevin E. Martin (martin@cs.unc.edu) * Modified for the Mach-8 by Rickard E. Faith (faith@cs.unc.edu) * Rewritten for the Mach32 by Kevin E. Martin (martin@cs.unc.edu) * Rewritten for the Mach64 by Kevin E. Martin (martin@cs.unc.edu) * Support for the Mach64 CT added by David Dawes (dawes@XFree86.org) * */ /* $XConsortium: mach64.c /main/34 1996/10/28 04:46:47 kaleb $ */ #include "X.h" #include "Xmd.h" #include "input.h" #include "scrnintstr.h" #include "pixmapstr.h" #include "mipointer.h" #include "cursorstr.h" #include "mi.h" #include "cfb.h" #include "cfb16.h" #include "cfb32.h" #include "gc.h" #include "windowstr.h" #include "compiler.h" #include "xf86.h" #include "xf86Priv.h" #include "xf86Procs.h" #include "xf86_OSlib.h" #include "xf86_HWlib.h" #include "mach64.h" #ifdef PIXPRIV #include "mach64im.h" #endif #ifdef DPMSExtension #include "opaque.h" #include "extensions/dpms.h" #endif #include "xf86_PCI.h" #define XCONFIG_FLAGS_ONLY #include "xf86_Config.h" #ifdef XFreeXDGA #include "X.h" #include "Xproto.h" #include "scrnintstr.h" #include "servermd.h" #define _XF86DGA_SERVER_ #include "extensions/xf86dgastr.h" #endif extern int defaultColorVisualClass; extern int mach64MaxClock; extern Bool xf86Resetting, xf86Exiting, xf86ProbeFailed; extern void mach64QueryBestSize(); extern void mach64WarpCursor(); extern void mach64RepositionCursor(); extern Bool miDCInitialize(); extern void SetTimeSinceLastInputEvent(); unsigned int mach64MemorySize = 0; unsigned int mach64ApertureSize = 0; unsigned long mach64ApertureAddr = 0; unsigned long mach64RegisterAddr = 0; extern char *xf86VisualNames[]; #ifdef PIXPRIV int mach64PixmapIndex; #endif static int mach64ValidMode( #if NeedFunctionPrototypes DisplayModePtr, Bool, int #endif ); ScrnInfoRec mach64InfoRec = { FALSE, /* Bool configured */ -1, /* int tmpIndex */ -1, /* int scrnIndex */ mach64Probe, /* Bool (* Probe)() */ mach64Initialize, /* Bool (* Init)() */ mach64ValidMode, /* int (* ValidMode)() */ mach64EnterLeaveVT, /* void (* EnterLeaveVT)() */ (void (*)())NoopDDA,/* void (* EnterLeaveMonitor)() */ (void (*)())NoopDDA,/* void (* EnterLeaveCursor)() */ mach64AdjustFrame, /* void (* AdjustFrame)() */ mach64SwitchMode, /* Bool (* SwitchMode)() */ mach64DPMSSet ,/* void (* DPMSSet)() */ mach64PrintIdent, /* void (* PrintIdent)() */ 8, /* int depth */ {5, 6, 5}, /* xrgb weight */ 8, /* int bitsPerPixel */ PseudoColor, /* int defaultVisual */ -1, -1, /* int virtualX,virtualY */ -1, /* int displayWidth */ -1, -1, -1, -1, /* int frameX0, frameY0, frameX1, frameY1 */ {0, }, /* OFlagSet options */ {0, }, /* OFlagSet clockOptions */ {0, }, /* OFlagSet xconfigFlag */ NULL, /* char *chipset */ NULL, /* char *ramdac */ {0, 0, 0, 0}, /* int dacSpeeds[MAXDACSPEEDS] */ 0, /* int dacSpeedBpp */ 0, /* int clocks */ {0, }, /* int clock[MAXCLOCKS] */ 0, /* int maxClock */ 0, /* int videoRam */ 0xC0000, /* int BIOSbase */ 0, /* unsigned long MemBase */ 240, 180, /* int width, height */ 0, /* unsigned long speedup */ NULL, /* DisplayModePtr modes */ NULL, /* MonPtr monitor */ NULL, /* char *clockprog */ -1, /* int textclock */ FALSE, /* Bool bankedMono */ "Mach64", /* char *name */ {0, }, /* xrgb blackColour */ {0, }, /* xrgb whiteColour */ mach64ValidTokens, /* int *validTokens */ MACH64_PATCHLEVEL, /* char *patchlevel */ 0, /* int IObase */ 0, /* int PALbase */ 0, /* int COPbase */ 0, /* int POSbase */ 0, /* int instance */ 0, /* int s3Madjust */ 0, /* int s3Nadjust */ 0, /* int s3MClk */ 0, /* int chipID */ 0, /* int chipRev */ 0, /* unsigned long VGAbase */ 0, /* int s3RefClk */ -1, /* int s3BlankDelay */ 0, /* int textClockFreq */ NULL, /* char* DCConfig */ NULL, /* char* DCOptions */ 0, /* int MemClk */ 0 /* int LCDClk */ #ifdef XFreeXDGA ,0, /* int directMode */ NULL, /* Set Vid Page */ 0, /* unsigned long physBase */ 0 /* int physSize */ #endif }; int mach64alu[16] = { MIX_0, MIX_AND, MIX_SRC_AND_NOT_DST, MIX_SRC, MIX_NOT_SRC_AND_DST, MIX_DST, MIX_XOR, MIX_OR, MIX_NOR, MIX_XNOR, MIX_NOT_DST, MIX_SRC_OR_NOT_DST, MIX_NOT_SRC, MIX_NOT_SRC_OR_DST, MIX_NAND, MIX_1 }; extern miPointerScreenFuncRec xf86PointerScreenFuncs; LUTENTRY mach64savedLUT[256]; static Bool LUTissaved = FALSE; int mach64MaxX, mach64MaxY; int mach64VirtX, mach64VirtY; Bool mach64Use4MbAperture = FALSE; Bool mach64DAC8Bit = FALSE; static unsigned Mach64_IOPorts[] = { /* VGA Registers */ 0x3B4, 0x3B5, 0x3BA, 0x3C0, 0x3C1, 0x3C2, 0x3C4, 0x3C5, 0x3C6, 0x3C7, 0x3C8, 0x3C9, 0x3CA, 0x3CB, 0x3CC, 0x3CE, 0x3CF, 0x3D4, 0x3D5, 0x3DA, /* ATI VGA Registers */ sioATIEXT, sioATIEXT+1, /* Mach64 Registers */ 0x400, /* This is enough to ensure access to all registers */ }; static int Num_Mach64_IOPorts = (sizeof(Mach64_IOPorts)/ sizeof(Mach64_IOPorts[0])); short mach64WeightMask; static mach64CRTCRegRec mach64CRTCRegs; static ScreenPtr savepScreen = NULL; static PixmapPtr ppix = NULL; static int mach64HWCursorSave = -1; unsigned ioCONFIG_CHIP_ID; unsigned ioCONFIG_CNTL; unsigned ioSCRATCH_REG0; unsigned ioSCRATCH_REG1; unsigned ioCONFIG_STAT0; unsigned ioMEM_CNTL; unsigned ioDAC_REGS; unsigned ioDAC_CNTL; unsigned ioGEN_TEST_CNTL; unsigned ioCLOCK_CNTL; unsigned ioCRTC_H_TOTAL_DISP; unsigned ioCRTC_H_SYNC_STRT_WID; unsigned ioCRTC_V_TOTAL_DISP; unsigned ioCRTC_V_SYNC_STRT_WID; unsigned ioCRTC_GEN_CNTL; unsigned ioLCD_GEN_CTRL; unsigned ioLCD_INDEX; unsigned ioLCD_DATA; unsigned ioHORZ_STRETCHING; unsigned ioVERT_STRETCHING; unsigned ATIExtReg; /* * ATI Hardware Probe * */ typedef struct ATIInformationBlock { char board_identifier[2]; char equipment_flags[2]; char asic_identifier; int bios_major; int bios_minor; char bios_date[21]; int VGA_Wonder_Present; int Mach64_Present; int Bus_Type; int Mem_Size; int Mem_Type; int DAC_Type; int DAC_SubType; int Clock_Type; int Clocks[MACH64_NUM_CLOCKS]; mach64FreqRec Freq_Table[MACH64_NUM_FREQS]; mach64FreqRec Freq_Table2[MACH64_NUM_FREQS]; int MinFreq; int MaxFreq; int RefFreq; int RefDivider; int NAdj; int DRAMMemClk; int VRAMMemClk; int MemCycle; int MemClk; int CXClk; int ChipType; int ChipRev; int PanelID; int LCDHorizontal; int LCDVertical; } ATIInformationBlock; typedef struct ATIPCIInformation { int ChipType; int ChipRev; unsigned long ApertureBase; unsigned long IOBase; unsigned long RegisterBase; Bool BlockIO; } ATIPCIInformation; SymTabRec mach64RamdacTableNames[] = { { DAC_INTERNAL, "internal" }, { DAC_IBMRGB514, "ibm_rgb514" }, { DAC_ATI68875, "ati68875" }, { DAC_ATI68875, "tlc34075" }, { DAC_TVP3026_A, "tvp3026" }, { DAC_BT476, "bt476" }, { DAC_BT476, "bt478" }, { DAC_BT476, "inmos176" }, { DAC_BT476, "inmos178" }, { DAC_BT481, "bt481" }, { DAC_ATT20C491, "att20c491" }, { DAC_SC15026, "sc15026" }, { DAC_MU9C1880, "mu9c1880" }, { DAC_IMSG174, "ims_g174" }, { DAC_ATI68860_B, "ati68860" }, { DAC_ATI68860_B, "ati68860b" }, { DAC_ATI68860_C, "ati68860c" }, { DAC_TVP3026_B, "tvp3026" }, { DAC_STG1700, "stg1700" }, { DAC_ATT498, "att20c498" }, { DAC_ATT498, "att498" }, { DAC_STG1702, "stg1702" }, { DAC_SC15021, "sc15021" }, { DAC_ATT21C498, "att21c498" }, { DAC_STG1703, "stg1703" }, { DAC_CH8398, "ch8398" }, { DAC_ATT20C408, "att20c408" }, { -1, "" }, }; SymTabRec mach64RamdacTable[] = { { DAC_INTERNAL, "Internal" }, { DAC_IBMRGB514, "IBM-RGB514" }, { DAC_ATI68875, "ATI-68875/TLC34075" }, { DAC_TVP3026_A, "TVP3026" }, { DAC_BT476, "Bt476/Bt478/INMOS176/INMOS178" }, { DAC_BT481, "Bt481" }, { DAC_ATT20C491, "AT&T20C491" }, { DAC_SC15026, "SC15026" }, { DAC_MU9C1880, "MU9C1880" }, { DAC_IMSG174, "IMS-G174" }, { DAC_ATI68860_B, "ATI68860 Rev B" }, { DAC_ATI68860_C, "ATI68860 Rev C" }, { DAC_TVP3026_B, "TVP3026" }, { DAC_STG1700, "STG1700" }, { DAC_ATT498, "AT&T20C498" }, { DAC_STG1702, "STG1702" }, { DAC_SC15021, "SC15021" }, { DAC_ATT21C498, "AT&T21C498" }, { DAC_STG1703, "STG1703" }, { DAC_CH8398, "CH8398" }, { DAC_ATT20C408, "AT&T20C408" }, { -1, "" }, }; SymTabRec mach64ChipTable[] = { { MACH64_GX_ID, "Mach64 GX" }, { MACH64_CX_ID, "Mach64 CX" }, { MACH64_CT_ID, "Mach64 CT" }, { MACH64_ET_ID, "Mach64 ET" }, { MACH64_VT_ID, "Mach64 VT" }, { MACH64_VU_ID, "Mach64 VT3" }, { MACH64_GT_ID, "Mach64 GT" }, { MACH64_GU_ID, "Mach64 RageII+DVD" }, { MACH64_GB_ID, "Mach64 RagePro" }, { MACH64_GD_ID, "Mach64 RagePro" }, { MACH64_GI_ID, "Mach64 RagePro" }, { MACH64_GP_ID, "Mach64 RagePro" }, { MACH64_GQ_ID, "Mach64 RagePro" }, { MACH64_VV_ID, "Mach64 VT4" }, { MACH64_GV_ID, "Mach64 Rage IIC" }, { MACH64_GW_ID, "Mach64 Rage IIC" }, { MACH64_GZ_ID, "Mach64 Rage IIC" }, { MACH64_LD_ID, "Mach64 Rage LT Pro" }, { MACH64_LG_ID, "Mach64 Rage LT" }, { MACH64_LB_ID, "Mach64 Rage LT Pro" }, { MACH64_LI_ID, "Mach64 Rage LT Pro" }, { MACH64_LP_ID, "Mach64 Rage LT Pro" }, { MACH64_GL_ID, "Mach64 Rage XL or XC" }, { MACH64_GM_ID, "Mach64 Rage XL or XC" }, { MACH64_GN_ID, "Mach64 Rage XL or XC" }, { MACH64_GO_ID, "Mach64 Rage XL or XC" }, { MACH64_GR_ID, "Mach64 Rage XL or XC" }, { MACH64_GS_ID, "Mach64 Rage XL or XC" }, { MACH64_LM_ID, "Mach64 Rage Mobility" }, { MACH64_LN_ID, "Mach64 Rage Mobility" }, { MACH64_LR_ID, "Mach64 Rage Mobility" }, { MACH64_LS_ID, "Mach64 Rage Mobility" }, { -1, "" }, }; char *mach64ClockTypeTable[] = { "ATI18818-0", "ATI18818-1/ICS2595", "STG1703", "CH8398", "Internal", "AT&T20C408", "IBM-RGB514", }; #define NUM_CLOCK_TYPES (sizeof(mach64ClockTypeTable) / sizeof(char *)) int mach64Ramdac; int mach64RamdacSubType; int mach64BusType; int mach64MemType; int mach64ChipType; int mach64ChipRev; int mach64ClockType; int mach64Clocks[MACH64_NUM_CLOCKS]; mach64FreqRec mach64FreqTable[MACH64_NUM_FREQS]; mach64FreqRec mach64FreqTable2[MACH64_NUM_FREQS]; int mach64MinFreq; int mach64MaxFreq; int mach64RefFreq; int mach64RefDivider; int mach64NAdj; int mach64CXClk; int mach64MemClk; int mach64DRAMMemClk; int mach64VRAMMemClk; int mach64MemCycle; Bool mach64IntegratedController; Bool mach64HasDSP; Bool mach64HasBlockWrite; Bool mach64AGP; int mach64LCDPanelID = -1; int mach64LCDClock = 0; int mach64LCDHorizontal = 0; int mach64LCDVertical = 0; static int LCDHSyncStart, LCDHSyncWidth, LCDHBlankWidth; static int LCDVSyncStart, LCDVSyncWidth, LCDVBlankWidth; static ATIInformationBlock *GetATIInformationBlock(BlockIO) Bool BlockIO; { #define BIOS_DATA_SIZE 0x10000 char signature[] = " 761295520"; char bios_data[BIOS_DATA_SIZE]; char bios_signature[10]; #define sbios_data(_n) (*((CARD16 *)(bios_data + (_n)))) int tmp,tmp2,i,j; static ATIInformationBlock info = { 0, }; int ROM_Table_Offset; int Freq_Table_Ptr; int CDepth_Table_Ptr; int CTable_Size; int LCDTable; int LCDPanelInfo; if (xf86ReadBIOS(mach64InfoRec.BIOSbase, 0x30, (unsigned char *)bios_signature, 10) != 10) { return NULL; } if (strncmp( signature, bios_signature, 10 )) { #ifdef DEBUG ErrorF("Mach64 probe failed on BIOS signature\n"); #endif return NULL; } if (xf86ReadBIOS(mach64InfoRec.BIOSbase, 0x00, (unsigned char *)bios_data, BIOS_DATA_SIZE) != BIOS_DATA_SIZE) { return NULL; } info.board_identifier[0] = bios_data[ 0x40 ]; info.board_identifier[1] = bios_data[ 0x41 ]; info.equipment_flags[0] = bios_data[ 0x42 ]; info.equipment_flags[1] = bios_data[ 0x44 ]; info.asic_identifier = bios_data[ 0x43 ]; info.bios_major = bios_data[ 0x4c ]; info.bios_minor = bios_data[ 0x4d ]; strncpy( info.bios_date, bios_data + 0x50, 20 ); info.VGA_Wonder_Present = bios_data[ 0x44 ] & 0x40; info.Mach64_Present = 1; /* Test for Mach64 product */ tmp = inl(ioSCRATCH_REG0); outl(ioSCRATCH_REG0, 0x55555555); if (inl(ioSCRATCH_REG0) != 0x55555555) { info.Mach64_Present = 0; #ifdef DEBUG ErrorF("Mach64 probe failed on read 1 of SCRATCH_REG0 %x\n", ioSCRATCH_REG0); #endif } else { outl(ioSCRATCH_REG0, 0xaaaaaaaa); if (inl(ioSCRATCH_REG0) != 0xaaaaaaaa) { info.Mach64_Present = 0; #ifdef DEBUG ErrorF("Mach64 probe failed on read 2 of SCRATCH_REG0 %x\n", ioSCRATCH_REG0); #endif } } outl(ioSCRATCH_REG0, tmp); if (!info.Mach64_Present) return &info; tmp = inl(ioCONFIG_CHIP_ID); if (mach64InfoRec.chipID) { ErrorF("%s %s: Mach64 chipset override, using ChipID 0x%04x instead" " of 0x%04x\n", XCONFIG_GIVEN, mach64InfoRec.name, mach64InfoRec.chipID & CFG_CHIP_TYPE, tmp & CFG_CHIP_TYPE); tmp = (tmp & ~CFG_CHIP_TYPE) | (mach64InfoRec.chipID & CFG_CHIP_TYPE); } switch (tmp & CFG_CHIP_TYPE) { case MACH64_GX_ID: case MACH64_CX_ID: case MACH64_CT_ID: case MACH64_ET_ID: case MACH64_VT_ID: case MACH64_VU_ID: case MACH64_GT_ID: case MACH64_GU_ID: case MACH64_GB_ID: case MACH64_GD_ID: case MACH64_GI_ID: case MACH64_GP_ID: case MACH64_GQ_ID: case MACH64_VV_ID: case MACH64_GV_ID: case MACH64_GW_ID: case MACH64_GZ_ID: case MACH64_LD_ID: case MACH64_LG_ID: case MACH64_LB_ID: case MACH64_LI_ID: case MACH64_LP_ID: case MACH64_GL_ID: case MACH64_GM_ID: case MACH64_GN_ID: case MACH64_GO_ID: case MACH64_GR_ID: case MACH64_GS_ID: case MACH64_LM_ID: case MACH64_LN_ID: case MACH64_LR_ID: case MACH64_LS_ID: info.ChipType = tmp & CFG_CHIP_TYPE; break; default: /* * Assume ATI won't produce any more adapters that don't (properly) * register themselves in PCI configuration space. */ if (BlockIO) { info.ChipType = MACH64_UNKNOWN_ID; break; } info.Mach64_Present = FALSE; return &info; } if (mach64InfoRec.chipRev) { ErrorF("%s %s: Mach64 chipset override, using ChipRev 0x%02x instead" " of 0x%02x\n", XCONFIG_GIVEN, mach64InfoRec.name, mach64InfoRec.chipRev & 0xFF, (tmp & CFG_CHIP_REV) >> 24); info.ChipRev = mach64InfoRec.chipRev & 0xFF; } else { info.ChipRev = (tmp & CFG_CHIP_REV) >> 24; } #ifdef DEBUG ErrorF("CONFIG_CHIP_ID reports: %s rev %d\n", xf86TokenToString(mach64ChipTable, info.ChipType), info.ChipRev); #endif tmp = inl(ioCONFIG_STAT0); if (info.ChipType == MACH64_GX_ID || info.ChipType == MACH64_CX_ID) { info.Bus_Type = tmp & CFG_BUS_TYPE; info.Mem_Type = (tmp & CFG_MEM_TYPE) >> 3; info.DAC_Type = (tmp & CFG_INIT_DAC_TYPE) >> 9; info.DAC_SubType = (inb(ioSCRATCH_REG1+1) & 0xf0) | info.DAC_Type; } else { info.Mem_Type = tmp & CFG_MEM_TYPE_xT; info.DAC_Type = DAC_INTERNAL; info.DAC_SubType = DAC_INTERNAL; #ifdef DEBUG ErrorF("CONFIG_STAT0 reports mem type %d\n", info.Mem_Type); ErrorF("CONFIG_STAT0 is 0x%08x\n", tmp); #endif } switch (info.ChipType) { case MACH64_LG_ID: tmp2 = inl(ioLCD_GEN_CTRL); break; case MACH64_LD_ID: case MACH64_LB_ID: case MACH64_LI_ID: case MACH64_LP_ID: case MACH64_GL_ID: case MACH64_GM_ID: case MACH64_GN_ID: case MACH64_GO_ID: case MACH64_GR_ID: case MACH64_GS_ID: case MACH64_LM_ID: case MACH64_LN_ID: case MACH64_LR_ID: case MACH64_LS_ID: outb(ioLCD_INDEX, LCD_HORZ_STRETCHING); tmp2 = inl(ioLCD_DATA); #if 0 if (tmp2 & AUTO_HORZ_RATIO) #endif info.LCDHorizontal = (((tmp2 >> 20) & 0x0FF) + 1) << 3; outb(ioLCD_INDEX, LCD_EXT_VERT_STRETCH); tmp2 = inl(ioLCD_DATA); #if 0 if (tmp2 & AUTO_VERT_RATIO) #endif info.LCDVertical = ((tmp2 >> 11) & 0x7FF) + 1; outb(ioLCD_INDEX, LCD_GEN_CNTL); tmp2 = inl(ioLCD_DATA); break; default: tmp2 = 0; break; } if (tmp2 & LCD_ON) info.PanelID = (tmp & CFG_PANEL_ID) >> 16; else info.PanelID = -1; tmp = inl(ioMEM_CNTL); if (info.ChipType == MACH64_GX_ID || info.ChipType == MACH64_CX_ID || info.ChipType == MACH64_CT_ID || info.ChipType == MACH64_ET_ID || ((info.ChipType == MACH64_VT_ID || info.ChipType == MACH64_GT_ID) && !(info.ChipRev & 0x07))) { switch (tmp & MEM_SIZE_ALIAS) { case MEM_SIZE_512K: info.Mem_Size = 512; break; case MEM_SIZE_1M: info.Mem_Size = 1024; break; case MEM_SIZE_2M: info.Mem_Size = 2*1024; break; case MEM_SIZE_4M: info.Mem_Size = 4*1024; break; case MEM_SIZE_6M: info.Mem_Size = 6*1024; break; case MEM_SIZE_8M: info.Mem_Size = 8*1024; break; } } else { switch (tmp & MEM_SIZE_ALIAS_GTB) { case MEM_SIZE_512K: info.Mem_Size = 512; break; case MEM_SIZE_1M: info.Mem_Size = 1024; break; case MEM_SIZE_2M_GTB: info.Mem_Size = 2*1024; break; case MEM_SIZE_4M_GTB: info.Mem_Size = 4*1024; break; case MEM_SIZE_6M_GTB: info.Mem_Size = 6*1024; break; case MEM_SIZE_8M_GTB: info.Mem_Size = 8*1024; break; case MEM_SIZE_16M_GTB: info.Mem_Size = 16*1024; break; } } ROM_Table_Offset = sbios_data(0x48); Freq_Table_Ptr = sbios_data(ROM_Table_Offset + 0x10); info.Clock_Type = bios_data[Freq_Table_Ptr]; info.MinFreq = sbios_data(Freq_Table_Ptr + 0x02); info.MaxFreq = sbios_data(Freq_Table_Ptr + 0x04); info.RefFreq = sbios_data(Freq_Table_Ptr + 0x08); info.RefDivider = sbios_data(Freq_Table_Ptr + 0x0A); info.NAdj = sbios_data(Freq_Table_Ptr + 0x0C); info.DRAMMemClk = sbios_data(Freq_Table_Ptr + 0x10); info.VRAMMemClk = sbios_data(Freq_Table_Ptr + 0x12); info.MemClk = bios_data[Freq_Table_Ptr + 22]; info.CXClk = bios_data[Freq_Table_Ptr + 6]; CDepth_Table_Ptr = sbios_data(Freq_Table_Ptr - 0x06); Freq_Table_Ptr = sbios_data(Freq_Table_Ptr - 0x02); for (i = 0; i < MACH64_NUM_CLOCKS; i++) info.Clocks[i] = sbios_data((2 * i) + Freq_Table_Ptr); info.MemCycle = bios_data[ROM_Table_Offset + 0]; CTable_Size = bios_data[CDepth_Table_Ptr - 1]; for (i = 0, j = 0; bios_data[CDepth_Table_Ptr + i] != 0; i += CTable_Size, j++) { info.Freq_Table[j].h_disp = bios_data[CDepth_Table_Ptr + i]; info.Freq_Table[j].dacmask = bios_data[CDepth_Table_Ptr + i + 1]; info.Freq_Table[j].ram_req = bios_data[CDepth_Table_Ptr + i + 2]; info.Freq_Table[j].max_dot_clock = bios_data[CDepth_Table_Ptr + i + 3]; info.Freq_Table[j].color_depth = bios_data[CDepth_Table_Ptr + i + 4]; } info.Freq_Table[j].h_disp = 0; if (bios_data[CDepth_Table_Ptr + i + 1] != 0) { CDepth_Table_Ptr += i + 2; CTable_Size = bios_data[CDepth_Table_Ptr - 1]; for (i = 0, j = 0; bios_data[CDepth_Table_Ptr + i] != 0; i += CTable_Size, j++) { info.Freq_Table2[j].h_disp = bios_data[CDepth_Table_Ptr + i]; info.Freq_Table2[j].dacmask = bios_data[CDepth_Table_Ptr + i + 1]; info.Freq_Table2[j].ram_req = bios_data[CDepth_Table_Ptr + i + 2]; info.Freq_Table2[j].max_dot_clock = bios_data[CDepth_Table_Ptr + i + 3]; info.Freq_Table2[j].color_depth = bios_data[CDepth_Table_Ptr + i + 4]; } info.Freq_Table2[j].h_disp = 0; } else info.Freq_Table2[0].h_disp = 0; if (info.PanelID < 0) return &info; /* Pick up panel dimensions */ LCDTable = sbios_data(0x78); LCDPanelInfo = sbios_data(LCDTable + 0x0A); if (!LCDTable || !LCDPanelInfo || ((LCDTable + bios_data[LCDTable + 5]) > BIOS_DATA_SIZE) || ((LCDPanelInfo + 0x1D) > BIOS_DATA_SIZE) || ((bios_data[LCDPanelInfo] != info.PanelID) && (info.PanelID || (bios_data[LCDPanelInfo] > 0x1F) || (info.ChipType == MACH64_LB_ID) || (info.ChipType == MACH64_LD_ID) || (info.ChipType == MACH64_LG_ID) || (info.ChipType == MACH64_LI_ID) || (info.ChipType == MACH64_LP_ID)))) { /* * Scan BIOS for panel info table. */ LCDPanelInfo = 0; for (i = 0; i <= ((bios_data[2] << 9) - 0x1D); i++) { if ((bios_data[i] != info.PanelID) && (info.PanelID || (bios_data[i] > 0x1F) || (info.ChipType == MACH64_LB_ID) || (info.ChipType == MACH64_LD_ID) || (info.ChipType == MACH64_LG_ID) || (info.ChipType == MACH64_LI_ID) || (info.ChipType == MACH64_LP_ID))) continue; for (j = 0; j < 24; j++) if ((CARD8)(bios_data[i + j + 1] - 0x20) > 0x5F) { i += j; goto NextBIOSByte; } if ((info.LCDHorizontal > 8) && (info.LCDHorizontal <= 0x7F8) && (info.LCDHorizontal != sbios_data(i + 0x19))) continue; if ((info.LCDVertical > 1) && (info.LCDVertical <= 0x7FF) && (info.LCDVertical != sbios_data(i + 0x1B))) continue; if (LCDPanelInfo) { /* * More than one possibility, but don't care if all tables * describe panels of the same size. */ if ((bios_data[LCDPanelInfo + 0x19] == bios_data[i + 0x19]) && (bios_data[LCDPanelInfo + 0x1A] == bios_data[i + 0x1A]) && (bios_data[LCDPanelInfo + 0x1B] == bios_data[i + 0x1B]) && (bios_data[LCDPanelInfo + 0x1C] == bios_data[i + 0x1C])) continue; LCDPanelInfo = 0; break; } LCDPanelInfo = i; NextBIOSByte: ; } if (!LCDPanelInfo) { ErrorF("Warning: Unable to determine dimensions of panel" " (ID %d)\n", info.PanelID); info.PanelID = -1; return &info; } } info.PanelID = bios_data[LCDPanelInfo]; info.LCDHorizontal = (bios_data[LCDPanelInfo + 0x1A] << 8) + bios_data[LCDPanelInfo + 0x19]; info.LCDVertical = (bios_data[LCDPanelInfo + 0x1C] << 8) + bios_data[LCDPanelInfo + 0x1B]; return &info; } static ATIPCIInformation * GetATIPCIInformation() { static ATIPCIInformation info = { 0, }; pciConfigPtr pcrp, *pcrpp; Bool found = FALSE; int i = 0; int devid; pcrpp = xf86scanpci(mach64InfoRec.scrnIndex); if (!pcrpp) return NULL; while (pcrp = pcrpp[i]) { if ((pcrp->_vendor == PCI_ATI_VENDOR_ID) && (pcrp->_command & PCI_CMD_IO_ENABLE) && (pcrp->_command & PCI_CMD_MEM_ENABLE)) { found = TRUE; devid = pcrp->_device; switch (devid) { case PCI_MACH64_GX_ID: info.ChipType = MACH64_GX_ID; break; case PCI_MACH64_CX_ID: info.ChipType = MACH64_CX_ID; break; case PCI_MACH64_CT_ID: case PCI_MACH64_ET_ID: case PCI_MACH64_VT_ID: case PCI_MACH64_VU_ID: case PCI_MACH64_GT_ID: case PCI_MACH64_GU_ID: case PCI_MACH64_GB_ID: case PCI_MACH64_GD_ID: case PCI_MACH64_GI_ID: case PCI_MACH64_GP_ID: case PCI_MACH64_GQ_ID: case PCI_MACH64_VV_ID: case PCI_MACH64_GV_ID: case PCI_MACH64_GW_ID: case PCI_MACH64_GZ_ID: case PCI_MACH64_LD_ID: case PCI_MACH64_LG_ID: case PCI_MACH64_LB_ID: case PCI_MACH64_LI_ID: case PCI_MACH64_LP_ID: case PCI_MACH64_GL_ID: case PCI_MACH64_GM_ID: case PCI_MACH64_GN_ID: case PCI_MACH64_GO_ID: case PCI_MACH64_GR_ID: case PCI_MACH64_GS_ID: case PCI_MACH64_LM_ID: case PCI_MACH64_LN_ID: case PCI_MACH64_LR_ID: case PCI_MACH64_LS_ID: info.ChipType = devid; break; default: info.ChipType = MACH64_UNKNOWN_ID; break; } info.ChipRev = pcrp->_rev_id; info.ApertureBase = pcrp->_base0 & 0xFFFFFFF0; if (info.ChipType == MACH64_GX_ID || info.ChipType == MACH64_CX_ID || info.ChipType == PCI_MACH64_CT_ID || info.ChipType == PCI_MACH64_ET_ID || ((info.ChipType == PCI_MACH64_VT_ID || info.ChipType == PCI_MACH64_GT_ID) && !(info.ChipRev & 0x07))) { info.RegisterBase = 0; } else { info.RegisterBase = pcrp->_base2 & 0xFFFFF000; } /* * The docs say check (pcrp->_user_config_0 & 0x04) for BlockIO * but this doesn't seem to be reliable. Instead check if * pcrp->_base1 is non-zero. */ if (pcrp->_base1 & 0xfffffffc) { info.BlockIO = TRUE; info.IOBase = pcrp->_base1 & (pcrp->_base1 & 0x1 ? 0xfffffffc : 0xfffffff0); /* If the Block I/O bit isn't set in userconfig, set it */ #ifdef DEBUG ErrorF("PCI userconfig0 = 0x%02x\n", pcrp->_user_config_0); #endif if ((pcrp->_user_config_0 & 0x04) != 0x04) { #ifdef DEBUG ErrorF("Setting bit 0x04 in PCI userconfig for card %d\n", pcrp->_cardnum); #endif xf86writepci(mach64InfoRec.scrnIndex, pcrp->_bus, pcrp->_cardnum, pcrp->_func, PCI_REG_USERCONFIG, 0x04, 0x04); } } else { info.BlockIO = FALSE; switch (pcrp->_user_config_0 & 0x03) { case 0: info.IOBase = 0x2EC; break; case 1: info.IOBase = 0x1CC; break; case 2: info.IOBase = 0x1C8; break; default: info.IOBase = 0; break; } } break; } i++; } /* Free PCI information */ xf86cleanpci(); if (found && xf86Verbose) { if (info.ChipType != MACH64_UNKNOWN_ID) { if (info.RegisterBase) { ErrorF("%s %s: PCI: %s rev %d, Aperture @ 0x%08x," " Registers @ 0x%08x, %s I/O @ 0x%04x\n", XCONFIG_PROBED, mach64InfoRec.name, xf86TokenToString(mach64ChipTable, info.ChipType), info.ChipRev, info.ApertureBase, info.RegisterBase, info.BlockIO ? "Block" : "Sparse", info.IOBase); } else { ErrorF("%s %s: PCI: %s rev %d, Aperture @ 0x%08x," " %s I/O @ 0x%04x\n", XCONFIG_PROBED, mach64InfoRec.name, xf86TokenToString(mach64ChipTable, info.ChipType), info.ChipRev, info.ApertureBase, info.BlockIO ? "Block" : "Sparse", info.IOBase); } } else { if (info.RegisterBase) { ErrorF("%s %s: PCI: unknown ATI (0x%04x) rev %d, " "Aperture @ 0x%08x, Registers @ 0x%08x, %s I/O @ 0x%04x\n", XCONFIG_PROBED, mach64InfoRec.name, devid, info.ChipRev, info.ApertureBase, info.RegisterBase, info.BlockIO ? "Block" : "Sparse", info.IOBase); } else { ErrorF("%s %s: PCI: unknown ATI (0x%04x) rev %d, " "Aperture @ 0x%08x, %s I/O @ 0x%04x\n", XCONFIG_PROBED, mach64InfoRec.name, devid, info.ChipRev, info.ApertureBase, info.BlockIO ? "Block" : "Sparse", info.IOBase); } } } if (found) { return &info; } else { return NULL; } } #ifdef DEBUG void mach64PrintCTPLL() { int i; unsigned char pll[16]; int R = 1432; int M, N, P; for (i = 0; i < 16; i++) { outb(ioCLOCK_CNTL + 1, i << 2); ErrorF("PLL register %2d: 0x%02x\n", i, pll[i] = inb(ioCLOCK_CNTL + 2)); } M = pll[PLL_REF_DIV]; N = pll[VCLK0_FB_DIV]; if (mach64HasDSP && (pll[PLL_XCLK_CNTL] & 0x10)) { switch (pll[VCLK_POST_DIV] & VCLK0_POST) { case 0: P = 3; break; case 1: P = 2; break; /* Unknown */ case 2: P = 6; break; case 3: P = 12; break; } } else { P = 1 << (pll[VCLK_POST_DIV] & VCLK0_POST); } ErrorF("VCLK0: M=%d, N=%d, P=%d, Clk=%.2f\n", M, N, P, (double)((2 * R * N)/(M * P)) / 100.0); N = pll[VCLK1_FB_DIV]; if (mach64HasDSP && (pll[PLL_XCLK_CNTL] & 0x20)) { switch ((pll[VCLK_POST_DIV] & VCLK1_POST) >> 2) { case 0: P = 3; break; case 1: P = 2; break; /* Unknown */ case 2: P = 6; break; case 3: P = 12; break; } } else { P = 1 << ((pll[VCLK_POST_DIV] & VCLK1_POST) >> 2); } ErrorF("VCLK1: M=%d, N=%d, P=%d, Clk=%.2f\n", M, N, P, (double)((2 * R * N)/(M * P)) / 100.0); N = pll[VCLK2_FB_DIV]; if (mach64HasDSP && (pll[PLL_XCLK_CNTL] & 0x40)) { switch ((pll[VCLK_POST_DIV] & VCLK2_POST) >> 4) { case 0: P = 3; break; case 1: P = 2; break; /* Unknown */ case 2: P = 6; break; case 3: P = 12; break; } } else { P = 1 << ((pll[VCLK_POST_DIV] & VCLK2_POST) >> 4); } ErrorF("VCLK2: M=%d, N=%d, P=%d, Clk=%.2f\n", M, N, P, (double)((2 * R * N)/(M * P)) / 100.0); N = pll[VCLK3_FB_DIV]; if (mach64HasDSP && (pll[PLL_XCLK_CNTL] & 0x80)) { switch ((pll[VCLK_POST_DIV] & VCLK3_POST) >> 6) { case 0: P = 3; break; case 1: P = 2; break; /* Unknown */ case 2: P = 6; break; case 3: P = 12; break; } } else { P = 1 << ((pll[VCLK_POST_DIV] & VCLK3_POST) >> 6); } ErrorF("VCLK3: M=%d, N=%d, P=%d, Clk=%.2f\n", M, N, P, (double)((2 * R * N)/(M * P)) / 100.0); N = pll[MCLK_FB_DIV]; P = 2; ErrorF("MCLK: M=%d, N=%d, P=%d, Clk=%.2f\n", M, N, P, (double)((2 * R * N)/(M * P)) / 100.0); } #endif static void InitIOAddresses(base, block) unsigned base; Bool block; { if (block) { ioCONFIG_CHIP_ID = base + CONFIG_CHIP_ID; ioCONFIG_CNTL = base + CONFIG_CNTL; ioSCRATCH_REG0 = base + SCRATCH_REG0; ioSCRATCH_REG1 = base + SCRATCH_REG1; ioCONFIG_STAT0 = base + CONFIG_STAT0; ioMEM_CNTL = base + MEM_CNTL; ioDAC_REGS = base + DAC_REGS; ioDAC_CNTL = base + DAC_CNTL; ioGEN_TEST_CNTL = base + GEN_TEST_CNTL; ioCLOCK_CNTL = base + CLOCK_CNTL; ioCRTC_GEN_CNTL = base + CRTC_GEN_CNTL; ATIExtReg = bioATIEXT; /* The following are only available through block I/O */ ioLCD_GEN_CTRL = base + LCD_GEN_CTRL; ioLCD_INDEX = base + LCD_INDEX; ioLCD_DATA = base + LCD_DATA; ioHORZ_STRETCHING = base + HORZ_STRETCHING; ioVERT_STRETCHING = base + VERT_STRETCHING; /* These are only needed for panel support (and are thus needed only * through block I/O) */ ioCRTC_H_TOTAL_DISP = base + CRTC_H_TOTAL_DISP; ioCRTC_H_SYNC_STRT_WID = base + CRTC_H_SYNC_STRT_WID; ioCRTC_V_TOTAL_DISP = base + CRTC_V_TOTAL_DISP; ioCRTC_V_SYNC_STRT_WID = base + CRTC_V_SYNC_STRT_WID; } else { ioCONFIG_CHIP_ID = base + (sioCONFIG_CHIP_ID << 10); ioCONFIG_CNTL = base + (sioCONFIG_CNTL << 10); ioSCRATCH_REG0 = base + (sioSCRATCH_REG0 << 10); ioSCRATCH_REG1 = base + (sioSCRATCH_REG1 << 10); ioCONFIG_STAT0 = base + (sioCONFIG_STAT0 << 10); ioMEM_CNTL = base + (sioMEM_CNTL << 10); ioDAC_REGS = base + (sioDAC_REGS << 10); ioDAC_CNTL = base + (sioDAC_CNTL << 10); ioGEN_TEST_CNTL = base + (sioGEN_TEST_CNTL << 10); ioCLOCK_CNTL = base + (sioCLOCK_CNTL << 10); ioCRTC_GEN_CNTL = base + (sioCRTC_GEN_CNTL << 10); ATIExtReg = sioATIEXT; } } /* * mach64Probe -- * Probe the hardware */ Bool mach64Probe() { int i, j; DisplayModePtr pMode, pEnd; ATIInformationBlock *info; ATIPCIInformation *pciInfo; int available_ram; Bool sw_cursor_supplied; OFlagSet validOptions; int tx, ty; Bool clock_type_probed = TRUE; int new = -1; /* Do the general PCI probe first */ pciInfo = GetATIPCIInformation(); if (pciInfo) { InitIOAddresses(pciInfo->IOBase, pciInfo->BlockIO); } else { InitIOAddresses(0x2EC, FALSE); } xf86ClearIOPortList(mach64InfoRec.scrnIndex); xf86AddIOPorts(mach64InfoRec.scrnIndex, Num_Mach64_IOPorts, Mach64_IOPorts); xf86EnableIOPorts(mach64InfoRec.scrnIndex); if (pciInfo) info = GetATIInformationBlock(pciInfo->BlockIO); else info = GetATIInformationBlock(FALSE); /* If probe fails when assuming block I/O, try again with sparse I/O */ if (pciInfo && pciInfo->BlockIO && info && !info->Mach64_Present) { InitIOAddresses(0x2EC, FALSE); info = GetATIInformationBlock(pciInfo->BlockIO); if (info && info->Mach64_Present) { ErrorF("%s %s: PCI reports Block I/O, but really Sparse I/O" " @ 0x2ec\n", XCONFIG_PROBED, mach64InfoRec.name); } } if (!info || !info->Mach64_Present) { xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } if (pciInfo && !mach64InfoRec.chipID) { if (pciInfo->ChipType != info->ChipType) { ErrorF("%s %s: PCI (%s) and CONFIG_CHIP_ID (%s) don't agree on" " ChipType,\n" "\tusing PCI value\n", XCONFIG_PROBED, mach64InfoRec.name, xf86TokenToString(mach64ChipTable, pciInfo->ChipType), xf86TokenToString(mach64ChipTable, info->ChipType)); } mach64ChipType = pciInfo->ChipType; } else { mach64ChipType = info->ChipType; } if (pciInfo && !mach64InfoRec.chipRev) { if (pciInfo->ChipRev != info->ChipRev) { ErrorF("%s %s: PCI (%d) and CONFIG_CHIP_ID (%d) don't agree on" " ChipRev,\n" "\tusing PCI value\n", XCONFIG_PROBED, mach64InfoRec.name, pciInfo->ChipRev, info->ChipRev); } mach64ChipRev = pciInfo->ChipRev; } else { mach64ChipRev = info->ChipRev; } if (!pciInfo) { ErrorF("%s %s: %s rev %d, Aperture @ 0x%08x," " %s I/O @ 0x%04x\n", XCONFIG_PROBED, mach64InfoRec.name, xf86TokenToString(mach64ChipTable, mach64ChipType), mach64ChipRev, (inw(ioCONFIG_CNTL) & 0x3FF0) << 18, "Sparse", 0x2EC); } if (mach64ChipType == MACH64_GX_ID || mach64ChipType == MACH64_CX_ID) { mach64IntegratedController = FALSE; } else { /* Even for MACH64_UNKNOWN_ID more than likely */ mach64IntegratedController = TRUE; } if (mach64ChipType == MACH64_GX_ID || mach64ChipType == MACH64_CX_ID || mach64ChipType == MACH64_CT_ID || mach64ChipType == MACH64_ET_ID || ((mach64ChipType == MACH64_VT_ID || mach64ChipType == MACH64_GT_ID) && !(mach64ChipRev & 0x07))) { mach64HasDSP = FALSE; } else { mach64HasDSP = TRUE; } if (mach64ChipType == MACH64_GX_ID || mach64ChipType == MACH64_CX_ID || mach64ChipType == MACH64_GB_ID || mach64ChipType == MACH64_GD_ID || mach64ChipType == MACH64_GI_ID || mach64ChipType == MACH64_GP_ID || mach64ChipType == MACH64_GQ_ID || mach64ChipType == MACH64_LD_ID || mach64ChipType == MACH64_LG_ID || mach64ChipType == MACH64_LB_ID || mach64ChipType == MACH64_LI_ID || mach64ChipType == MACH64_LP_ID || mach64ChipType == MACH64_GL_ID || mach64ChipType == MACH64_GM_ID || mach64ChipType == MACH64_GN_ID || mach64ChipType == MACH64_GO_ID || mach64ChipType == MACH64_GR_ID || mach64ChipType == MACH64_GS_ID || mach64ChipType == MACH64_LM_ID || mach64ChipType == MACH64_LN_ID || mach64ChipType == MACH64_LR_ID || mach64ChipType == MACH64_LS_ID) { mach64HasBlockWrite = TRUE; } else { mach64HasBlockWrite = FALSE; } if (mach64ChipType == MACH64_GB_ID || mach64ChipType == MACH64_GD_ID || mach64ChipType == MACH64_GW_ID || mach64ChipType == MACH64_GZ_ID || mach64ChipType == MACH64_LB_ID || mach64ChipType == MACH64_LD_ID || mach64ChipType == MACH64_GM_ID || mach64ChipType == MACH64_GN_ID || mach64ChipType == MACH64_LM_ID || mach64ChipType == MACH64_LN_ID) { mach64AGP = TRUE; } else { mach64AGP = FALSE; } #ifdef DEBUG if (mach64IntegratedController) mach64PrintCTPLL(); #endif if (xf86bpp < 0) { xf86bpp = mach64InfoRec.depth; } if (xf86weight.red == 0 || xf86weight.green == 0 || xf86weight.blue == 0) { xf86weight = mach64InfoRec.weight; } /* Check for known contradictions */ if (info->Clock_Type == CLK_CH8398 && info->DAC_SubType != DAC_CH8398) new = DAC_CH8398; if (info->Clock_Type == CLK_STG1703 && info->DAC_SubType != DAC_STG1703) new = DAC_STG1703; if (info->Clock_Type == CLK_ATT20C408 && info->DAC_SubType != DAC_ATT20C408) new = DAC_ATT20C408; if (new >= 0) { ErrorF("%s %s: Autodetected RAMDAC %s contradicts the Clock type\n", XCONFIG_PROBED, mach64InfoRec.name, xf86TokenToString(mach64RamdacTable, info->DAC_SubType)); ErrorF("\tSetting probed RAMDAC to %s\n", xf86TokenToString(mach64RamdacTable, new)); info->DAC_SubType = new; } switch (info->DAC_SubType) { case DAC_ATI68860_B: case DAC_ATI68860_C: case DAC_ATI68875: case DAC_CH8398: case DAC_STG1702: case DAC_STG1703: case DAC_ATT20C408: case DAC_INTERNAL: case DAC_IBMRGB514: break; default: if (xf86bpp != 8) { ErrorF("mach64Probe: Invalid bpp: %d\n", xf86bpp); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } break; } switch (xf86bpp) { case 8: break; case 16: if (xf86weight.red == 5 && xf86weight.green == 5 && xf86weight.blue == 5) { mach64WeightMask = RGB16_555; mach64InfoRec.depth = 15; } else if (xf86weight.red == 5 && xf86weight.green == 6 && xf86weight.blue == 5) { mach64WeightMask = RGB16_565; mach64InfoRec.depth = 16; } else { ErrorF("Invalid color weighting %1d%1d%1d (only 555 and 565 are valid)\n", xf86weight.red, xf86weight.green, xf86weight.blue); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } mach64InfoRec.bitsPerPixel = 16; if (mach64InfoRec.defaultVisual < 0) mach64InfoRec.defaultVisual = TrueColor; if (defaultColorVisualClass < 0) defaultColorVisualClass = mach64InfoRec.defaultVisual; if (defaultColorVisualClass != TrueColor) { ErrorF("Invalid default visual type: %d (%s)\n", defaultColorVisualClass, xf86VisualNames[defaultColorVisualClass]); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } break; case 24: case 32: mach64InfoRec.depth = 24; mach64InfoRec.bitsPerPixel = 32; xf86weight.red = xf86weight.green = xf86weight.blue = 8; if (mach64InfoRec.defaultVisual < 0) mach64InfoRec.defaultVisual = TrueColor; if (defaultColorVisualClass < 0) defaultColorVisualClass = mach64InfoRec.defaultVisual; if (defaultColorVisualClass != TrueColor) { ErrorF("Invalid default visual type: %d (%s)\n", defaultColorVisualClass, xf86VisualNames[defaultColorVisualClass]); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } break; default: ErrorF("mach64Probe: Invalid bpp: %d\n", xf86bpp); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } switch(info->DAC_SubType) { case DAC_ATI68860_B: case DAC_ATI68860_C: mach64InfoRec.maxClock = 135000; break; case DAC_ATI68875: mach64InfoRec.maxClock = 135000; break; case DAC_CH8398: mach64InfoRec.maxClock = 135000; break; case DAC_STG1702: case DAC_STG1703: mach64InfoRec.maxClock = 135000; break; case DAC_ATT20C408: mach64InfoRec.maxClock = 135000; break; case DAC_INTERNAL: if ((mach64ChipType == MACH64_VT_ID || mach64ChipType == MACH64_GT_ID) && (mach64ChipRev & 0x07)) { mach64InfoRec.maxClock = 170000; } else if (mach64ChipType == MACH64_VU_ID || mach64ChipType == MACH64_GU_ID) { mach64InfoRec.maxClock = 200000; } else if (mach64ChipType == MACH64_GB_ID || mach64ChipType == MACH64_GD_ID || mach64ChipType == MACH64_GI_ID || mach64ChipType == MACH64_GP_ID || mach64ChipType == MACH64_GQ_ID || mach64ChipType == MACH64_VV_ID || mach64ChipType == MACH64_GV_ID || mach64ChipType == MACH64_GW_ID || mach64ChipType == MACH64_GZ_ID || mach64ChipType == MACH64_LD_ID || mach64ChipType == MACH64_LG_ID || mach64ChipType == MACH64_LB_ID || mach64ChipType == MACH64_LI_ID || mach64ChipType == MACH64_LP_ID || mach64ChipType == MACH64_GL_ID || mach64ChipType == MACH64_GM_ID || mach64ChipType == MACH64_GN_ID || mach64ChipType == MACH64_GO_ID || mach64ChipType == MACH64_GR_ID || mach64ChipType == MACH64_GS_ID || mach64ChipType == MACH64_LM_ID || mach64ChipType == MACH64_LN_ID || mach64ChipType == MACH64_LR_ID || mach64ChipType == MACH64_LS_ID) { mach64InfoRec.maxClock = 230000; } else { if (xf86bpp == 8) mach64InfoRec.maxClock = 135000; else mach64InfoRec.maxClock = 80000; } break; case DAC_IBMRGB514: mach64InfoRec.maxClock = 220000; break; default: mach64InfoRec.maxClock = mach64MaxClock; break; } if (mach64InfoRec.dacSpeeds[0] > 0) mach64InfoRec.maxClock = mach64InfoRec.dacSpeeds[0]; OFLG_ZERO(&validOptions); OFLG_SET(OPTION_CLKDIV2, &validOptions); OFLG_SET(OPTION_HW_CURSOR, &validOptions); OFLG_SET(OPTION_SW_CURSOR, &validOptions); OFLG_SET(OPTION_CSYNC, &validOptions); if (info->DAC_SubType != DAC_CH8398) { OFLG_SET(OPTION_DAC_8_BIT, &validOptions); } OFLG_SET(OPTION_DAC_6_BIT, &validOptions); OFLG_SET(OPTION_OVERRIDE_BIOS, &validOptions); if (mach64HasDSP) { OFLG_SET(OPTION_FIFO_CONSERV, &validOptions); OFLG_SET(OPTION_FIFO_AGGRESSIVE, &validOptions); } if (mach64HasBlockWrite) { OFLG_SET(OPTION_NO_BLOCK_WRITE, &validOptions); OFLG_SET(OPTION_BLOCK_WRITE, &validOptions); } OFLG_SET(OPTION_POWER_SAVER, &validOptions); OFLG_SET(OPTION_NO_BIOS_CLOCKS, &validOptions); OFLG_SET(OPTION_NO_PROGRAM_CLOCKS, &validOptions); OFLG_SET(OPTION_NO_FONT_CACHE, &validOptions); OFLG_SET(OPTION_NO_PIXMAP_CACHE, &validOptions); xf86VerifyOptions(&validOptions, &mach64InfoRec); mach64InfoRec.chipset = "mach64"; xf86ProbeFailed = FALSE; if (mach64IntegratedController) { if (pciInfo) mach64BusType = PCI; else mach64BusType = LOCAL_BUS; /* How can this be confirmed? */ } else { mach64BusType = info->Bus_Type; } if (xf86Verbose) { ErrorF("%s %s: Card type: ", XCONFIG_PROBED, mach64InfoRec.name); switch(mach64BusType) { case ISA: ErrorF("ISA\n"); break; case EISA: ErrorF("EISA\n"); break; case LOCAL_BUS: ErrorF("VESA LocalBus\n"); break; case PCI: if (mach64AGP) ErrorF("AGP\n"); else ErrorF("PCI\n"); break; default: ErrorF("Unknown\n"); } } if (mach64InfoRec.ramdac) { mach64RamdacSubType = xf86StringToToken(mach64RamdacTableNames, mach64InfoRec.ramdac); mach64Ramdac = mach64RamdacSubType & 0x0f; if (mach64RamdacSubType < 0) { ErrorF("%s %s: Unknown RAMDAC type \"%s\"\n", XCONFIG_GIVEN, mach64InfoRec.name, mach64InfoRec.ramdac); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } } else { mach64Ramdac = info->DAC_Type; mach64RamdacSubType = info->DAC_SubType; } mach64MemType = info->Mem_Type; if (xf86Verbose) { ErrorF("%s %s: Memory type: ", XCONFIG_PROBED, mach64InfoRec.name); if (mach64IntegratedController) { switch (mach64MemType) { case DRAM: ErrorF("DRAM"); break; case EDO_DRAM: case PSEUDO_EDO: ErrorF("EDO"); break; case SDRAM: ErrorF("SDRAM"); break; case SGRAM: ErrorF("SGRAM (1:1)"); break; case SGRAM32: ErrorF("SGRAM (2:1)"); break; } } else { switch (mach64MemType) { case DRAMx4: case DRAMx16: case GraphicsDRAMx16: ErrorF("DRAM"); break; case VRAMx16: case VRAMx16ssr: case EnhancedVRAMx16: case EnhancedVRAMx16ssr: ErrorF("VRAM"); break; } } ErrorF(" (%d)\n", mach64MemType); } mach64MinFreq = info->MinFreq; mach64MaxFreq = info->MaxFreq; mach64RefFreq = info->RefFreq; mach64RefDivider = info->RefDivider; mach64NAdj = info->NAdj; mach64DRAMMemClk = info->DRAMMemClk; mach64VRAMMemClk = info->VRAMMemClk; mach64MemCycle = info->MemCycle; mach64MemClk = info->MemClk; if (mach64RamdacSubType == DAC_IBMRGB514) mach64CXClk = 7; /* Use IBM RGB514 PLL */ else mach64CXClk = info->CXClk; #ifdef DEBUG ErrorF("MinFreq = %d, MaxFreq = %d, RefFreq = %d, RefDivider = %d\n", info->MinFreq, info->MaxFreq, info->RefFreq, info->RefDivider); ErrorF("CXClk = %d\n", info->CXClk); #endif mach64ClockType = info->Clock_Type; for (i = 0; i < MACH64_NUM_CLOCKS; i++) mach64Clocks[i] = info->Clocks[i]; for (i = 0; i < MACH64_NUM_FREQS; i++) mach64FreqTable[i] = info->Freq_Table[i]; for (i = 0; i < MACH64_NUM_FREQS; i++) mach64FreqTable2[i] = info->Freq_Table2[i]; if ((mach64LCDPanelID = info->PanelID) >= 0) { CARD32 h_total_disp, h_sync_strt_wid, v_total_disp, v_sync_strt_wid; int HDisplay, VDisplay; mach64LCDHorizontal = info->LCDHorizontal; mach64LCDVertical = info->LCDVertical; mach64LCDClock = mach64GetCTClock(0); ErrorF("%s %s: %dx%d panel (ID %d) detected; clock %.2f MHz\n", XCONFIG_PROBED, mach64InfoRec.name, mach64LCDHorizontal, mach64LCDVertical, mach64LCDPanelID, (double)mach64LCDClock / 100.0); /* * Determine porch data. The intent here is to produce stretched modes * that approximate the horizontal sync and vertical refresh rates of * the mode on entry. */ h_total_disp = inl(ioCRTC_H_TOTAL_DISP); h_sync_strt_wid = inl(ioCRTC_H_SYNC_STRT_WID); v_total_disp = inl(ioCRTC_V_TOTAL_DISP); v_sync_strt_wid = inl(ioCRTC_V_SYNC_STRT_WID); HDisplay = h_total_disp >> 16; VDisplay = v_total_disp >> 16; LCDHSyncStart = ((h_sync_strt_wid & 0x1000) >> 4) + (h_sync_strt_wid & 0xFF) - HDisplay; LCDHSyncWidth = (h_sync_strt_wid & 0x1F0000) >> 16; LCDHBlankWidth = (h_total_disp & 0x1FF) - HDisplay; LCDVSyncStart = (v_sync_strt_wid & 0x7FF) - VDisplay; LCDVSyncWidth = (v_sync_strt_wid & 0x1F0000) >> 16; LCDVBlankWidth = (v_total_disp & 0x7FF) - VDisplay; if (!(inl(ioCRTC_GEN_CNTL) & CRTC_EXT_DISP_EN)) { /* Adjust for VGA */ LCDHSyncWidth = (LCDHSyncWidth - LCDHSyncStart - HDisplay) & 0x1F; LCDHBlankWidth += 4; LCDVSyncWidth = (LCDVSyncWidth - LCDVSyncStart - VDisplay) & 0x0F; LCDVSyncStart--; LCDVBlankWidth++; } HDisplay <<= 3; LCDHSyncStart <<= 3; LCDHSyncWidth <<= 3; LCDHBlankWidth <<= 3; /* If the mode on entry isn't stretched, adjust timings */ do { CARD32 horz_stretching; if ((HDisplay = mach64LCDHorizontal - HDisplay) <= 0) break; if (mach64ChipType == MACH64_LG_ID) { horz_stretching = inl(ioHORZ_STRETCHING); } else { outb(ioLCD_INDEX, LCD_HORZ_STRETCHING); horz_stretching = inl(ioLCD_DATA); } if (horz_stretching & HORZ_STRETCH_EN) break; if ((LCDHSyncStart -= HDisplay) < 0) LCDHSyncStart = 0; LCDHBlankWidth -= HDisplay; HDisplay = LCDHSyncStart + LCDHSyncWidth; if (LCDHBlankWidth < HDisplay) LCDHBlankWidth = HDisplay; } while(0); do { CARD32 vert_stretching; if ((VDisplay = mach64LCDVertical - VDisplay) <= 0) break; if (mach64ChipType == MACH64_LG_ID) { vert_stretching = inl(ioVERT_STRETCHING); } else { outb(ioLCD_INDEX, LCD_VERT_STRETCHING); vert_stretching = inl(ioLCD_DATA); } if (vert_stretching & VERT_STRETCH_EN) break; if ((LCDVSyncStart -= VDisplay) < 0) LCDVSyncStart = 0; LCDVBlankWidth -= VDisplay; VDisplay = LCDVSyncStart + LCDVSyncWidth; if (LCDVBlankWidth < VDisplay) LCDVBlankWidth = VDisplay; } while(0); } if (OFLG_ISSET(OPTION_NO_PROGRAM_CLOCKS, &mach64InfoRec.options)) { if (OFLG_ISSET(CLOCK_OPTION_PROGRAMABLE, &mach64InfoRec.clockOptions)) { ErrorF("Warning: Clock programming overriden\n"); } /* No need to use auto probing code since the BIOS contains * all of the clocks unless the "no_bios_clocks" option is * set. */ if (!mach64InfoRec.clocks || !OFLG_ISSET(OPTION_NO_BIOS_CLOCKS, &mach64InfoRec.options)) { if (mach64InfoRec.clocks) { ErrorF("Warning: Clocks being read from the video card's BIOS,\n"); ErrorF(" and the clocks lines in XF86Config file are ignored\n"); ErrorF(" (see man page or README.Mach64 for more details).\n"); } else if (OFLG_ISSET(OPTION_NO_BIOS_CLOCKS, &mach64InfoRec.options)) { ErrorF("Warning: \"no_bios_clocks\" option set, but no Clocks\n"); ErrorF(" given in XF86Config file. Clocks being read from\n"); ErrorF(" the video card's BIOS (see man page or README.Mach64\n"); ErrorF(" for more details).\n"); } for (i = 0; i < MACH64_NUM_CLOCKS; i++) { mach64InfoRec.clock[i] = mach64Clocks[i] * 10; mach64InfoRec.clock[i + MACH64_NUM_CLOCKS] = mach64Clocks[i] * 5; } mach64InfoRec.clocks = MACH64_NUM_CLOCKS*2; } else { ErrorF("Warning: BIOS Clocks overidden.\n"); } } else if (OFLG_ISSET(CLOCK_OPTION_PROGRAMABLE, &mach64InfoRec.clockOptions)) { if (OFLG_ISSET(CLOCK_OPTION_ICS2595, &mach64InfoRec.clockOptions)) mach64ClockType = CLK_ATI18818_1; else if (OFLG_ISSET(CLOCK_OPTION_STG1703, &mach64InfoRec.clockOptions)) mach64ClockType = CLK_STG1703; else if (OFLG_ISSET(CLOCK_OPTION_CH8398, &mach64InfoRec.clockOptions)) mach64ClockType = CLK_CH8398; else if (OFLG_ISSET(CLOCK_OPTION_ATT409, &mach64InfoRec.clockOptions)) mach64ClockType = CLK_ATT20C408; else if (OFLG_ISSET(CLOCK_OPTION_IBMRGB, &mach64InfoRec.clockOptions)) mach64ClockType = CLK_IBMRGB514; else { ErrorF("Unrecognized clock chip type\n"); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } clock_type_probed = FALSE; } else { OFLG_SET(CLOCK_OPTION_PROGRAMABLE, &mach64InfoRec.clockOptions); } if (xf86Verbose) { ErrorF("%s %s: Clock type: %s\n", (clock_type_probed ? XCONFIG_PROBED : XCONFIG_GIVEN), mach64InfoRec.name, (mach64ClockType < NUM_CLOCK_TYPES ? (mach64RamdacSubType == DAC_IBMRGB514 ? mach64ClockTypeTable[CLK_IBMRGB514] : mach64ClockTypeTable[mach64ClockType]) : "Unknown")); if (!OFLG_ISSET(CLOCK_OPTION_PROGRAMABLE, &mach64InfoRec.clockOptions) || OFLG_ISSET(OPTION_NO_PROGRAM_CLOCKS, &mach64InfoRec.options)) { ErrorF("%s ",(OFLG_ISSET(XCONFIG_CLOCKS,&mach64InfoRec.xconfigFlag) && OFLG_ISSET(OPTION_NO_BIOS_CLOCKS, &mach64InfoRec.options)) ? XCONFIG_GIVEN : XCONFIG_PROBED); ErrorF("%s: ", mach64InfoRec.name); ErrorF("Number of Clocks: %d", mach64InfoRec.clocks); for (i = 0; i < mach64InfoRec.clocks; i++) { if (i % 8 == 0) ErrorF("\n%s %s: Clocks:", (OFLG_ISSET(XCONFIG_CLOCKS,&mach64InfoRec.xconfigFlag) && OFLG_ISSET(OPTION_NO_BIOS_CLOCKS, &mach64InfoRec.options)) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach64InfoRec.name); ErrorF(" %6.2f", mach64InfoRec.clock[i]/1000.0); } ErrorF("\n"); } } if (!mach64InfoRec.videoRam) { mach64InfoRec.videoRam = info->Mem_Size; } tx = mach64InfoRec.virtualX; ty = mach64InfoRec.virtualY; pMode = mach64InfoRec.modes; if (pMode == NULL) { ErrorF("No modes supplied in XF86Config\n"); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } pEnd = (DisplayModePtr)NULL; do { DisplayModePtr pModeSv; /* * xf86LookupMode returns FALSE if it ran into an invalid * parameter */ if(xf86LookupMode(pMode, &mach64InfoRec, LOOKUP_DEFAULT) == FALSE) { pModeSv=pMode->next; xf86DeleteMode(&mach64InfoRec, pMode); pMode = pModeSv; } else if (pMode->HDisplay * pMode->VDisplay * (mach64InfoRec.bitsPerPixel / 8) > mach64InfoRec.videoRam*1024) { pModeSv=pMode->next; ErrorF("%s %s: Too little memory for mode \"%s\"\n", XCONFIG_PROBED, mach64InfoRec.name, pMode->name); xf86DeleteMode(&mach64InfoRec, pMode); pMode = pModeSv; } else if (((tx > 0) && (pMode->HDisplay > tx)) || ((ty > 0) && (pMode->VDisplay > ty))) { pModeSv=pMode->next; ErrorF("%s %s: Resolution %dx%d too large for virtual %dx%d\n", XCONFIG_PROBED, mach64InfoRec.name, pMode->HDisplay, pMode->VDisplay, tx, ty); xf86DeleteMode(&mach64InfoRec, pMode); pMode = pModeSv; } else if ((pMode->Flags & V_DBLSCAN) && (mach64ChipType == MACH64_GX_ID || mach64ChipType == MACH64_CX_ID || mach64ChipType == MACH64_CT_ID || mach64ChipType == MACH64_ET_ID)) { pModeSv=pMode->next; ErrorF("%s %s: Doublescan mode not supported on the %s\n", XCONFIG_PROBED, mach64InfoRec.name, xf86TokenToString(mach64ChipTable, mach64ChipType)); xf86DeleteMode(&mach64InfoRec, pMode); pMode = pModeSv; } else { int found = FALSE; int mach64CDepths[] = { -1, 4, 8, 15, 16, 24, 32, -1 }; for (i = 0; mach64FreqTable2[i].h_disp != 0; i++) if ((mach64FreqTable2[i].h_disp << 3 >= pMode->HDisplay) && (mach64FreqTable2[i].dacmask == mach64RamdacSubType) && (mach64FreqTable2[i].max_dot_clock >= mach64InfoRec.clock[pMode->Clock] / 1000) && (mach64CDepths[mach64FreqTable2[i].color_depth & 0x07] >= mach64InfoRec.bitsPerPixel)) { found = TRUE; break; } if (!found) for (i = 0; mach64FreqTable[i].h_disp != 0; i++) if ((mach64FreqTable[i].h_disp << 3 >= pMode->HDisplay) && (mach64FreqTable[i].dacmask & (1 << mach64Ramdac)) && (mach64FreqTable[i].max_dot_clock >= mach64InfoRec.clock[pMode->Clock] / 1000) && (mach64CDepths[mach64FreqTable[i].color_depth & 0x07] >= mach64InfoRec.bitsPerPixel)) { found = TRUE; break; } if (!found && OFLG_ISSET(OPTION_OVERRIDE_BIOS, &mach64InfoRec.options)) { /* BIOS doesn't think this mode is legal! */ ErrorF("%s %s: Illegal mode according to Mach64 BIOS (Overridden)\n", XCONFIG_GIVEN, mach64InfoRec.name); found = TRUE; } if (!found) { pModeSv=pMode->next; ErrorF("%s %s: Illegal mode according to Mach64 BIOS\n", XCONFIG_PROBED, mach64InfoRec.name); xf86DeleteMode(&mach64InfoRec, pMode); pMode = pModeSv; } else { /* * Successfully looked up this mode. If pEnd isn't * initialized, set it to this mode. */ if(pEnd == (DisplayModePtr) NULL) pEnd = pMode; mach64InfoRec.virtualX = max(mach64InfoRec.virtualX, pMode->HDisplay); mach64InfoRec.virtualY = max(mach64InfoRec.virtualY, pMode->VDisplay); /* * For programmable clocks, fill in the SynthClock value * for each mode. */ if (OFLG_ISSET(CLOCK_OPTION_PROGRAMABLE, &mach64InfoRec.clockOptions)) pMode->SynthClock = mach64InfoRec.clock[pMode->Clock]; /* For panels, clobber mode timings */ if (mach64LCDPanelID >= 0) { pMode->Flags &= ~(V_DBLSCAN | V_INTERLACE | V_CLKDIV2); pMode->CrtcHDisplay = pMode->HDisplay; pMode->CrtcHSyncStart = pMode->HDisplay + LCDHSyncStart; pMode->CrtcHSyncEnd = pMode->CrtcHSyncStart + LCDHSyncWidth; pMode->CrtcHTotal = pMode->HDisplay + LCDHBlankWidth; pMode->CrtcHAdjusted = TRUE; pMode->CrtcVDisplay = pMode->VDisplay; pMode->CrtcVSyncStart = pMode->VDisplay + LCDVSyncStart; pMode->CrtcVSyncEnd = pMode->CrtcVSyncStart + LCDVSyncWidth; pMode->CrtcVTotal = pMode->VDisplay + LCDVBlankWidth; pMode->CrtcVAdjusted = TRUE; } pMode = pMode->next; } } } while (pMode != pEnd); mach64VirtX = mach64InfoRec.virtualX = (mach64InfoRec.virtualX+7) & 0xfff8; mach64VirtY = mach64InfoRec.virtualY; if ((tx != mach64InfoRec.virtualX) || (ty != mach64InfoRec.virtualY)) OFLG_CLR(XCONFIG_VIRTUAL,&mach64InfoRec.xconfigFlag); if (xf86Verbose) { ErrorF("%s %s: Virtual resolution: %dx%d\n", OFLG_ISSET(XCONFIG_VIRTUAL, &mach64InfoRec.xconfigFlag) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach64InfoRec.name, mach64VirtX, mach64VirtY); } /* Set mach64MemorySize to required MEM_SIZE value in MISC_OPTIONS */ if (mach64InfoRec.videoRam <= 512) mach64MemorySize = MEM_SIZE_512K; else if (mach64InfoRec.videoRam <= 1024) mach64MemorySize = MEM_SIZE_1M; else if (mach64InfoRec.videoRam <= 2048) mach64MemorySize = MEM_SIZE_2M; else if (mach64InfoRec.videoRam <= 4096) mach64MemorySize = MEM_SIZE_4M; else if (mach64InfoRec.videoRam <= 6144) mach64MemorySize = MEM_SIZE_6M; else if (mach64InfoRec.videoRam <= 8192) mach64MemorySize = MEM_SIZE_8M; else mach64MemorySize = MEM_SIZE_16M; if (xf86Verbose) { ErrorF("%s %s: Video RAM: %dk\n", OFLG_ISSET(XCONFIG_VIDEORAM, &mach64InfoRec.xconfigFlag) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach64InfoRec.name, mach64InfoRec.videoRam ); } if (((mach64VirtX) * (mach64VirtY) * (mach64InfoRec.bitsPerPixel / 8)) > (mach64InfoRec.videoRam*1024)) { ErrorF("Not enough memory for requested virtual resolution (%dx%d)\n", mach64VirtX, mach64VirtY); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } /* Set values of mach64MaxX and mach64MaxY. * This must be done here so that cache area and * scissor limits are set up correctly (this setup * happens before the pixmap cache is initialized). */ mach64MaxX = mach64VirtX - 1; mach64MaxY = (mach64InfoRec.videoRam * 1024) / (mach64VirtX * (mach64InfoRec.bitsPerPixel / 8)) - 1; /* No need to reserve space for the registers in the frame buffer */ /* if we are using the auxilliary register aperture */ if (!pciInfo || !(pciInfo->RegisterBase)) { /* Reserve space for the registers at the end of video memory */ mach64InfoRec.videoRam--; } available_ram = mach64InfoRec.videoRam * 1024; sw_cursor_supplied = OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options); if (sw_cursor_supplied && OFLG_ISSET(OPTION_HW_CURSOR, &mach64InfoRec.options)) { ErrorF("Cannot use hardware and software cursors simultaneously.\n"); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } if (!sw_cursor_supplied && mach64RamdacSubType != DAC_IBMRGB514) { if (available_ram - (mach64VirtX * mach64VirtY) >= MACH64_CURSBYTES) { available_ram -= (MACH64_CURSBYTES + 1023) & ~1023; mach64InfoRec.videoRam -= (MACH64_CURSBYTES + 1023) / 1024; } else if (OFLG_ISSET(OPTION_HW_CURSOR, &mach64InfoRec.options)) { ErrorF("Not enough memory to use the hardware cursor.\n"); ErrorF(" Decreasing the virtual Y resolution by 1 will allow\n"); ErrorF(" you to use the hardware cursor.\n"); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } else { OFLG_SET(OPTION_SW_CURSOR, &mach64InfoRec.options); ErrorF("Warning: Not enough memory to use the hardware cursor.\n"); ErrorF(" Decreasing the virtual Y resolution by 1 will allow\n"); ErrorF(" you to use the hardware cursor.\n"); } } ErrorF("%s %s: Using %s cursor\n", (sw_cursor_supplied || OFLG_ISSET(OPTION_HW_CURSOR, &mach64InfoRec.options)) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach64InfoRec.name, OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options) ? "software" : "hardware"); /* Assume we are not on an ISA bus since supporting one would require * a tremendous rewrite of this code. The best solution is to make * another accel server (XF86_Mach64ISA) for ISA cards if there are * any masochists out there. */ mach64Use4MbAperture = xf86LinearVidMem(); if (!mach64Use4MbAperture) { ErrorF("The mach64 X server requires at least a 4Mb memory aperture.\n"); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } if (mach64Use4MbAperture) { if (mach64InfoRec.MemBase != 0) mach64ApertureAddr = mach64InfoRec.MemBase & 0xffc00000; else { if (pciInfo && pciInfo->ApertureBase) mach64ApertureAddr = pciInfo->ApertureBase; else mach64ApertureAddr = (inw(ioCONFIG_CNTL) & 0x3FF0) << 18; } /* Last-resort defaults */ if (mach64ApertureAddr == 0) { if (mach64BusType == PCI) mach64ApertureAddr = 0x7c000000; else mach64ApertureAddr = 0x04000000; /* for VLB */ } if ((mach64BusType == ISA) && (mach64ChipType != MACH64_VT_ID)) { mach64ApertureSize = MEM_SIZE_4M; if (xf86Verbose) { ErrorF("%s %s: Using 4 MB aperture @ 0x%08x\n", XCONFIG_PROBED, mach64InfoRec.name, mach64ApertureAddr); } } else if ((mach64BusType == PCI) && (mach64IntegratedController)) { mach64ApertureSize = MEM_SIZE_16M; if (xf86Verbose) { ErrorF("%s %s: Using 16 MB aperture @ 0x%08x\n", XCONFIG_PROBED, mach64InfoRec.name, mach64ApertureAddr); } } else { mach64ApertureSize = MEM_SIZE_8M; if (xf86Verbose) { ErrorF("%s %s: Using 8 MB aperture @ 0x%08x\n", XCONFIG_PROBED, mach64InfoRec.name, mach64ApertureAddr); } } if (pciInfo && pciInfo->RegisterBase) { mach64RegisterAddr = pciInfo->RegisterBase; if (xf86Verbose) { ErrorF("%s %s: Using 4 KB register aperture @ 0x%08x\n", XCONFIG_PROBED, mach64InfoRec.name, mach64RegisterAddr); } } } else { ErrorF("To use the Mach64 X server you need to be able to use\n"); ErrorF("a 4, 8 or 16 Mb memory aperture.\n"); xf86DisableIOPorts(mach64InfoRec.scrnIndex); return(FALSE); } if (xf86Verbose) { for (i = 0; ((mach64RamdacTable[i].token != -1) && (mach64RamdacTable[i].token != mach64RamdacSubType)); i++); if (mach64RamdacTable[i].token == -1) { ErrorF("%s %s: Ramdac is Unknown (%d)\n", (mach64InfoRec.ramdac ? XCONFIG_GIVEN : XCONFIG_PROBED), mach64InfoRec.name, mach64RamdacSubType); } else { ErrorF("%s %s: Ramdac is %s\n", (mach64InfoRec.ramdac ? XCONFIG_GIVEN : XCONFIG_PROBED), mach64InfoRec.name, mach64RamdacTable[i].name); } ErrorF("%s %s: Ramdac speed: %d MHz\n", OFLG_ISSET(XCONFIG_DACSPEED, &mach64InfoRec.xconfigFlag) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach64InfoRec.name, mach64InfoRec.maxClock / 1000); } mach64DAC8Bit = ((!OFLG_ISSET(OPTION_DAC_6_BIT, &mach64InfoRec.options) && (mach64InfoRec.bitsPerPixel == 8) && (mach64RamdacSubType != DAC_CH8398)) || (mach64InfoRec.bitsPerPixel == 16) || (mach64InfoRec.bitsPerPixel == 32)); if (xf86Verbose) { if (mach64InfoRec.bitsPerPixel == 8) { ErrorF("%s %s: Using %d bits per RGB value\n", (OFLG_ISSET(OPTION_DAC_6_BIT, &mach64InfoRec.options) || OFLG_ISSET(OPTION_DAC_8_BIT, &mach64InfoRec.options)) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach64InfoRec.name, mach64DAC8Bit ? 8 : 6); } else if (mach64InfoRec.bitsPerPixel == 16) { ErrorF("%s %s: Color weight: %1d%1d%1d\n", XCONFIG_GIVEN, mach64InfoRec.name, xf86weight.red, xf86weight.green, xf86weight.blue); } } #ifdef DPMSExtension if (DPMSEnabledSwitch || (OFLG_ISSET(OPTION_POWER_SAVER, &mach64InfoRec.options) && !DPMSDisabledSwitch)) defaultDPMSEnabled = DPMSEnabled = TRUE; #endif #ifdef XFreeXDGA mach64InfoRec.displayWidth = mach64InfoRec.virtualX; mach64InfoRec.directMode = XF86DGADirectPresent | XF86DGAAccelPresent; #endif return(TRUE); } /* * mach64PrintIdent -- * Print the indentification of the video card. */ void mach64PrintIdent() { ErrorF(" %s: accelerated server for ATI Mach64 graphics adaptors ", mach64InfoRec.name); ErrorF("(Patchlevel %s)\n", mach64InfoRec.patchLevel); } /* * mach64Initialize -- * Attempt to find and initialize a VGA framebuffer * Most of the elements of the ScreenRec are filled in. The * video is enabled for the frame buffer... */ Bool mach64Initialize (scr_index, pScreen, argc, argv) int scr_index; /* The index of pScreen in the ScreenInfo */ ScreenPtr pScreen; /* The Screen to initialize */ int argc; /* The number of the Server's arguments. */ char **argv; /* The arguments themselves. Don't change! */ { int displayResolution = 75; /* default to 75dpi */ extern int monitorResolution; mach64InitGC(); mach64InitDisplay(scr_index); mach64CalcCRTCRegs(&mach64CRTCRegs, mach64InfoRec.modes); mach64SetCRTCRegs(&mach64CRTCRegs); mach64InitEnvironment(); /* Clear the display. * Need to set the color, origin, and size. Then draw. */ WaitQueue(4); if (xf86bpp == 8 && xf86FlipPixels) regw(DP_FRGD_CLR, 1); else regw(DP_FRGD_CLR, 0); regw(DST_Y_X, 0); regw(DST_CNTL, 0x03); regw(DST_HEIGHT_WIDTH, ((mach64VirtX << 16) | mach64VirtY)); mach64CacheInit(mach64VirtX, mach64VirtY); mach64FontCache8Init(mach64VirtX, mach64VirtY); mach64ImageInit(); WaitIdleEmpty(); /* Make sure that all commands have finished */ /* * Take display resolution from the -dpi flag if specified */ if (monitorResolution) displayResolution = monitorResolution; if (!mach64ScreenInit(pScreen, mach64VideoMem, mach64VirtX, mach64VirtY, displayResolution, displayResolution, mach64VirtX)) return(FALSE); savepScreen = pScreen; pScreen->CloseScreen = mach64CloseScreen; pScreen->SaveScreen = mach64SaveScreen; switch (mach64InfoRec.bitsPerPixel) { case 8: pScreen->InstallColormap = mach64InstallColormap; pScreen->UninstallColormap = mach64UninstallColormap; pScreen->ListInstalledColormaps = mach64ListInstalledColormaps; pScreen->StoreColors = mach64StoreColors; break; case 16: case 32: pScreen->InstallColormap = cfbInstallColormap; pScreen->UninstallColormap = cfbUninstallColormap; pScreen->ListInstalledColormaps = cfbListInstalledColormaps; pScreen->StoreColors = (void (*)())NoopDDA; } if (OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options)) { miDCInitialize (pScreen, &xf86PointerScreenFuncs); } else { pScreen->QueryBestSize = mach64QueryBestSize; xf86PointerScreenFuncs.WarpCursor = mach64WarpCursor; (void)mach64CursorInit(0, pScreen); } #ifdef PIXPRIV mach64PixmapIndex = AllocatePixmapPrivateIndex(); if (!AllocatePixmapPrivate(pScreen, mach64PixmapIndex, sizeof(mach64PixPrivRec))) return FALSE; #endif return (cfbCreateDefColormap(pScreen)); } /* * Assign a new serial number to the window. * Used to force GC validation on VT switch. */ /*ARGSUSED*/ static int mach64NewSerialNumber(pWin, data) WindowPtr pWin; pointer data; { pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; return WT_WALKCHILDREN; } /* * mach64EnterLeaveVT -- * grab/ungrab the current VT completely. */ void mach64EnterLeaveVT(enter, screen_idx) Bool enter; int screen_idx; { PixmapPtr pspix; ScreenPtr pScreen = savepScreen; if (!xf86Exiting && !xf86Resetting) { switch (mach64InfoRec.bitsPerPixel) { case 8: pspix = (PixmapPtr)pScreen->devPrivate; break; case 16: pspix = (PixmapPtr)pScreen->devPrivates[cfb16ScreenPrivateIndex].ptr; break; case 32: pspix = (PixmapPtr)pScreen->devPrivates[cfb32ScreenPrivateIndex].ptr; break; } } #ifdef XFreeXDGA /* * Patch up things to allow a graphics operations to go to the screen * while remaining in direct graphics mode. */ if (mach64InfoRec.directMode & XF86DGADoAccel) { if (enter) { pspix->devPrivate.ptr = mach64VideoMem; pScreen->CopyWindow = mach64CopyWindow; pScreen->PaintWindowBackground = mach64PaintWindow; pScreen->PaintWindowBorder = mach64PaintWindow; switch (mach64InfoRec.bitsPerPixel) { case 8: pScreen->GetSpans = cfbGetSpans; break; case 16: pScreen->GetSpans = cfb16GetSpans; break; case 32: pScreen->GetSpans = cfb32GetSpans; break; } } else { pspix->devPrivate.ptr = ppix->devPrivate.ptr; switch (mach64InfoRec.bitsPerPixel) { case 8: pScreen->CopyWindow = cfbCopyWindow; pScreen->GetSpans = cfbGetSpans; pScreen->PaintWindowBackground = cfbPaintWindow; pScreen->PaintWindowBorder = cfbPaintWindow; break; case 16: pScreen->CopyWindow = cfb16CopyWindow; pScreen->GetSpans = cfb16GetSpans; pScreen->PaintWindowBackground = cfb16PaintWindow; pScreen->PaintWindowBorder = cfb16PaintWindow; break; case 32: pScreen->CopyWindow = cfb32CopyWindow; pScreen->GetSpans = cfb32GetSpans; pScreen->PaintWindowBackground = cfb32PaintWindow; pScreen->PaintWindowBorder = cfb32PaintWindow; break; } } return; } #endif /* XFreeXDGA */ if (pScreen && !xf86Exiting && !xf86Resetting) WalkTree(pScreen, mach64NewSerialNumber, 0); if (enter) { if (vgaBase) xf86MapDisplay(screen_idx, VGA_REGION); if (mach64VideoMem != vgaBase) xf86MapDisplay(screen_idx, LINEAR_REGION); if (!xf86Resetting) { ScrnInfoPtr pScr = (ScrnInfoPtr)XF86SCRNINFO(pScreen); mach64InitDisplay(screen_idx); mach64SetCRTCRegs(&mach64CRTCRegs); mach64InitEnvironment(); WaitQueue(4); regw(DP_FRGD_CLR, 1); regw(DST_Y_X, 0); regw(DST_CNTL, 0x03); regw(DST_HEIGHT_WIDTH, ((mach64VirtX << 16) | mach64VirtY)); mach64CacheInit(mach64VirtX, mach64VirtY); mach64FontCache8Init(mach64VirtX, mach64VirtY); if (!OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options)) mach64RestoreCursor(pScreen); mach64AdjustFrame(pScr->frameX0, pScr->frameY0); WaitIdleEmpty(); /* Make sure that all commands have finished */ if (LUTissaved) { mach64RestoreLUT(mach64savedLUT); LUTissaved = FALSE; mach64RestoreColor0(pScreen); } if (pspix->devPrivate.ptr != mach64VideoMem && ppix) { pspix->devPrivate.ptr = mach64VideoMem; (mach64ImageWriteFunc)(0, 0, pScreen->width, pScreen->height, ppix->devPrivate.ptr, PixmapBytePad(pScreen->width, pScreen->rootDepth), 0, 0, MIX_SRC, ~0); } if (pScreen) { pScreen->CopyWindow = mach64CopyWindow; pScreen->PaintWindowBackground = mach64PaintWindow; pScreen->PaintWindowBorder = mach64PaintWindow; switch (mach64InfoRec.bitsPerPixel) { case 8: pScreen->GetSpans = cfbGetSpans; break; case 16: pScreen->GetSpans = cfb16GetSpans; break; case 32: pScreen->GetSpans = cfb32GetSpans; break; } } } if (ppix) { (pScreen->DestroyPixmap)(ppix); ppix = NULL; } } else { if (vgaBase) xf86MapDisplay(screen_idx, VGA_REGION); if (mach64VideoMem != vgaBase) xf86MapDisplay(screen_idx, LINEAR_REGION); if (!xf86Exiting) { ppix = (pScreen->CreatePixmap)(pScreen, pScreen->width, pScreen->height, pScreen->rootDepth); if (ppix) { (mach64ImageReadFunc)(0, 0, pScreen->width, pScreen->height, ppix->devPrivate.ptr, PixmapBytePad(pScreen->width, pScreen->rootDepth), 0, 0, ~0); pspix->devPrivate.ptr = ppix->devPrivate.ptr; } switch (mach64InfoRec.bitsPerPixel) { case 8: pScreen->CopyWindow = cfbCopyWindow; pScreen->GetSpans = cfbGetSpans; pScreen->PaintWindowBackground = cfbPaintWindow; pScreen->PaintWindowBorder = cfbPaintWindow; break; case 16: pScreen->CopyWindow = cfb16CopyWindow; pScreen->GetSpans = cfb16GetSpans; pScreen->PaintWindowBackground = cfb16PaintWindow; pScreen->PaintWindowBorder = cfb16PaintWindow; break; case 32: pScreen->CopyWindow = cfb32CopyWindow; pScreen->GetSpans = cfb32GetSpans; pScreen->PaintWindowBackground = cfb32PaintWindow; pScreen->PaintWindowBorder = cfb32PaintWindow; break; } } if (!OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options)) mach64CursorOff(); mach64SaveLUT(mach64savedLUT); LUTissaved = TRUE; if (!xf86Resetting) { #ifdef XFreeXDGA if (!(mach64InfoRec.directMode & XF86DGADirectGraphics)) #endif mach64CleanUp(); } if (vgaBase) xf86UnMapDisplay(screen_idx, VGA_REGION); if (mach64VideoMem != vgaBase) xf86UnMapDisplay(screen_idx, LINEAR_REGION); } } /* * mach64CloseScreen -- * called to ensure video is enabled when server exits. */ /*ARGSUSED*/ Bool mach64CloseScreen(screen_idx, pScreen) int screen_idx; ScreenPtr pScreen; { extern void mach64ClearSavedCursor(); /* * Hmm... The server may shut down even if it is not running on the * current vt. Let's catch this case here. */ xf86Exiting = TRUE; if (xf86VTSema) mach64EnterLeaveVT(LEAVE, screen_idx); else if (ppix) { /* 7-Jan-94 CEG: The server is not running on the current vt. * Free the screen snapshot taken when the server vt was left. */ (savepScreen->DestroyPixmap)(ppix); ppix = NULL; } if (!OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options)) mach64ClearSavedCursor(screen_idx); switch (mach64InfoRec.bitsPerPixel) { case 8: cfbCloseScreen(screen_idx, savepScreen); break; case 16: cfb16CloseScreen(screen_idx, savepScreen); break; case 32: cfb32CloseScreen(screen_idx, savepScreen); break; } savepScreen = NULL; return(TRUE); } /* * mach64SaveScreen -- * blank the screen. */ Bool mach64SaveScreen (pScreen, on) ScreenPtr pScreen; Bool on; { if (on) SetTimeSinceLastInputEvent(); if (xf86VTSema) { if (on) { mach64SetRamdac(mach64CRTCRegs.color_depth, TRUE, mach64CRTCRegs.dot_clock); if (!OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options)) if (mach64HWCursorSave != -1) { if (mach64RamdacSubType == DAC_IBMRGB514) mach64P_RGB514Index(0x30, mach64HWCursorSave); else regwb(GEN_TEST_CNTL, mach64HWCursorSave); mach64HWCursorSave = -1; } mach64RestoreColor0(pScreen); if (mach64RamdacSubType != DAC_ATI68875) outb(ioDAC_REGS+2, 0xff); } else { outb(ioDAC_REGS, 0); outb(ioDAC_REGS+1, 0); outb(ioDAC_REGS+1, 0); outb(ioDAC_REGS+1, 0); outb(ioDAC_REGS+2, 0x00); if (mach64InfoRec.bitsPerPixel > 8 && mach64RamdacSubType == DAC_INTERNAL) { int temp; outb(ioDAC_REGS, 0); for (temp = 0; temp < 256; temp++) { outb(ioDAC_REGS + 1, 0); outb(ioDAC_REGS + 1, 0); outb(ioDAC_REGS + 1, 0); } } mach64SetRamdac(CRTC_PIX_WIDTH_8BPP, TRUE, mach64CRTCRegs.dot_clock); if (!OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options)) { if (mach64RamdacSubType == DAC_IBMRGB514) { mach64HWCursorSave = mach64R_RGB514Index(0x30); mach64P_RGB514Index(0x30, 0x00); } else { mach64HWCursorSave = regrb(GEN_TEST_CNTL); regwb(GEN_TEST_CNTL, mach64HWCursorSave & ~HWCURSOR_ENABLE); } } if (mach64RamdacSubType != DAC_ATI68875) outb(ioDAC_REGS+2, 0x00); } } return(TRUE); } /* * mach64DPMSSet -- Sets VESA Display Power Management Signaling (DPMS) Mode */ void mach64DPMSSet(PowerManagementMode) int PowerManagementMode; { #ifdef DPMSExtension int crtcGenCntl; if (!xf86VTSema) return; crtcGenCntl = regr(CRTC_GEN_CNTL) & ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS); switch (PowerManagementMode) { case DPMSModeOn: /* HSync: On, VSync: On */ break; case DPMSModeStandby: /* HSync: Off, VSync: On */ crtcGenCntl |= CRTC_HSYNC_DIS; break; case DPMSModeSuspend: /* HSync: On, VSync: Off */ crtcGenCntl |= CRTC_VSYNC_DIS; break; case DPMSModeOff: /* HSync: Off, VSync: Off */ crtcGenCntl |= (CRTC_HSYNC_DIS | CRTC_VSYNC_DIS); break; } usleep(10000); regw(CRTC_GEN_CNTL, crtcGenCntl); #endif } /* * mach64AdjustFrame -- * Modify the CRT_OFFSET for panning the display. */ void mach64AdjustFrame(x, y) int x, y; { int byte_offset = ((x + y*mach64VirtX) * (mach64InfoRec.bitsPerPixel / 8)) >> 3; if (!OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options)) mach64CursorOff(); regw(CRTC_OFF_PITCH, (regr(CRTC_OFF_PITCH) & 0xfff00000) | byte_offset); if (!OFLG_ISSET(OPTION_SW_CURSOR, &mach64InfoRec.options)) mach64RepositionCursor(savepScreen); #ifdef XFreeXDGA if (mach64InfoRec.directMode & XF86DGADirectGraphics) { #if 0 /* Wait until the current vertical line has gone past 0. */ while (regr(CRTC_VLINE_CRNT_VLINE) & CRTC_CRNT_VLINE); while (!(regr(CRTC_VLINE_CRNT_VLINE) & CRTC_CRNT_VLINE)); #else /* Wait until vertical retrace is in progress. */ /* This seems better */ while (regrb(CRTC_INT_CNTL) & CRTC_VBLANK); while (!(regrb(CRTC_INT_CNTL) & CRTC_VBLANK)); #endif } #endif } /* * mach64SwitchMode -- * Reinitialize the CRTC registers for the new mode. */ Bool mach64SwitchMode(mode) DisplayModePtr mode; { mach64CalcCRTCRegs(&mach64CRTCRegs, mode); mach64SetCRTCRegs(&mach64CRTCRegs); return(TRUE); } /* * mach64ValidMode -- * */ static int mach64ValidMode(mode, verbose, flag) DisplayModePtr mode; Bool verbose; { if ((mach64LCDPanelID >= 0) && ((mode->HDisplay > mach64LCDHorizontal) || (mode->VDisplay > mach64LCDVertical))) { if (verbose) ErrorF("Mode \"%s\" exceeds panel dimensions. Deleted.\n", mode->name); return MODE_BAD; } return MODE_OK; }