/* $XFree86: xc/programs/Xserver/hw/xfree86/accel/mach32/mach32.c,v 3.63.2.6 1998/02/07 10:05:08 hohndel Exp $ */ /* * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. * Copyright 1993 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, RICKARD E. FAITH, AND CRAIG E. GROESCHEL * DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ANY OR ALL OF * 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) * Modified for 16 bpp and VTSema-independence by Craig E. Groeschel * Modified for more 16 bpp and Ramdac parsing by Bryan K. Feir * */ /* $XConsortium: mach32.c /main/23 1996/10/27 11:46:34 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 "gc.h" #include "windowstr.h" #include "compiler.h" #include "xf86.h" #include "xf86Priv.h" #include "xf86Procs.h" #include "xf86_HWlib.h" #include "mach32.h" #include "regmach32.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 mach32MaxClock; extern int mach32MaxTlc34075Clock; extern int mach32Max16bppClock; extern Bool xf86Resetting, xf86Exiting, xf86ProbeFailed; unsigned short mach32MemorySize = 0; extern char *xf86VisualNames[]; extern unsigned short vgaIOBase; static int mach32ValidMode( #if NeedFunctionPrototypes DisplayModePtr, Bool, int #endif ); ScrnInfoRec mach32InfoRec = { FALSE, /* Bool configured */ -1, /* int tmpIndex */ -1, /* int scrnIndex */ mach32Probe, /* Bool (* Probe)() */ mach32Initialize, /* Bool (* Init)() */ mach32ValidMode, /* int (* ValidMode)() */ mach32EnterLeaveVT, /* void (* EnterLeaveVT)() */ (void (*)())NoopDDA,/* void (* EnterLeaveMonitor)() */ (void (*)())NoopDDA,/* void (* EnterLeaveCursor)() */ mach32AdjustFrame, /* void (* AdjustFrame)() */ mach32SwitchMode, /* Bool (* SwitchMode)() */ (void (*)())NoopDDA,/* void (* DPMSSet)() */ mach32PrintIdent, /* 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 */ "Mach32", /* char *name */ {0, }, /* xrgb blackColour */ {0, }, /* xrgb whiteColour */ mach32ValidTokens, /* int *validTokens */ MACH32_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 */ mach32SetVGAPage, /* Set Vid Page */ 0, /* unsigned long physBase */ 0 /* int physSize */ #endif }; short mach32alu[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 mach32savedLUT[256]; static Bool LUTissaved = FALSE; short mach32MaxX, mach32MaxY; short mach32VirtX, mach32VirtY; short mach32DisplayWidth; Bool mach32Use4MbAperture = FALSE; Bool mach32DAC8Bit = FALSE; Bool mach32DoubleClock = FALSE; Bool mach32clkprobedif4fix = FALSE; static unsigned Mach32_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 */ ATIEXT, ATIEXT+1, /* 8514 Registers */ DAC_MASK, DAC_R_INDEX, DAC_W_INDEX, DAC_DATA, DISP_STAT, H_TOTAL, H_DISP, H_SYNC_STRT, H_SYNC_WID, V_TOTAL, V_DISP, V_SYNC_STRT, V_SYNC_WID, DISP_CNTL, ADVFUNC_CNTL, SUBSYS_CNTL, ROM_PAGE_SEL, CUR_Y, CUR_X, DESTY_AXSTP, DESTX_DIASTP, ERR_TERM, MAJ_AXIS_PCNT, GP_STAT, CMD, SHORT_STROKE, BKGD_COLOR, FRGD_COLOR, WRT_MASK, RD_MASK, COLOR_CMP, BKGD_MIX, FRGD_MIX, MULTIFUNC_CNTL, PIX_TRANS, /* Mach32 Registers */ GE_OFFSET_LO, GE_OFFSET_HI, CRT_OFFSET_LO, CRT_OFFSET_HI, CLOCK_SEL, SHADOW_SET, SHADOW_CTL, CRT_PITCH, GE_PITCH, EXT_SCISSOR_L, EXT_SCISSOR_R, EXT_SCISSOR_T, EXT_SCISSOR_B, MISC_OPTIONS, CONFIG_STATUS_1, CONFIG_STATUS_2, MEM_CFG, MEM_BNDRY, ROM_ADDR_1, READ_SRC_X, CHIP_ID, EXT_FIFO_STATUS, R_EXT_GE_CONFIG, EXT_GE_CONFIG, DP_CONFIG, DEST_X_START, DEST_X_END, DEST_Y_END, ALU_FG_FN, MISC_CNTL, R_MISC_CNTL, HORZ_OVERSCAN, VERT_OVERSCAN, EXT_GE_STATUS, LINEDRAW, LINEDRAW_OPT, LINEDRAW_INDEX, EXT_CURSOR_COLOR_0, EXT_CURSOR_COLOR_1, }; static int Num_Mach32_IOPorts = (sizeof(Mach32_IOPorts)/ sizeof(Mach32_IOPorts[0])); /* mach32WeightMasks must match mach32weights[], below */ static short mach32WeightMasks[] = { RGB16_565, RGB16_555, RGB16_655, RGB16_664 }; short mach32WeightMask; static mach32CRTCRegRec mach32CRTCRegs; static ScreenPtr savepScreen = NULL; static PixmapPtr ppix = NULL; /* * 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 Graphics_Ultra_Present; int ATI_Accelerator_Present; int Mach8_Present; int Mach32_Present; int Bus_8bit_Only; int Bus_Type; int Mem_Size; int Mem_Type; int DAC_Type; } ATIInformationBlock; int mach32Ramdac; int mach32RamdacSubType; char *mach32ramdac_names[] = { "ATI-68830", "IMS-G173/SC1148[368]", "ATI68875/TLC34075/Bt885", "Bt47[68]/INMOS17[68]", "AT&T20C49[01]/Bt48[12]/IMS-G174/MU9C{1880,4910}/SC1502[56]", "ATI-68860", "STG1700 (or similar)", "SC15021/STG1702/AT&T21C498" }; SymTabRec mach32RamdacTable[] = { { DAC_ATI68830, "ati68830" }, { DAC_SC11483, "sc11483" }, { DAC_SC11483, "sc11486" }, { DAC_SC11483, "sc11488" }, { DAC_SC11483, "ims_g173" }, { DAC_SC11483, "mu9c4870" }, { DAC_ATI68875, "ati68875" }, { DAC_ATI68875, "bt885" }, { DAC_ATI68875, "tlc34075" }, { DAC_BT476, "bt476" }, { DAC_BT476, "bt478" }, { DAC_BT476, "inmos176" }, { DAC_BT476, "inmos178" }, { DAC_BT481, "bt481" }, { DAC_BT481, "bt482" }, { DAC_BT481, "ims_g174" }, { DAC_BT481, "mu9c1880" }, { DAC_BT481, "mu9c4910" }, { DAC_BT481, "sc15025" }, { DAC_BT481, "sc15026" }, { DAC_ATT20C490, "att20c490" }, { DAC_ATT20C490, "att20c491" }, { DAC_ATI68860, "ati68860" }, { DAC_STG1700, "stg1700" }, { DAC_ATT21C498, "sc15021" }, { DAC_ATT21C498, "stg1702" }, { DAC_ATT21C498, "att21c498" }, { -1, "" }, }; SymTabRec mach32RamdacNames[] = { { DAC_ATI68830, "ATI-68830" }, { DAC_SC11483, "IMS-G173/SC1148[368]" }, { DAC_ATI68875, "ATI68875/TLC34075/Bt885" }, { DAC_BT476, "Bt47[68]/INMOS17[68]" }, { DAC_BT481, "Bt48[12]/IMS-G174/MU9C{1880,4910}/SC1502[56]" }, { DAC_ATT20C490, "AT&T20C49[01]" }, { DAC_ATI68860, "ATI-68860" }, { DAC_STG1700, "STG1700 (or similar)" }, { DAC_ATT21C498, "SC15021/STG1702/AT&T21C498" }, { -1, "" }, }; int mach32BusType; static ATIInformationBlock *GetATIInformationBlock() { #define BIOS_DATA_SIZE 0x70 char signature[] = " 761295520"; char bios_data[BIOS_DATA_SIZE]; char bios_signature[10]; int tmp; static ATIInformationBlock info = { 0, }; if (xf86ReadBIOS(mach32InfoRec.BIOSbase, 0x30, (unsigned char *)bios_signature, 10) != 10) { return NULL; } if (strncmp( signature, bios_signature, 10 )) return NULL; if (xf86ReadBIOS(mach32InfoRec.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.Graphics_Ultra_Present = !(bios_data[ 0x44 ] & 0x40); /* Test for graphics acceleration */ if (!info.Graphics_Ultra_Present) return &info; /* Test for ATI accelerator product */ info.ATI_Accelerator_Present = 1; /* Reset the 8514/A, and disable all interrupts. */ outw(SUBSYS_CNTL, GPCTRL_RESET | CHPTEST_NORMAL); outw(SUBSYS_CNTL, GPCTRL_ENAB | CHPTEST_NORMAL); tmp = inw( ROM_ADDR_1 ); outw( ROM_ADDR_1, 0x5555 ); ProbeWaitIdleEmpty(); if (inw( ROM_ADDR_1 ) != 0x5555) { info.ATI_Accelerator_Present = 0; } else { outw( ROM_ADDR_1, 0x2a2a ); ProbeWaitIdleEmpty(); if (inw( ROM_ADDR_1 ) != 0x2a2a) { info.ATI_Accelerator_Present = 0; } } outw( ROM_ADDR_1, tmp ); if (!info.ATI_Accelerator_Present) return &info; /* Determine chip family */ outw( DESTX_DIASTP, 0xaaaa ); WaitIdleEmpty(); if (inw( READ_SRC_X ) != 0x02aa) info.Mach8_Present = 1; else info.Mach32_Present = 1; outw( DESTX_DIASTP, 0x5555 ); WaitIdleEmpty(); if (inw( READ_SRC_X ) != 0x0555) { if (!info.Mach8_Present) { ErrorF( "WARNING: Chip should be Mach8, but isn't!\n" ); info.Mach8_Present = 0; } } else { if (!info.Mach32_Present) { ErrorF( "WARNING: Chip should be Mach32, but isn't!\n" ); info.Mach32_Present = 0; } } if (info.Mach8_Present) { tmp = inw( CONFIG_STATUS_1 ); if (!(tmp & 0x02)) info.Bus_8bit_Only = 1; switch( (tmp & MEM_INSTALLED) >> 5 ) { case 0: info.Mem_Size = 512; break; case 1: info.Mem_Size = 1024; break; } info.Mem_Type = (tmp & DRAM_ENA) >> 4; } if (info.Mach32_Present) { tmp = inw( CONFIG_STATUS_1 ); info.Bus_Type = tmp & BUS_TYPE; info.Mem_Type = tmp & MEM_TYPE; info.DAC_Type = (tmp & DACTYPE) >> 9; tmp = inw( CONFIG_STATUS_2 ); if ((info.Bus_Type == ISA_16_BIT) && !(tmp & ISA_16_ENA)) info.Bus_8bit_Only = 1; tmp = inw( MISC_OPTIONS ); 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; } } return &info; } /* * mach32Probe -- * Probe the hardware */ Bool mach32Probe() { int i, j; DisplayModePtr pMode, pEnd; ATIInformationBlock *info; int available_ram; Bool sw_cursor_supplied; OFlagSet validOptions; int tx, ty; xrgb mach32weights[] = { { 5, 6, 5 }, { 5, 5, 5 }, { 6, 5, 5 }, { 6, 6, 4 } }; xf86ClearIOPortList(mach32InfoRec.scrnIndex); xf86AddIOPorts(mach32InfoRec.scrnIndex, Num_Mach32_IOPorts, Mach32_IOPorts); xf86EnableIOPorts(mach32InfoRec.scrnIndex); info = GetATIInformationBlock(); if (!info || !info->Mach32_Present) { xf86DisableIOPorts(mach32InfoRec.scrnIndex); return(FALSE); } if (xf86bpp < 0) { xf86bpp = mach32InfoRec.depth; } if (xf86weight.red == 0 || xf86weight.green == 0 || xf86weight.blue == 0) { xf86weight = mach32InfoRec.weight; } switch (xf86bpp) { case 8: break; case 15: case 16: if (info->DAC_Type == DAC_BT476) { /* * Hate to break the news to them, but hopefully this will forestall * queries of, "But you said it supports 16bpp...?" */ ErrorF("Unsupported bpp--this ramdac supports only 8 bpp\n"); return(FALSE); } if (info->DAC_Type != DAC_TLC34075 && info->DAC_Type != DAC_BT481 && info->DAC_Type != DAC_ATT20C490) { ErrorF("Unsupported bpp in this version of code.\n"); return(FALSE); } mach32InfoRec.depth = xf86bpp; /* if 16/555, set to 15, below */ mach32InfoRec.bitsPerPixel = 16; if (mach32InfoRec.defaultVisual < 0) mach32InfoRec.defaultVisual = TrueColor; if (defaultColorVisualClass < 0) defaultColorVisualClass = mach32InfoRec.defaultVisual; if (defaultColorVisualClass != TrueColor) { ErrorF("Invalid default visual type: %d (%s)\n", defaultColorVisualClass, xf86VisualNames[defaultColorVisualClass]); return(FALSE); } break; default: ErrorF("Invalid bpp--valid "); if (info->DAC_Type != DAC_TLC34075 && info->DAC_Type != DAC_BT481) ErrorF("number of bpp is 8\n"); else ErrorF("numbers of bpp are 8, 15 and 16\n"); return(FALSE); } if (xf86bpp == 15) { if (xf86weight.red != 5 && xf86weight.green != 5 && xf86weight.blue != 5) { ErrorF("Invalid color weighting\n"); return(FALSE); } mach32WeightMask = mach32WeightMasks[1]; } if (xf86bpp == 16) { for (i = 0; i < 4; i++) { if (xf86weight.red == mach32weights[i].red && xf86weight.green == mach32weights[i].green && xf86weight.blue == mach32weights[i].blue) break; } if (i == 4) { ErrorF("Invalid color weighting\n"); return(FALSE); } if (i == 1) mach32InfoRec.depth = 15; /* Of course, the SC11483 doesn't get here, but... */ if ( (info->DAC_Type == DAC_SC11483 || info->DAC_Type == DAC_BT481 || info->DAC_Type == DAC_ATT20C490) && (i > 1)) { ErrorF("Invalid RGB weighting--valid weights are 555 and 565.\n"); return(FALSE); } mach32WeightMask = mach32WeightMasks[i]; } /* There are several considerations in working out the max clock: */ mach32InfoRec.maxClock = mach32MaxClock; /* Type 2 and 5 DACs are high performance, and can handle 135MHz */ if (info->DAC_Type == DAC_TLC34075 || info->DAC_Type == DAC_ATI68860) { mach32InfoRec.maxClock = mach32MaxTlc34075Clock; } if (mach32InfoRec.bitsPerPixel == 16) { /* Only the ATI68860 can MUX 4 pixels at 16bpp each */ if (info->DAC_Type != DAC_ATI68860) { if (info->DAC_Type == DAC_ATI68875) mach32InfoRec.maxClock = mach32MaxClock; else mach32InfoRec.maxClock /= 2; } /* 8-bit data path DACs have to be double-clocked */ if (info->DAC_Type == DAC_ATI68830 || info->DAC_Type == DAC_SC11483 || info->DAC_Type == DAC_BT481 || info->DAC_Type == DAC_ATT20C490) { ErrorF("%s %s: Eight-bit DAC path, halving clocks\n", XCONFIG_PROBED, mach32InfoRec.name); mach32DoubleClock = TRUE; } } OFLG_ZERO(&validOptions); OFLG_SET(OPTION_CLKDIV2, &validOptions); OFLG_SET(OPTION_SW_CURSOR, &validOptions); OFLG_SET(OPTION_NOLINEAR_MODE, &validOptions); OFLG_SET(OPTION_CSYNC, &validOptions); OFLG_SET(OPTION_INTEL_GX, &validOptions); OFLG_SET(OPTION_DAC_8_BIT, &validOptions); OFLG_SET(OPTION_AST_MACH32, &validOptions); xf86VerifyOptions(&validOptions, &mach32InfoRec); mach32InfoRec.chipset = "mach32"; xf86ProbeFailed = FALSE; mach32BusType = info->Bus_Type; if (xf86Verbose) { ErrorF("%s %s: card type: ", XCONFIG_PROBED, mach32InfoRec.name); switch(mach32BusType) { case EISA: ErrorF("EISA\n"); break; case LOCAL_386SX: ErrorF("localbus (386SX)\n"); break; case LOCAL_386DX: ErrorF("localbus (386DX)\n"); break; case LOCAL_486: ErrorF("localbus (486)\n"); break; case PCI: ErrorF("PCI\n"); break; default: ErrorF("ISA\n"); } } if (!mach32InfoRec.clocks) { outb(DISP_CNTL, DISPEN_DISAB | MEMCFG_4 | ODDBNKENAB); /* 13-jun-93 TCG : set up dummy video mode */ outw(SHADOW_SET, 1); outw(SHADOW_CTL, 0); outw(SHADOW_SET, 2); outw(SHADOW_CTL, 0); outw(SHADOW_SET, 0); outw(ADVFUNC_CNTL, DISABPASSTHRU); /* vt: 480 488 +31 528 hz: 640 656 +248 920 */ outw(V_TOTAL, 0x420); outw(V_DISP, 0x3c0); outw(V_SYNC_STRT, 0x3d0); outw(V_SYNC_WID, 0x1f); outb(H_TOTAL, 0x72); outw(H_DISP, 0x4f); outb(H_SYNC_STRT, 0x51); outb(H_SYNC_WID, 0x1f); outb(DAC_MASK, 0x00); outb(DISP_CNTL, DISPEN_ENAB | MEMCFG_4 | ODDBNKENAB); /* 2-oct-93 TCG : detect clocks with dif4 fix */ mach32clkprobedif4fix = TRUE; xf86GetClocks(16, mach32ClockSelect, (void (*)())NoopDDA, (SaveScreenProcPtr)NoopDDA, DISP_STAT, 2, 7, 44900, &mach32InfoRec); outw(CLOCK_SEL, 0); /* reset pass-through */ mach32clkprobedif4fix = FALSE; outw(SHADOW_SET, 1); outw(SHADOW_CTL, 0x3f); outw(SHADOW_SET, 2); outw(SHADOW_CTL, 0x3f); outw(SHADOW_SET, 0); outb(DAC_MASK, 0xff); if (mach32DoubleClock) { for (j = 0; j < 16; j++) mach32InfoRec.clock[j] /= 2; mach32InfoRec.clocks = 16; } else { for (j = 0; j < 16; j++) mach32InfoRec.clock[j + 16] = mach32InfoRec.clock[j] / 2; mach32InfoRec.clocks = 32; } } else if (mach32DoubleClock) { if (mach32InfoRec.clocks > 16) mach32InfoRec.clocks = 16; for (j = 0; j < mach32InfoRec.clocks; j++) mach32InfoRec.clock[j] /= 2; } if (xf86Verbose) { ErrorF("%s ",OFLG_ISSET(XCONFIG_CLOCKS,&mach32InfoRec.xconfigFlag) ? XCONFIG_GIVEN : XCONFIG_PROBED); ErrorF("%s: ", mach32InfoRec.name); ErrorF("Number of Clocks: %d", mach32InfoRec.clocks); for (i = 0; i < mach32InfoRec.clocks; i++) { if (i % 8 == 0) ErrorF("\n%s %s: clocks:", OFLG_ISSET(XCONFIG_CLOCKS,&mach32InfoRec.xconfigFlag) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach32InfoRec.name); ErrorF(" %6.2f", mach32InfoRec.clock[i]/1000.0); } ErrorF("\n"); } if (!mach32InfoRec.videoRam) { #ifdef NEW_MEM_DETECT mach32InfoRec.videoRam = mach32GetMemSize(); #else mach32InfoRec.videoRam = info->Mem_Size; #endif } tx = mach32InfoRec.virtualX; ty = mach32InfoRec.virtualY; pMode = mach32InfoRec.modes; if (pMode == NULL) { ErrorF("No modes supplied in XF86Config\n"); xf86DisableIOPorts(mach32InfoRec.scrnIndex); return(FALSE); } pEnd = (DisplayModePtr)NULL; do { DisplayModePtr pModeSv; /* * xf86LookupMode returns FALSE if it ran into an invalid * parameter */ if(xf86LookupMode(pMode, &mach32InfoRec, LOOKUP_DEFAULT) == FALSE) { pModeSv=pMode->next; xf86DeleteMode(&mach32InfoRec, pMode); pMode = pModeSv; } else if (pMode->HDisplay > 1536) { pModeSv=pMode->next; ErrorF("%s %s: Width of mode \"%s\" is too large (max is" " 1536)\n", XCONFIG_PROBED, mach32InfoRec.name, pMode->name); xf86DeleteMode(&mach32InfoRec, pMode); pMode = pModeSv; } else if (pMode->VDisplay > 1536) { pModeSv=pMode->next; ErrorF("%s %s: Height of mode \"%s\" is too large (max is" " 1536)\n", XCONFIG_PROBED, mach32InfoRec.name, pMode->name); xf86DeleteMode(&mach32InfoRec, pMode); pMode = pModeSv; } else if (pMode->HDisplay * pMode->VDisplay * (mach32InfoRec.bitsPerPixel / 8) > mach32InfoRec.videoRam*1024) { pModeSv=pMode->next; ErrorF("%s %s: Too little memory for mode \"%s\"\n", XCONFIG_PROBED, mach32InfoRec.name, pMode->name); xf86DeleteMode(&mach32InfoRec, 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, mach32InfoRec.name, pMode->HDisplay, pMode->VDisplay, tx, ty); xf86DeleteMode(&mach32InfoRec, 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; mach32InfoRec.virtualX = max(mach32InfoRec.virtualX, pMode->HDisplay); mach32InfoRec.virtualY = max(mach32InfoRec.virtualY, pMode->VDisplay); pMode = pMode->next; } } while (pMode != pEnd); mach32VirtX = mach32InfoRec.virtualX = (mach32InfoRec.virtualX+7) & 0xfff8; mach32VirtY = mach32InfoRec.virtualY; if ((tx != mach32InfoRec.virtualX) || (ty != mach32InfoRec.virtualY)) OFLG_CLR(XCONFIG_VIRTUAL,&mach32InfoRec.xconfigFlag); /* * Limitation of 8514 drawing commands */ if (mach32VirtY > 1536) { ErrorF("Virtual screen height must be no greater than 1536\n"); xf86DisableIOPorts(mach32InfoRec.scrnIndex); return(FALSE); } if (mach32VirtX > 1536) { ErrorF("Virtual screen width must be no greater than 1536\n"); xf86DisableIOPorts(mach32InfoRec.scrnIndex); return(FALSE); } if (xf86Verbose) { ErrorF("%s %s: Virtual resolution: %dx%d\n", OFLG_ISSET(XCONFIG_VIRTUAL, &mach32InfoRec.xconfigFlag) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach32InfoRec.name, mach32VirtX, mach32VirtY); } if (mach32VirtX < 1024) mach32DisplayWidth = 1024; else mach32DisplayWidth = mach32VirtX; if (xf86Verbose) { ErrorF("%s %s: Display width: %d\n", XCONFIG_PROBED, mach32InfoRec.name, mach32DisplayWidth); } /* Set mach32MemorySize to required MEM_SIZE value in MISC_OPTIONS */ if (mach32InfoRec.videoRam <= 512) mach32MemorySize = MEM_SIZE_512K; else if (mach32InfoRec.videoRam <= 1024) mach32MemorySize = MEM_SIZE_1M; else if (mach32InfoRec.videoRam <= 2048) mach32MemorySize = MEM_SIZE_2M; else mach32MemorySize = MEM_SIZE_4M; if (xf86Verbose) { ErrorF("%s %s: videoram: %dk\n", OFLG_ISSET(XCONFIG_VIDEORAM, &mach32InfoRec.xconfigFlag) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach32InfoRec.name, mach32InfoRec.videoRam ); } if (((mach32DisplayWidth) * (mach32VirtY) * (mach32InfoRec.bitsPerPixel / 8)) > (mach32InfoRec.videoRam*1024)) { ErrorF("Not enough memory for requested display size (%dx%d)\n", mach32DisplayWidth, mach32VirtY); xf86DisableIOPorts(mach32InfoRec.scrnIndex); return(FALSE); } /* Set values of mach32MaxX and mach32MaxY. * 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). */ mach32MaxX = mach32DisplayWidth - 1; available_ram = mach32InfoRec.videoRam * 1024; sw_cursor_supplied = OFLG_ISSET(OPTION_SW_CURSOR, &mach32InfoRec.options); if (!sw_cursor_supplied) { if (available_ram - (mach32DisplayWidth * mach32VirtY) >= MACH32_CURSBYTES) { available_ram -= (MACH32_CURSBYTES + 1023) & ~1023; mach32InfoRec.videoRam -= (MACH32_CURSBYTES + 1023) / 1024; } else { OFLG_SET(OPTION_SW_CURSOR, &mach32InfoRec.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 ? XCONFIG_GIVEN : XCONFIG_PROBED, mach32InfoRec.name, OFLG_ISSET(OPTION_SW_CURSOR, &mach32InfoRec.options) ? "software" : "hardware"); mach32MaxY = available_ram / (mach32DisplayWidth * (mach32InfoRec.bitsPerPixel / 8)) - 1; if (mach32MaxY > 1535) mach32MaxY = 1535; /* Limitation of 8514 drawing commands */ mach32Use4MbAperture = !OFLG_ISSET(OPTION_NOLINEAR_MODE, &mach32InfoRec.options) && (info->Bus_Type == LOCAL_386SX || info->Bus_Type == LOCAL_386DX || info->Bus_Type == LOCAL_486 || info->Bus_Type == EISA || info->Bus_Type == PCI) && xf86LinearVidMem(); if (mach32InfoRec.ramdac) { mach32RamdacSubType = xf86StringToToken(mach32RamdacTable, mach32InfoRec.ramdac); mach32Ramdac = mach32RamdacSubType & 0x0f; if (mach32RamdacSubType < 0) { ErrorF("%s %s: Unknown RAMDAC type \"%s\"\n", XCONFIG_GIVEN, mach32InfoRec.name, mach32InfoRec.ramdac); xf86DisableIOPorts(mach32InfoRec.scrnIndex); return(FALSE); } } else { mach32Ramdac = info->DAC_Type; mach32RamdacSubType = mach32Ramdac; } if (xf86Verbose) { if (mach32Use4MbAperture) { ErrorF("%s %s: Using 4 MB aperture\n", XCONFIG_PROBED, mach32InfoRec.name); } else { ErrorF("%s %s: Using 64 kb aperture\n", OFLG_ISSET(OPTION_NOLINEAR_MODE, &mach32InfoRec.options) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach32InfoRec.name); } for (i = 0; ((mach32RamdacNames[i].token != -1) && (mach32RamdacNames[i].token != mach32RamdacSubType)); i++); if (mach32RamdacNames[i].token == -1) { ErrorF("%s %s: Ramdac is Unknown (%d)\n", (mach32InfoRec.ramdac ? XCONFIG_GIVEN : XCONFIG_PROBED), mach32InfoRec.name, mach32RamdacSubType); } else { ErrorF("%s %s: Ramdac is %s\n", (mach32InfoRec.ramdac ? XCONFIG_GIVEN : XCONFIG_PROBED), mach32InfoRec.name, mach32RamdacNames[i].name); } } /* The Type 2 RAMDACS can support 8 bits per RGB value, not just the * VGA-standard 6 bits; however, according to ATI, this is not an * official feature of the mach32. */ mach32DAC8Bit = OFLG_ISSET(OPTION_DAC_8_BIT, &mach32InfoRec.options) && (info->DAC_Type == DAC_TLC34075 || info->DAC_Type == DAC_ATT20C490) && mach32InfoRec.bitsPerPixel == 8; if (xf86Verbose) { if (mach32InfoRec.bitsPerPixel == 8) ErrorF("%s %s: Using %d bits per RGB value\n", (info->DAC_Type == DAC_TLC34075) ? XCONFIG_GIVEN : XCONFIG_PROBED, mach32InfoRec.name, mach32DAC8Bit ? 8 : 6); else if (mach32InfoRec.bitsPerPixel == 16) ErrorF("%s %s: Color weight: %1d%1d%1d\n", XCONFIG_GIVEN, mach32InfoRec.name, xf86weight.red, xf86weight.green, xf86weight.blue); } #ifdef XFreeXDGA mach32InfoRec.displayWidth = mach32DisplayWidth; mach32InfoRec.directMode = XF86DGADirectPresent; #endif return(TRUE); } /* * mach32PrintIdent -- * Print the indentification of the video card. */ void mach32PrintIdent() { ErrorF(" %s: accelerated server for ATI Mach32 graphics adaptors ", mach32InfoRec.name); ErrorF("(Patchlevel %s)\n", mach32InfoRec.patchLevel); } /* * mach32Initialize -- * 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 mach32Initialize (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; mach32InitGC(); mach32InitDisplay(scr_index); mach32InitAperture(scr_index); mach32CalcCRTCRegs(&mach32CRTCRegs, mach32InfoRec.modes); mach32SetCRTCRegs(&mach32CRTCRegs); mach32InitEnvironment(); /* Clear the display. * Need to set the color, origin, and size. Then draw. */ WaitQueue(6); if (xf86bpp == 8 && xf86FlipPixels) outw(FRGD_COLOR, 1); else outw(FRGD_COLOR, 0); outw(CUR_X, 0); outw(CUR_Y, 0); outw(MAJ_AXIS_PCNT, mach32MaxX); outw(MULTIFUNC_CNTL, MIN_AXIS_PCNT | mach32MaxY); outw(CMD, CMD_RECT | INC_Y | INC_X | DRAW | PLANAR | WRTDATA); xf86InitCache(mach32CacheMoveBlock); mach32FontCache8Init(); mach32ImageInit(); WaitIdleEmpty(); /* Make sure that all commands have finished */ /* * Take display resolution from the -dpi flag if specified */ if (monitorResolution) displayResolution = monitorResolution; if (!mach32ScreenInit(pScreen, mach32VideoMem, mach32VirtX, mach32VirtY, displayResolution, displayResolution, mach32DisplayWidth)) return(FALSE); savepScreen = pScreen; pScreen->CloseScreen = mach32CloseScreen; pScreen->SaveScreen = mach32SaveScreen; switch (mach32InfoRec.bitsPerPixel) { case 8: pScreen->InstallColormap = mach32InstallColormap; pScreen->UninstallColormap = mach32UninstallColormap; pScreen->ListInstalledColormaps = mach32ListInstalledColormaps; pScreen->StoreColors = mach32StoreColors; break; case 16: pScreen->InstallColormap = cfbInstallColormap; pScreen->UninstallColormap = cfbUninstallColormap; pScreen->ListInstalledColormaps = cfbListInstalledColormaps; pScreen->StoreColors = (void (*)())NoopDDA; } if (OFLG_ISSET(OPTION_SW_CURSOR, &mach32InfoRec.options)) { miDCInitialize (pScreen, &xf86PointerScreenFuncs); } else { pScreen->QueryBestSize = mach32QueryBestSize; xf86PointerScreenFuncs.WarpCursor = mach32WarpCursor; (void)mach32CursorInit(0, pScreen); } return (cfbCreateDefColormap(pScreen)); } /* * Assign a new serial number to the window. * Used to force GC validation on VT switch. */ /*ARGSUSED*/ static int mach32NewSerialNumber(pWin, data) WindowPtr pWin; pointer data; { pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER; return WT_WALKCHILDREN; } /* * mach32EnterLeaveVT -- * grab/ungrab the current VT completely. */ void mach32EnterLeaveVT(enter, screen_idx) Bool enter; int screen_idx; { PixmapPtr pspix; ScreenPtr pScreen = savepScreen; if (!xf86Exiting && !xf86Resetting) { /* cfbGetScreenPixmap(pScreen) */ switch (mach32InfoRec.bitsPerPixel) { case 8: pspix = (PixmapPtr)pScreen->devPrivate; break; case 16: { pspix = (PixmapPtr)pScreen->devPrivates[cfb16ScreenPrivateIndex].ptr; } break; } } if (pScreen && !xf86Exiting && !xf86Resetting) WalkTree(pScreen, mach32NewSerialNumber, 0); if (enter) { if (vgaBase) xf86MapDisplay(screen_idx, VGA_REGION); if (mach32VideoMem != vgaBase) xf86MapDisplay(screen_idx, LINEAR_REGION); if (!xf86Resetting) { ScrnInfoPtr pScr = XF86SCRNINFO(pScreen); mach32InitDisplay(screen_idx); mach32CalcCRTCRegs(&mach32CRTCRegs, mach32InfoRec.modes); /* 96/02/12 SM */ mach32SetCRTCRegs(&mach32CRTCRegs); mach32InitEnvironment(); WaitQueue(6); outw(FRGD_COLOR, 1); outw(CUR_X, 0); outw(CUR_Y, 0); outw(MAJ_AXIS_PCNT, mach32MaxX); outw(MULTIFUNC_CNTL, MIN_AXIS_PCNT | mach32MaxY); outw(CMD, CMD_RECT | INC_Y | INC_X | DRAW | PLANAR | WRTDATA); mach32FontCache8Init(); mach32RestoreCursor(pScreen); mach32AdjustFrame(pScr->frameX0, pScr->frameY0); WaitIdleEmpty(); /* Make sure that all commands have finished */ if (LUTissaved) { mach32RestoreLUT(mach32savedLUT); LUTissaved = FALSE; mach32RestoreColor0(pScreen); } if (pspix->devPrivate.ptr != mach32VideoMem && ppix) { pspix->devPrivate.ptr = mach32VideoMem; (mach32ImageWriteFunc)(0, 0, pScreen->width, pScreen->height, ppix->devPrivate.ptr, PixmapBytePad(mach32DisplayWidth, pScreen->rootDepth), 0, 0, MIX_SRC, ~0); } if (pScreen) { pScreen->CopyWindow = mach32CopyWindow; pScreen->GetSpans = mach32GetSpans; pScreen->PaintWindowBackground = mach32PaintWindow; pScreen->PaintWindowBorder = mach32PaintWindow; } } if (ppix) { (pScreen->DestroyPixmap)(ppix); ppix = NULL; } } else { if (vgaBase) xf86MapDisplay(screen_idx, VGA_REGION); if (mach32VideoMem != vgaBase) xf86MapDisplay(screen_idx, LINEAR_REGION); if (!xf86Exiting) { ppix = (pScreen->CreatePixmap)(pScreen, mach32DisplayWidth, pScreen->height, pScreen->rootDepth); if (ppix) { (mach32ImageReadFunc)(0, 0, pScreen->width, pScreen->height, ppix->devPrivate.ptr, PixmapBytePad(mach32DisplayWidth, pScreen->rootDepth), 0, 0, ~0); pspix->devPrivate.ptr = ppix->devPrivate.ptr; } switch (mach32InfoRec.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; } if (!mach32Use4MbAperture) { pScreen->PaintWindowBackground = miPaintWindow; pScreen->PaintWindowBorder = miPaintWindow; } } mach32CursorOff(); mach32SaveLUT(mach32savedLUT); LUTissaved = TRUE; if (!xf86Resetting) { #ifdef XFreeXDGA if (!(mach32InfoRec.directMode & XF86DGADirectGraphics)) #endif mach32CleanUp(); } if (vgaBase) xf86UnMapDisplay(screen_idx, VGA_REGION); if (mach32VideoMem != vgaBase) xf86UnMapDisplay(screen_idx, LINEAR_REGION); } } /* * mach32CloseScreen -- * called to ensure video is enabled when server exits. */ /*ARGSUSED*/ Bool mach32CloseScreen(screen_idx, pScreen) int screen_idx; ScreenPtr pScreen; { extern void mach32ClearSavedCursor(); /* * 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) mach32EnterLeaveVT(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; } mach32ClearSavedCursor(screen_idx); if (mach32InfoRec.bitsPerPixel == 8) cfbCloseScreen(screen_idx, savepScreen); else cfb16CloseScreen(screen_idx, savepScreen); savepScreen = NULL; return(TRUE); } /* * mach32SaveScreen -- * blank the screen. */ Bool mach32SaveScreen (pScreen, on) ScreenPtr pScreen; Bool on; { int ext_ge_config; if (on) SetTimeSinceLastInputEvent(); if (xf86VTSema) { /* * Make sure that register 0-3 are addressed */ ext_ge_config = inw(R_EXT_GE_CONFIG) & ~0x3000; outw(EXT_GE_CONFIG, ext_ge_config); /* Quick and dirty hack: * To save the screen at 16 bpp, disable the CRT controller. CEG */ if (on) { if (mach32InfoRec.bitsPerPixel == 8) { mach32RestoreColor0(pScreen); outb(DAC_MASK, 0xff); } else { mach32CalcCRTCRegs(&mach32CRTCRegs, mach32InfoRec.modes); /* 96/02/12 SM */ mach32SetCRTCRegs(&mach32CRTCRegs); } } else { if (mach32InfoRec.bitsPerPixel == 8) { WaitQueue(5); outb(DAC_W_INDEX, 0); outb(DAC_DATA, 0); outb(DAC_DATA, 0); outb(DAC_DATA, 0); outb(DAC_MASK, 0x00); } else { WaitQueue(1); outb(DISP_CNTL, DISPEN_DISAB); } } } return(TRUE); } /* * mach32AdjustFrame -- * Modify the CRT_OFFSET for panning the display. */ void mach32AdjustFrame(x, y) int x, y; { /* cursor offset in units of bytes/4 */ int byte_offset = ((x + y * mach32DisplayWidth) * (mach32InfoRec.bitsPerPixel / 8)) >> 2; mach32CursorOff(); WaitQueue(2); outw(CRT_OFFSET_LO, byte_offset & 0xffff); outw(CRT_OFFSET_HI, (byte_offset >> 16) & 0xf); mach32RepositionCursor(savepScreen); #ifdef XFreeXDGA if (mach32InfoRec.directMode & XF86DGADirectGraphics) { /* Wait until vertical retrace is in progress. */ while (inb(vgaIOBase + 0xA) & 0x08); while (!(inb(vgaIOBase + 0xA) & 0x08)); } #endif } /* * mach32SwitchMode -- * Reinitialize the CRTC registers for the new mode. */ Bool mach32SwitchMode(mode) DisplayModePtr mode; { mach32CalcCRTCRegs(&mach32CRTCRegs, mode); mach32SetCRTCRegs(&mach32CRTCRegs); return(TRUE); } /* * mach32ClockSelect */ Bool mach32ClockSelect(no) int no; { switch(no) { case CLK_REG_SAVE: break; case CLK_REG_RESTORE: break; default: if (mach32clkprobedif4fix) outw(CLOCK_SEL, (no << 2) | 0xac1); else outw(CLOCK_SEL, (no << 2) | 0xa01); } return(TRUE); } /* * mach32ValidMode -- * */ static int mach32ValidMode(pMode, verbose, flag) DisplayModePtr pMode; Bool verbose; { return MODE_OK; }