/* * Copyright 1999 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org * * 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 Marc Aurele La France not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. Marc Aurele La France makes no representations * about the suitability of this software for any purpose. It is provided * "as-is" without express or implied warranty. * * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO * EVENT SHALL MARC AURELE LA FRANCE 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "ati.h" #include "atiadapter.h" #include "atiadjust.h" #include "atiaudio.h" #include "atibus.h" #include "atichip.h" #include "aticonfig.h" #include "aticursor.h" #include "atidac.h" #include "atidsp.h" #include "atii2c.h" #include "atiident.h" #include "atiload.h" #include "atilock.h" #include "atimach64.h" #include "atimach64accel.h" #include "atimach64io.h" #include "atimode.h" #include "atipreinit.h" #include "atiprint.h" #include "atividmem.h" #include "atiwonderio.h" #include "atixv.h" #include "vbe.h" #include "xf86RAC.h" #ifndef AVOID_CPIO typedef CARD16 Colour; /* The correct spelling should be OK :-) */ /* * Bit patterns which are extremely unlikely to show up when reading from * nonexistant memory (which normally shows up as either all bits set or all * bits clear). */ static const Colour Test_Pixel[] = {0x5AA5U, 0x55AAU, 0xA55AU, 0xCA53U}; static const struct { int videoRamSize; int Miscellaneous_Options_Setting; struct { short int x, y; } Coordinates[NumberOf(Test_Pixel) + 1]; } Test_Case[] = { /* * Given the engine settings used, only a 4M card will have enough memory * to back up the 1025th line of the display. Since the pixel coordinates * are zero-based, line 1024 will be the first one which is only backed on * 4M cards. * * : * In case memory is being wrapped, (0,0) and (0,1024) to make sure they * can each hold a unique value. */ {4096, MEM_SIZE_4M, {{0,0}, {0,1024}, {-1,-1}}}, /* * This card has 2M or less. On a 1M card, the first 2M of the card's * memory will have even doublewords backed by physical memory and odd * doublewords unbacked. * * Pixels 0 and 1 of a row will be in the zeroth doubleword, while pixels 2 * and 3 will be in the first. Check both pixels 2 and 3 in case this is a * pseudo-1M card (one chip pulled to turn a 2M card into a 1M card). * * : * I don't have a 1M card, so I'm taking a stab in the dark. Maybe memory * wraps every 512 lines, or maybe odd doublewords are aliases of their * even doubleword counterparts. I try everything here. */ {2048, MEM_SIZE_2M, {{0,0}, {0,512}, {2,0}, {3,0}, {-1,-1}}}, /* * This is a either a 1M card or a 512k card. Test pixel 1, since it is an * odd word in an even doubleword. * * : * This is the same idea as the test above. */ {1024, MEM_SIZE_1M, {{0,0}, {0,256}, {1,0}, {-1,-1}}}, /* * Assume it is a 512k card by default, since that is the minimum * configuration. */ {512, MEM_SIZE_512K, {{-1,-1}}} }; /* * ATIMach32ReadPixel -- * * Return the colour of the specified screen location. Called from * ATIMach32videoRam function below. */ static Colour ATIMach32ReadPixel ( const short int X, const short int Y ) { Colour Pixel_Colour; /* Wait for idle engine */ ProbeWaitIdleEmpty(); /* Set up engine for pixel read */ ATIWaitQueue(7); outw(RD_MASK, (CARD16)(~0)); outw(DP_CONFIG, FG_COLOR_SRC_BLIT | DATA_WIDTH | DRAW | DATA_ORDER); outw(CUR_X, X); outw(CUR_Y, Y); outw(DEST_X_START, X); outw(DEST_X_END, X + 1); outw(DEST_Y_END, Y + 1); /* Wait for data to become ready */ ATIWaitQueue(16); WaitDataReady(); /* Read pixel colour */ Pixel_Colour = inw(PIX_TRANS); ProbeWaitIdleEmpty(); return Pixel_Colour; } /* * ATIMach32WritePixel -- * * Set the colour of the specified screen location. Called from * ATIMach32videoRam function below. */ static void ATIMach32WritePixel ( const short int X, const short int Y, const Colour Pixel_Colour ) { /* Set up engine for pixel write */ ATIWaitQueue(9); outw(WRT_MASK, (CARD16)(~0)); outw(DP_CONFIG, FG_COLOR_SRC_FG | DRAW | READ_WRITE); outw(ALU_FG_FN, MIX_FN_PAINT); outw(FRGD_COLOR, Pixel_Colour); outw(CUR_X, X); outw(CUR_Y, Y); outw(DEST_X_START, X); outw(DEST_X_END, X + 1); outw(DEST_Y_END, Y + 1); } /* * ATIMach32videoRam -- * * Determine the amount of video memory installed on an 68800-6 based adapter. * This is done because these chips exhibit a bug that causes their * MISC_OPTIONS register to report 1M rather than the true amount of memory. * * This function is adapted from a similar function in mach32mem.c written by * Robert Wolff, David Dawes and Mark Weaver. */ static int ATIMach32videoRam ( void ) { CARD16 clock_sel, mem_bndry, misc_options, ext_ge_config; Colour saved_Pixel[NumberOf(Test_Pixel)]; unsigned int Case_Number, Pixel_Number; Bool AllPixelsOK; /* Save register values to be modified */ clock_sel = inw(CLOCK_SEL); mem_bndry = inw(MEM_BNDRY); misc_options = inw(MISC_OPTIONS) & ~MEM_SIZE_ALIAS; ext_ge_config = inw(R_EXT_GE_CONFIG); /* Wait for enough FIFO entries */ ATIWaitQueue(7); /* Enable accelerator */ outw(CLOCK_SEL, clock_sel | DISABPASSTHRU); /* Make accelerator and VGA share video memory */ outw(MEM_BNDRY, mem_bndry & ~(MEM_PAGE_BNDRY | MEM_BNDRY_ENA)); /* Prevent video memory wrap */ outw(MISC_OPTIONS, misc_options | MEM_SIZE_4M); /* * Set up the drawing engine for a pitch of 1024 at 16 bits per pixel. No * need to mess with the CRT because the results of this test are not * intended to be seen. */ outw(EXT_GE_CONFIG, PIXEL_WIDTH_16 | ORDER_16BPP_565 | MONITOR_8514 | ALIAS_ENA); outw(GE_PITCH, 1024 >> 3); outw(GE_OFFSET_HI, 0); outw(GE_OFFSET_LO, 0); for (Case_Number = 0; Case_Number < (NumberOf(Test_Case) - 1); Case_Number++) { /* Reduce redundancy as per Mark_Weaver@brown.edu */ # define TestPixel Test_Case[Case_Number].Coordinates[Pixel_Number] # define ForEachTestPixel \ for (Pixel_Number = 0; TestPixel.x >= 0; Pixel_Number++) /* Save pixel colours that will be clobbered */ ForEachTestPixel saved_Pixel[Pixel_Number] = ATIMach32ReadPixel(TestPixel.x, TestPixel.y); /* Write test patterns */ ForEachTestPixel ATIMach32WritePixel(TestPixel.x, TestPixel.y, Test_Pixel[Pixel_Number]); /* Test for lost pixels */ AllPixelsOK = TRUE; ForEachTestPixel { if (ATIMach32ReadPixel(TestPixel.x, TestPixel.y) != Test_Pixel[Pixel_Number]) { AllPixelsOK = FALSE; break; } } /* Restore clobbered pixels */ ForEachTestPixel ATIMach32WritePixel(TestPixel.x, TestPixel.y, saved_Pixel[Pixel_Number]); /* End test on success */ if (AllPixelsOK) break; /* Completeness */ # undef ForEachTestPixel # undef TestPixel } /* Restore what was changed and correct MISC_OPTIONS register */ ATIWaitQueue(4); outw(EXT_GE_CONFIG, ext_ge_config); misc_options |= Test_Case[Case_Number].Miscellaneous_Options_Setting; outw(MISC_OPTIONS, misc_options); outw(MEM_BNDRY, mem_bndry); outw(CLOCK_SEL, clock_sel); /* Wait for activity to die down */ ProbeWaitIdleEmpty(); /* Tell ATIPreInit the REAL story */ return Test_Case[Case_Number].videoRamSize; } #endif /* AVOID_CPIO */ /* * ATIReportMemory -- * * This function reports on the amount and type of video memory found. */ static void ATIReportMemory ( ScrnInfoPtr pScreenInfo, ATIPtr pATI, const char *MemoryTypeName ) { char Buffer[128], *Message; Message = Buffer + snprintf(Buffer, SizeOf(Buffer), "%d kB of %s detected", pATI->VideoRAM, MemoryTypeName); #ifndef AVOID_CPIO if (pATI->depth == 1) { /* 1bpp only uses one plane of four */ pScreenInfo->videoRam /= 4; Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, " (using %d kB)", pScreenInfo->videoRam); } else #endif /* AVOID_CPIO */ if (pATI->VideoRAM > pScreenInfo->videoRam) { Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, " (using %d kB)", pScreenInfo->videoRam); } xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s.\n", Buffer); } static const int videoRamSizes[] = {0, 256, 512, 1024, 2*1024, 4*1024, 6*1024, 8*1024, 12*1024, 16*1024, 0}; static const rgb defaultWeight = {0, 0, 0}; static const Gamma defaultGamma = {0.0, 0.0, 0.0}; /* * ATIMach64Map -- * * This function attempts to mmap() a Mach64's MMIO aperture. */ static void ATIMach64Map ( int iScreen, ATIPtr pATI ) { (void)ATIMapApertures(iScreen, pATI); if (!pATI->pBlock[0] || (pATI->config_chip_id != inr(CONFIG_CHIP_ID))) ATIUnmapApertures(iScreen, pATI); } /* * ATIPrintNoiseIfRequested -- * * This function formats debugging information on the server's stderr when * requested by the user through the server's verbosity setting. */ static void ATIPrintNoiseIfRequested ( ATIPtr pATI, CARD8 *BIOS, unsigned int BIOSSize ) { if (xf86GetVerbosity() <= 3) return; if (BIOSSize > 0) ATIPrintBIOS(BIOS, BIOSSize); xf86ErrorFVerb(4, "\n On server entry:\n"); ATIPrintRegisters(pATI); } /* * ATIPreInit -- * * This function is only called once per screen at the start of the first * server generation. */ _X_EXPORT Bool ATIPreInit ( ScrnInfoPtr pScreenInfo, int flags ) { # define BIOS_SIZE 0x00010000U /* 64kB */ CARD8 BIOS[BIOS_SIZE]; # define BIOSByte(_n) ((CARD8)(BIOS[_n])) # define BIOSWord(_n) ((CARD16)(BIOS[_n] | \ (BIOS[(_n) + 1] << 8))) # define BIOSLong(_n) ((CARD32)(BIOS[_n] | \ (BIOS[(_n) + 1] << 8) | \ (BIOS[(_n) + 2] << 16) | \ (BIOS[(_n) + 3] << 24))) unsigned int BIOSSize = 0; unsigned int ROMTable = 0, ClockTable = 0, FrequencyTable = 0; unsigned int LCDTable = 0, LCDPanelInfo = 0, VideoTable = 0; unsigned int HardwareTable = 0; char Buffer[128], *Message; ATIPtr pATI; GDevPtr pGDev; EntityInfoPtr pEntity; resPtr pResources; pciVideoPtr pVideo; DisplayModePtr pMode; unsigned long Block0Base; CARD32 IOValue; int i, j, AcceleratorVideoRAM = 0, ServerVideoRAM; int Numerator, Denominator; int MinX, MinY; ClockRange ATIClockRange = {NULL, 0, 80000, 0, TRUE, TRUE, 1, 1, 0}; int DefaultmaxClock = 0; int minPitch, maxPitch = 0xFFU, maxHeight = 0; int ApertureSize = 0x00010000U; int ModeType = M_T_BUILTIN; LookupModeFlags Strategy = LOOKUP_CLOSEST_CLOCK; int DefaultDepth; # define pATIHW (&pATI->OldHW) #ifndef AVOID_CPIO xf86Int10InfoPtr pInt10Info = NULL; vbeInfoPtr pVBE; pointer pInt10Module, pDDCModule = NULL, pVBEModule = NULL; int VGAVideoRAM = 0; resRange Resources[2] = {{0, 0, 0}, _END}; #endif /* AVOID_CPIO */ if (pScreenInfo->numEntities != 1) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Logic error: Number of attached entities not 1.\n"); return FALSE; } pATI = ATIPTR(pScreenInfo); if (pATI->iEntity != pScreenInfo->entityList[0]) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Logic error: Entity mismatch.\n"); return FALSE; } /* Register resources */ pEntity = xf86GetEntityInfo(pATI->iEntity); pGDev = pEntity->device; pResources = pEntity->resources; xfree(pEntity); if (!pResources) pResources = xf86RegisterResources(pATI->iEntity, NULL, pATI->SharedAccelerator ? ResShared : ResExclusive); if (pResources) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Unable to register the following bus resources:\n"); xf86PrintResList(0, pResources); xf86FreeResList(pResources); return FALSE; } ConfiguredMonitor = NULL; (void)memset(BIOS, 0, SizeOf(BIOS)); if (!(flags & PROBE_DETECT)) { xf86DrvMsg(pScreenInfo->scrnIndex, pATI->Chipset ? X_CONFIG : X_DEFAULT, "Chipset: \"%s\".\n", ATIChipsetNames[pATI->Chipset]); /* Promote chipset specification */ switch (pATI->Chipset) { #ifndef AVOID_CPIO case ATI_CHIPSET_IBMVGA: if (pATI->Adapter == ATI_ADAPTER_VGA) break; /* XXX */ /* Fall through */ case ATI_CHIPSET_VGAWONDER: pATI->Chipset = ATI_CHIPSET_ATIVGA; break; case ATI_CHIPSET_IBM8514: if (pATI->Adapter == ATI_ADAPTER_8514A) break; /* XXX */ /* Fall through */ case ATI_CHIPSET_MACH8: case ATI_CHIPSET_MACH32: #endif /* AVOID_CPIO */ case ATI_CHIPSET_MACH64: case ATI_CHIPSET_RAGE128: case ATI_CHIPSET_RADEON: pATI->Chipset = ATI_CHIPSET_ATI; break; default: break; } /* Set monitor */ pScreenInfo->monitor = pScreenInfo->confScreen->monitor; /* Set depth, bpp, etc. */ if ((pATI->Chipset != ATI_CHIPSET_ATI) || (pATI->Chip < ATI_CHIP_264CT)) { i = NoDepth24Support; /* No support for >8bpp either */ DefaultDepth = 8; } else { i = Support24bppFb | Support32bppFb; DefaultDepth = 0; } if (!xf86SetDepthBpp(pScreenInfo, DefaultDepth, 0, 0, i)) return FALSE; for (j = 0; ; j++) { static const CARD8 AllowedDepthBpp[][2] = { #ifndef AVOID_CPIO { 1, 1}, { 4, 4}, { 4, 8}, #endif /* AVOID_CPIO */ { 8, 8}, {15, 16}, {16, 16}, {24, 24}, {24, 32} }; if (j < NumberOf(AllowedDepthBpp)) { if (pScreenInfo->depth > AllowedDepthBpp[j][0]) continue; if (pScreenInfo->depth == AllowedDepthBpp[j][0]) { if (pScreenInfo->bitsPerPixel > AllowedDepthBpp[j][1]) continue; if (pScreenInfo->bitsPerPixel == AllowedDepthBpp[j][1]) break; } } xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Driver does not support depth %d at fbbpp %d.\n", pScreenInfo->depth, pScreenInfo->bitsPerPixel); return FALSE; } xf86PrintDepthBpp(pScreenInfo); if ((i == NoDepth24Support) && (pScreenInfo->depth > 8)) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Depth %d is not supported through this adapter.\n", pScreenInfo->depth); return FALSE; } /* Pick up XF86Config options */ ATIProcessOptions(pScreenInfo, pATI); } #ifdef AVOID_CPIO else /* if (flags & PROBE_DETECT) */ { return TRUE; } #else /* AVOID_CPIO */ #ifdef TV_OUT pATI->pVBE = NULL; pATI->pInt10 = NULL; #endif /* TV_OUT */ /* * If there is an ix86-style BIOS, ensure its initialisation entry point * has been executed, and retrieve DDC and VBE information from it. */ if (!(pInt10Module = ATILoadModule(pScreenInfo, "int10", ATIint10Symbols))) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Unable to load int10 module.\n"); } else if (!(pInt10Info = xf86InitInt10(pATI->iEntity))) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Unable to initialise int10 interface.\n"); } else { if (!(pDDCModule = ATILoadModule(pScreenInfo, "ddc", ATIddcSymbols))) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Unable to load ddc module.\n"); } else if (!(pVBEModule = ATILoadModule(pScreenInfo, "vbe", ATIvbeSymbols))) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Unable to load vbe module.\n"); } else { if ((pVBE = VBEInit(pInt10Info, pATI->iEntity))) { ConfiguredMonitor = vbeDoEDID(pVBE, pDDCModule); #ifdef TV_OUT pATI->pInt10 = pInt10Info; pATI->pVBE = pVBE; pVBE = NULL; #else vbeFree(pVBE); #endif /* TV_OUT */ } #ifndef TV_OUT xf86UnloadSubModule(pVBEModule); #endif /* TV_OUT */ } if (!(flags & PROBE_DETECT)) { /* Validate, then make a private copy of, the initialised BIOS */ CARD8 *pBIOS = xf86int10Addr(pInt10Info, pInt10Info->BIOSseg << 4); if ((pBIOS[0] != 0x55U) || (pBIOS[1] != 0xAAU) || !pBIOS[2]) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Unable to correctly retrieve adapter BIOS.\n"); } else { BIOSSize = pBIOS[2] << 9; if (BIOSSize > BIOS_SIZE) BIOSSize = BIOS_SIZE; (void)memcpy(BIOS, pBIOS, BIOSSize); } } } #ifndef TV_OUT /* De-activate int10 */ xf86FreeInt10(pInt10Info); xf86UnloadSubModule(pInt10Module); #else pInt10Info = NULL; #endif /* TV_OUT */ if (flags & PROBE_DETECT) { xf86UnloadSubModule(pDDCModule); return TRUE; } if (ConfiguredMonitor) { xf86PrintEDID(ConfiguredMonitor); xf86SetDDCproperties(pScreenInfo, ConfiguredMonitor); } /* DDC module is no longer needed at this point */ xf86UnloadSubModule(pDDCModule); #endif /* AVOID_CPIO */ pATI->Block0Base = 0; /* Might no longer be valid */ if ((pVideo = pATI->PCIInfo)) { if (pATI->CPIODecoding == BLOCK_IO) pATI->CPIOBase = pVideo->ioBase[1]; /* Set MMIO address from PCI configuration space, if available */ if ((pATI->Block0Base = pVideo->memBase[2])) { if (pATI->Block0Base >= (CARD32)(-1 << pVideo->size[2])) pATI->Block0Base = 0; else pATI->Block0Base += 0x0400U; } } #ifdef AVOID_CPIO pScreenInfo->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; #else /* AVOID_CPIO */ pScreenInfo->racIoFlags = RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR; pScreenInfo->racMemFlags = RAC_FB | RAC_CURSOR; #endif /* AVOID_CPIO */ /* Deal with ChipID & ChipRev overrides */ if (pGDev->chipID >= 0) { ATIChipType Chip; Chip = ATIChipID(pGDev->chipID, (pGDev->chipRev < 0) ? pATI->ChipRev : pGDev->chipRev); if (Chip != pATI->Chip) { pATI->Chip = Chip; pATI->ChipType = pGDev->chipID; if (pGDev->chipRev < 0) { xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, "Driver messages reflect ChipID 0x%04X override.\n", pATI->ChipType); } else { pATI->ChipRev = pGDev->chipRev; pATI->ChipVersion = GetBits(pATI->ChipRev, GetBits(CFG_CHIP_VERSION, CFG_CHIP_REV)); pATI->ChipFoundry = GetBits(pATI->ChipRev, GetBits(CFG_CHIP_FOUNDRY, CFG_CHIP_REV)); pATI->ChipRevision = GetBits(pATI->ChipRev, GetBits(CFG_CHIP_REVISION, CFG_CHIP_REV)); xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, "Driver messages reflect ChipID 0x%04X and ChipRev 0x%02X" " overrides.\n", pATI->ChipType, pATI->ChipRev); } } } /* Finish private area initialisation */ pATI->DAC = ATI_DAC_GENERIC; #ifndef AVOID_CPIO pATI->NewHW.SetBank = ATIx8800SetBank; pATI->BankInfo.SetSourceBank = ATIx8800SetRead; pATI->BankInfo.SetDestinationBank = ATIx8800SetWrite; pATI->BankInfo.SetSourceAndDestinationBanks = ATIx8800SetReadWrite; pATI->BankInfo.BankSize = 0x00010000U; /* 64kB */ #endif /* AVOID_CPIO */ pATI->LCDPanelID = -1; pATI->nFIFOEntries = 16; /* For now */ pATI->Audio = ATI_AUDIO_NONE; /* Finish probing the adapter */ switch (pATI->Adapter) { #ifndef AVOID_CPIO case ATI_ADAPTER_NONE: case ATI_ADAPTER_EGA: case ATI_ADAPTER_EGA_PLUS: case ATI_ADAPTER_VGA: case ATI_ADAPTER_BASIC: pATI->NewHW.SetBank = (ATIBankProcPtr)NoopDDA; pATI->BankInfo.SetSourceBank = pATI->BankInfo.SetDestinationBank = pATI->BankInfo.SetSourceAndDestinationBanks = (miBankProcPtr)NoopDDA; break; case ATI_ADAPTER_V3: pATI->NewHW.SetBank = ATIV3SetBank; pATI->BankInfo.SetSourceBank = ATIV3SetRead; pATI->BankInfo.SetDestinationBank = ATIV3SetWrite; pATI->BankInfo.SetSourceAndDestinationBanks = ATIV3SetReadWrite; break; case ATI_ADAPTER_V4: case ATI_ADAPTER_V5: pATI->NewHW.SetBank = ATIV4V5SetBank; pATI->BankInfo.SetSourceBank = ATIV4V5SetRead; pATI->BankInfo.SetDestinationBank = ATIV4V5SetWrite; pATI->BankInfo.SetSourceAndDestinationBanks = ATIV4V5SetReadWrite; break; case ATI_ADAPTER_XL: pATI->DAC = ATI_DAC_SC11483; break; case ATI_ADAPTER_8514A: pATI->VideoRAM = videoRamSizes[GetBits(inw(SUBSYS_STAT), _8PLANE) + 2]; break; case ATI_ADAPTER_MACH8: pATI->VideoRAM = videoRamSizes[GetBits(inw(CONFIG_STATUS_1), MEM_INSTALLED) + 2]; break; case ATI_ADAPTER_MACH32: IOValue = inw(CONFIG_STATUS_1); pATI->DAC = ATI_DAC(GetBits(IOValue, DACTYPE), 0); pATI->MemoryType = GetBits(IOValue, MEM_TYPE); IOValue = inw(MISC_OPTIONS); pATI->VideoRAM = videoRamSizes[GetBits(IOValue, MEM_SIZE_ALIAS) + 2]; /* * The 68800-6 doesn't necessarily report the correct video memory * size. */ if ((pATI->Chip == ATI_CHIP_68800_6) && (pATI->VideoRAM == 1024)) pATI->VideoRAM = ATIMach32videoRam(); break; #endif /* AVOID_CPIO */ case ATI_ADAPTER_MACH64: do { /* * Find and mmap() MMIO area. Allow only auxiliary aperture if * it exists. */ if (!(Block0Base = pATI->Block0Base)) { if (pVideo) { /* Check tail end of linear (8MB or 4MB) aperture */ if ((pATI->Block0Base = pVideo->memBase[0])) { pATI->Block0Base += 0x007FFC00U; ATIMach64Map(pScreenInfo->scrnIndex, pATI); if (pATI->pBlock[0]) break; pATI->Block0Base -= 0x00400000U; ATIMach64Map(pScreenInfo->scrnIndex, pATI); if (pATI->pBlock[0]) break; } } /* Check VGA MMIO aperture */ pATI->Block0Base = 0x000BFC00U; } ATIMach64Map(pScreenInfo->scrnIndex, pATI); } while (0); pATI->Block0Base = Block0Base; #ifdef AVOID_CPIO if (!pATI->pBlock[0]) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Unable to mmap() adapter registers.\n"); return FALSE; } #endif /* AVOID_CPIO */ pATIHW->crtc_gen_cntl = inr(CRTC_GEN_CNTL); if (!(pATIHW->crtc_gen_cntl & CRTC_EN) && (pATI->Chip >= ATI_CHIP_264CT)) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Adapter has not been initialised.\n"); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } #ifdef AVOID_CPIO if (!(pATIHW->crtc_gen_cntl & CRTC_EXT_DISP_EN)) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Adapters found to be in VGA mode on server entry are not" " supported by the MMIO-only version of this driver.\n"); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } #endif /* AVOID_CPIO */ pATIHW->mem_cntl = inr(MEM_CNTL); if (pATI->Chip < ATI_CHIP_264VTB) { pATI->VideoRAM = videoRamSizes[GetBits(pATIHW->mem_cntl, CTL_MEM_SIZE) + 2]; } else { pATI->nFIFOEntries = /* Don't care */ (unsigned int)(-1) >> 1; IOValue = GetBits(pATIHW->mem_cntl, CTL_MEM_SIZEB); if (IOValue < 8) pATI->VideoRAM = (IOValue + 1) * 512; else if (IOValue < 12) pATI->VideoRAM = (IOValue - 3) * 1024; else pATI->VideoRAM = (IOValue - 7) * 2048; } pATI->DAC = GetBits(inr(DAC_CNTL), DAC_TYPE); IOValue = inr(CONFIG_STATUS64_0); if (pATI->Chip >= ATI_CHIP_264CT) { pATI->MemoryType = GetBits(IOValue, CFG_MEM_TYPE_T); /* Get LCD panel id */ if (pATI->Chip == ATI_CHIP_264LT) { pATI->LCDPanelID = GetBits(IOValue, CFG_PANEL_ID); pATIHW->horz_stretching = inr(HORZ_STRETCHING); pATIHW->vert_stretching = inr(VERT_STRETCHING); pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL); } else if ((pATI->Chip == ATI_CHIP_264LTPRO) || (pATI->Chip == ATI_CHIP_264XL) || (pATI->Chip == ATI_CHIP_MOBILITY)) { pATI->LCDPanelID = GetBits(IOValue, CFG_PANEL_ID); pATIHW->lcd_index = inr(LCD_INDEX); pATIHW->horz_stretching = ATIMach64GetLCDReg(LCD_HORZ_STRETCHING); pATI->LCDHorizontal = GetBits(pATIHW->horz_stretching, HORZ_PANEL_SIZE); if (pATI->LCDHorizontal) { if (pATI->LCDHorizontal == MaxBits(HORZ_PANEL_SIZE)) pATI->LCDHorizontal = 0; else pATI->LCDHorizontal = (pATI->LCDHorizontal + 1) << 3; } pATIHW->ext_vert_stretch = ATIMach64GetLCDReg(LCD_EXT_VERT_STRETCH); pATI->LCDVertical = GetBits(pATIHW->ext_vert_stretch, VERT_PANEL_SIZE); if (pATI->LCDVertical) { if (pATI->LCDVertical == MaxBits(VERT_PANEL_SIZE)) pATI->LCDVertical = 0; else pATI->LCDVertical++; } pATIHW->vert_stretching = ATIMach64GetLCDReg(LCD_VERT_STRETCHING); pATIHW->lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); outr(LCD_INDEX, pATIHW->lcd_index); } /* * Don't bother with panel support if it hasn't been previously * enabled. */ if ((pATI->LCDPanelID >= 0) && !(pATIHW->horz_stretching & HORZ_STRETCH_EN) && !(pATIHW->vert_stretching & VERT_STRETCH_EN) && !(pATIHW->lcd_gen_ctrl & LCD_ON)) { /* * At this point, if an XL or Mobility BIOS hasn't set * panel dimensions, then there is no panel. Otherwise, * keep any panel disabled to allow for modes greater than * the panel's dimensions. */ if ((pATI->Chip >= ATI_CHIP_264XL) && (!pATI->LCDHorizontal || !pATI->LCDVertical)) pATI->LCDPanelID = -1; else pATI->OptionPanelDisplay = FALSE; } } else { pATI->MemoryType = GetBits(IOValue, CFG_MEM_TYPE); /* Factor in what the BIOS says the DAC is */ pATI->DAC = ATI_DAC(pATI->DAC, GetBits(inr(SCRATCH_REG1), BIOS_INIT_DAC_SUBTYPE)); } /* * RAMDAC types 0 & 1 for Mach64's are different than those for * Mach32's. */ if (pATI->DAC < ATI_DAC_ATI68875) pATI->DAC += ATI_DAC_INTERNAL; break; default: break; } /* * For Mach64 adapters, pick up, from the BIOS, the type of programmable * clock generator (if any), and various information about it. */ #ifndef AVOID_CPIO if (pATI->Chip >= ATI_CHIP_88800GXC) #endif /* AVOID_CPIO */ { CARD16 ClockDac; /* Set up non-zero defaults */ pATI->ClockDescriptor = ATIClockDescriptors[ATI_CLOCK_FIXED]; pATI->ClockNumberToProgramme = -1; ROMTable = BIOSWord(0x48U); if ((ROMTable < 0x0002U) || (BIOSWord(ROMTable - 0x02U) < 0x0012U) || ((ROMTable + BIOSWord(ROMTable - 0x02U)) > BIOSSize)) ROMTable = 0; if (ROMTable > 0) { ClockTable = BIOSWord(ROMTable + 0x10U); if ((ClockTable + 0x20U) > BIOSSize) ClockTable = 0; if (BIOSWord(ROMTable - 0x02U) >= 0x0048U) { VideoTable = BIOSWord(ROMTable + 0x46U); if ((VideoTable < 0x08U) || (BIOSByte(VideoTable - 0x01U) < 0x08U) || (BIOSByte(VideoTable - 0x02U) > 0x01U) || ((VideoTable + BIOSByte(VideoTable - 0x01U)) > BIOSSize)) VideoTable = 0; } if (BIOSWord(ROMTable - 0x02U) >= 0x004AU) { HardwareTable = BIOSWord(ROMTable + 0x48U); if (((HardwareTable + 0x08U) <= BIOSSize) && !memcmp(BIOS + HardwareTable, "$ATI", 4)) pATI->I2CType = BIOSByte(HardwareTable + 0x06U) & 0x0FU; else HardwareTable = 0; } } if (ClockTable > 0) { FrequencyTable = BIOSWord(ClockTable - 0x02U); if ((FrequencyTable > 0) && ((FrequencyTable + 0x20U) <= BIOSSize)) { for (i = 0; i < 16; i++) { pATI->BIOSClocks[i] = BIOSWord(FrequencyTable); FrequencyTable += 2; } } pATI->ProgrammableClock = BIOSByte(ClockTable); pATI->ClockNumberToProgramme = BIOSByte(ClockTable + 0x06U); switch (BIOSWord(ClockTable + 0x08U) / 10) { case 143: pATI->ReferenceNumerator = 157500; pATI->ReferenceDenominator = 11; break; case 286: pATI->ReferenceNumerator = 315000; pATI->ReferenceDenominator = 11; break; default: pATI->ReferenceNumerator = BIOSWord(ClockTable + 0x08U) * 10; pATI->ReferenceDenominator = 1; break; } } else { /* * Compensate for BIOS absence. Note that the reference * frequency has already been set by option processing. */ if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL) { pATI->ProgrammableClock = ATI_CLOCK_INTERNAL; } else switch (pATI->DAC) { case ATI_DAC_STG1703: pATI->ProgrammableClock = ATI_CLOCK_STG1703; break; case ATI_DAC_CH8398: pATI->ProgrammableClock = ATI_CLOCK_CH8398; break; case ATI_DAC_ATT20C408: pATI->ProgrammableClock = ATI_CLOCK_ATT20C408; break; case ATI_DAC_IBMRGB514: pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514; break; default: /* Provisional */ pATI->ProgrammableClock = ATI_CLOCK_ICS2595; break; } /* This should be safe for all generators except IBM's RGB514 */ pATI->ClockNumberToProgramme = 3; } if ((pATI->ProgrammableClock > ATI_CLOCK_FIXED) && (pATI->ProgrammableClock < ATI_CLOCK_MAX)) { /* * Graphics PRO TURBO 1600's are unusual in that an ICS2595 is used * to generate clocks for VGA modes, and an IBM RGB514 is used for * accelerator modes. */ if ((pATI->ProgrammableClock == ATI_CLOCK_ICS2595) && (pATI->DAC == ATI_DAC_IBMRGB514) && (pScreenInfo->depth >= 8) && (pATI->Chipset == ATI_CHIPSET_ATI)) pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514; pATI->ClockDescriptor = ATIClockDescriptors[pATI->ProgrammableClock]; } ClockDac = pATI->DAC; switch (pATI->ProgrammableClock) { case ATI_CLOCK_ICS2595: /* * Pick up reference divider (43 or 46) appropriate to the chip * revision level. */ if (ClockTable > 0) pATI->ClockDescriptor.MinM = pATI->ClockDescriptor.MaxM = BIOSWord(ClockTable + 0x0AU); else if (!xf86NameCmp(pGDev->clockchip, "ATI 18818-0")) pATI->ClockDescriptor.MinM = pATI->ClockDescriptor.MaxM = 43; else if (!xf86NameCmp(pGDev->clockchip, "ATI 18818-1")) pATI->ClockDescriptor.MinM = pATI->ClockDescriptor.MaxM = 46; else pATI->ProgrammableClock = ATI_CLOCK_UNKNOWN; break; case ATI_CLOCK_STG1703: /* This one's also a RAMDAC */ ClockDac = ATI_DAC_STG1703; break; case ATI_CLOCK_CH8398: /* This one's also a RAMDAC */ ClockDac = ATI_DAC_CH8398; break; case ATI_CLOCK_INTERNAL: /* * The reference divider has already been programmed by BIOS * initialisation. Because, there is only one reference * divider for all generated frequencies (including MCLK), it * cannot be changed without reprogramming all clocks every * time one of them needs a different reference divider. * * Besides, it's not a good idea to change the reference * divider. BIOS initialisation sets it to a value that * effectively prevents generating frequencies beyond the * graphics controller's tolerance. */ pATI->ClockDescriptor.MinM = pATI->ClockDescriptor.MaxM = ATIMach64GetPLLReg(PLL_REF_DIV); /* The DAC is also integrated */ if ((pATI->DAC & ~0x0FU) != ATI_DAC_INTERNAL) ClockDac = ATI_DAC_INTERNAL; break; case ATI_CLOCK_ATT20C408: /* This one's also a RAMDAC */ ClockDac = ATI_DAC_ATT20C408; break; case ATI_CLOCK_IBMRGB514: /* This one's also a RAMDAC */ ClockDac = ATI_DAC_IBMRGB514; pATI->ClockNumberToProgramme = 7; break; default: break; } /* * We now have up to two indications of what RAMDAC the adapter uses. * They should be the same. The following test and corresponding * action are under construction. */ if (pATI->DAC != ClockDac) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Mach64 RAMDAC probe discrepancy detected:\n" " DAC=0x%02X; ClockDac=0x%02X.\n", pATI->DAC, ClockDac); if (pATI->DAC == ATI_DAC_IBMRGB514) { pATI->ProgrammableClock = ATI_CLOCK_IBMRGB514; pATI->ClockDescriptor = ATIClockDescriptors[ATI_CLOCK_IBMRGB514]; pATI->ClockNumberToProgramme = 7; } else { pATI->DAC = ClockDac; /* For now */ } } /* * Pick up multimedia information, which will be at different * displacements depending on table revision. */ if (VideoTable > 0) { switch (BIOSByte(VideoTable - 0x02U)) { case 0x00U: pATI->Tuner = BIOSByte(VideoTable) & 0x1FU; /* * XXX The VideoTable[1] byte is known to have been * omitted in LTPro and Mobility BIOS'es. Any others? */ switch (pATI->Chip) { case ATI_CHIP_264LTPRO: case ATI_CHIP_MOBILITY: pATI->Decoder = BIOSByte(VideoTable + 0x01U) & 0x07U; pATI->Audio = BIOSByte(VideoTable + 0x02U) & 0x0FU; break; default: pATI->Decoder = BIOSByte(VideoTable + 0x02U) & 0x07U; pATI->Audio = BIOSByte(VideoTable + 0x03U) & 0x0FU; break; } break; case 0x01U: pATI->Tuner = BIOSByte(VideoTable) & 0x1FU; pATI->Audio = BIOSByte(VideoTable + 0x01U) & 0x0FU; pATI->Decoder = BIOSByte(VideoTable + 0x05U) & 0x0FU; break; default: break; } } /* Determine panel dimensions */ if (pATI->LCDPanelID >= 0) { LCDTable = BIOSWord(0x78U); if ((LCDTable + BIOSByte(LCDTable + 5)) > BIOSSize) LCDTable = 0; if (LCDTable > 0) { LCDPanelInfo = BIOSWord(LCDTable + 0x0AU); if (((LCDPanelInfo + 0x1DU) > BIOSSize) || ((BIOSByte(LCDPanelInfo) != pATI->LCDPanelID) && (pATI->LCDPanelID || (BIOSByte(LCDPanelInfo) > 0x1FU) || (pATI->Chip <= ATI_CHIP_264LTPRO)))) LCDPanelInfo = 0; } if (!LCDPanelInfo) { /* * Scan BIOS for panel info table. */ for (i = 0; i <= (int)(BIOSSize - 0x1DU); i++) { /* Look for panel ID ... */ if ((BIOSByte(i) != pATI->LCDPanelID) && (pATI->LCDPanelID || (BIOSByte(i) > 0x1FU) || (pATI->Chip <= ATI_CHIP_264LTPRO))) continue; /* ... followed by 24-byte panel model name ... */ for (j = 0; j < 24; j++) { if ((CARD8)(BIOSByte(i + j + 1) - 0x20U) > 0x5FU) { i += j; goto NextBIOSByte; } } /* ... verify panel width ... */ if (pATI->LCDHorizontal && (pATI->LCDHorizontal != BIOSWord(i + 0x19U))) continue; /* ... and verify panel height */ if (pATI->LCDVertical && (pATI->LCDVertical != BIOSWord(i + 0x1BU))) continue; if (LCDPanelInfo) { /* * More than one possibility, but don't care if all * tables describe panels of the same size. */ if ((BIOSByte(LCDPanelInfo + 0x19U) == BIOSByte(i + 0x19U)) && (BIOSByte(LCDPanelInfo + 0x1AU) == BIOSByte(i + 0x1AU)) && (BIOSByte(LCDPanelInfo + 0x1BU) == BIOSByte(i + 0x1BU)) && (BIOSByte(LCDPanelInfo + 0x1CU) == BIOSByte(i + 0x1CU))) continue; LCDPanelInfo = 0; break; } LCDPanelInfo = i; NextBIOSByte: ; } } if (LCDPanelInfo > 0) { pATI->LCDPanelID = BIOSByte(LCDPanelInfo); pATI->LCDHorizontal = BIOSWord(LCDPanelInfo + 0x19U); pATI->LCDVertical = BIOSWord(LCDPanelInfo + 0x1BU); } } xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, "BIOS Data: BIOSSize=0x%04X, ROMTable=0x%04X.\n", BIOSSize, ROMTable); xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, "BIOS Data: ClockTable=0x%04X, FrequencyTable=0x%04X.\n", ClockTable, FrequencyTable); xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, "BIOS Data: LCDTable=0x%04X, LCDPanelInfo=0x%04X.\n", LCDTable, LCDPanelInfo); xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, "BIOS Data: VideoTable=0x%04X, HardwareTable=0x%04X.\n", VideoTable, HardwareTable); xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_INFO, 3, "BIOS Data: I2CType=0x%02X, Tuner=0x%02X, Decoder=0x%02X," " Audio=0x%02X.\n", pATI->I2CType, pATI->Tuner, pATI->Decoder, pATI->Audio); } ATIUnlock(pATI); /* Unlock registers */ #ifndef AVOID_CPIO /* Sometimes, the BIOS lies about the chip */ if ((pATI->Chip >= ATI_CHIP_28800_4) && (pATI->Chip <= ATI_CHIP_28800_6)) { IOValue = GetBits(ATIGetExtReg(0xAAU), 0x0FU) + (ATI_CHIP_28800_4 - 4); if ((IOValue <= ATI_CHIP_28800_6) && (IOValue > pATI->Chip)) pATI->Chip = IOValue; } #endif /* AVOID_CPIO */ /* Report what was found */ xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s graphics controller detected.\n", ATIChipNames[pATI->Chip]); #ifndef AVOID_CPIO if ((pATI->Chip >= ATI_CHIP_68800) && (pATI->Chip != ATI_CHIP_68800_3)) #endif /* AVOID_CPIO */ { Message = Buffer + snprintf(Buffer, SizeOf(Buffer), "Chip type %04X", pATI->ChipType); if (!(pATI->ChipType & ~(CHIP_CODE_0 | CHIP_CODE_1))) Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, " (%c%c)", GetBits(pATI->ChipType, CHIP_CODE_1) + 0x41U, GetBits(pATI->ChipType, CHIP_CODE_0) + 0x41U); else if ((pATI->ChipType & 0x4040U) == 0x4040U) Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, " \"%c%c\"", GetByte(pATI->ChipType, 1), GetByte(pATI->ChipType, 0)); if ((pATI->Chip >= ATI_CHIP_264CT) && (pATI->Chip != ATI_CHIP_Mach64)) Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, ", version %d, foundry %s", pATI->ChipVersion, ATIFoundryNames[pATI->ChipFoundry]); xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s, class %d, revision 0x%02X.\n", Buffer, pATI->ChipClass, pATI->ChipRevision); } #ifndef AVOID_CPIO if (pATI->Adapter >= ATI_ADAPTER_MACH8) #endif /* AVOID_CPIO */ { Message = Buffer + snprintf(Buffer, SizeOf(Buffer), "%s bus interface detected", ATIBusNames[pATI->BusType]); #ifndef AVOID_CPIO if (pATI->Adapter >= ATI_ADAPTER_MACH64) { Message += snprintf(Message, Buffer + SizeOf(Buffer) - Message, "; %s I/O base is 0x%04lX", (pATI->CPIODecoding == SPARSE_IO) ? "sparse" : "block", pATI->CPIOBase); } #endif /* AVOID_CPIO */ xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s.\n", Buffer); } #ifndef AVOID_CPIO if (pATI->CPIO_VGAWonder) xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "VGA Wonder registers at I/O port 0x%04lX.\n", pATI->CPIO_VGAWonder); if (pATI->Coprocessor != ATI_CHIP_NONE) xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s graphics accelerator detected,\n with %d kB of coprocessor" " memory.\n", ATIChipNames[pATI->Coprocessor], pATI->VideoRAM); #endif /* AVOID_CPIO */ xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s adapter detected.\n", ATIAdapterNames[pATI->Adapter]); if (pATI->Chip >= ATI_CHIP_264GT) xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, "For information on using the multimedia capabilities\n\tof this" " adapter, please see http://gatos.sf.net.\n"); if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL) { xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "Internal RAMDAC (subtype %d) detected.\n", pATI->DAC & 0x0FU); } else { const SymTabRec *DAC; for (DAC = ATIDACDescriptors; ; DAC++) { if (pATI->DAC == DAC->token) { xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%s RAMDAC detected.\n", DAC->name); break; } if (pATI->DAC < DAC->token) { xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 0, "Unknown RAMDAC type 0x%02X detected.\n", pATI->DAC); break; } } } #ifdef AVOID_CPIO if (!xf86LinearVidMem()) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "A linear aperture is not available.\n"); ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } #endif /* AVOID_CPIO */ /* * Set colour weights. */ if (pATI->Chip < ATI_CHIP_264CT) pScreenInfo->rgbBits = 6; else pScreenInfo->rgbBits = 8; pATI->rgbBits = pScreenInfo->rgbBits; if (!xf86SetWeight(pScreenInfo, defaultWeight, defaultWeight)) { ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } if ((pScreenInfo->depth > 8) && ((pScreenInfo->weight.red != pScreenInfo->weight.blue) || (pScreenInfo->weight.red != (CARD32)(pScreenInfo->depth / 3)) || ((CARD32)pScreenInfo->depth != (pScreenInfo->weight.red + pScreenInfo->weight.green + pScreenInfo->weight.blue)))) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Driver does not support weight %d%d%d for depth %d.\n", (int)pScreenInfo->weight.red, (int)pScreenInfo->weight.green, (int)pScreenInfo->weight.blue, pScreenInfo->depth); ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } /* * Set default visual. */ if (!xf86SetDefaultVisual(pScreenInfo, -1)) { ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } if ((pScreenInfo->depth > 8) && (((pScreenInfo->defaultVisual | DynamicClass) != DirectColor) || ((pScreenInfo->defaultVisual == DirectColor) && (pATI->DAC == ATI_DAC_INTERNAL)))) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Driver does not support default visual %s for depth %d.\n", xf86GetVisualName(pScreenInfo->defaultVisual), pScreenInfo->depth); ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } /* * Set colour gamma. */ #ifndef AVOID_CPIO if (pScreenInfo->depth > 1) #endif /* AVOID_CPIO */ { if (!xf86SetGamma(pScreenInfo, defaultGamma)) { ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } } pATI->depth = pScreenInfo->depth; pATI->bitsPerPixel = pScreenInfo->bitsPerPixel; pATI->weight = pScreenInfo->weight; pATI->XModifier = pATI->bitsPerPixel / UnitOf(pATI->bitsPerPixel); /* * Determine which CRT controller to use for video modes. */ #ifndef AVOID_CPIO if ((pATI->Chip >= ATI_CHIP_88800GXC) && (pATI->depth >= 8) && (pATI->Chipset == ATI_CHIPSET_ATI)) #endif /* AVOID_CPIO */ { pATI->NewHW.crtc = ATI_CRTC_MACH64; xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Using Mach64 accelerator CRTC.\n"); #ifndef AVOID_CPIO if (pATI->VGAAdapter != ATI_ADAPTER_NONE) { /* * No need for VGA I/O resources during operating state (but they * are still decoded). */ pResources = xf86SetOperatingState(resVgaIo, pATI->iEntity, ResUnusedOpr); if (pResources) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Logic error setting operating state for VGA I/O.\n"); xf86FreeResList(pResources); } if (pATI->CPIO_VGAWonder) { pResources = xf86SetOperatingState(pATI->VGAWonderResources, pATI->iEntity, ResUnusedOpr); if (pResources) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Logic error setting operating state for" " VGAWonder I/O.\n"); xf86FreeResList(pResources); } } } #endif /* AVOID_CPIO */ } #ifndef AVOID_CPIO else { pATI->NewHW.crtc = ATI_CRTC_VGA; xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Using VGA CRTC.\n"); } /* Complain if VGA is needed but not there */ if ((pATI->NewHW.crtc == ATI_CRTC_VGA) || !pATI->OptionLinear) { /* VGA is required at this point */ if (pATI->VGAAdapter == ATI_ADAPTER_NONE) { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "VGA is not available through this adapter.\n"); ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } if (pATI->Coprocessor != ATI_CHIP_NONE) { /* Ignore any 8514/A or Mach8 accelerator from this point on */ pATI->Adapter = pATI->VGAAdapter; /* Accelerator and VGA cannot share memory */ pATI->VideoRAM = 0; } } #endif /* AVOID_CPIO */ /* * Decide between the CRT and the panel. */ if (pATI->LCDPanelID >= 0) { if (!pATI->OptionPanelDisplay) { xf86DrvMsg(pScreenInfo->scrnIndex, X_CONFIG, "Using CRT interface and disabling digital flat panel.\n"); } else { unsigned HDisplay, VDisplay; CARD8 ClockMask, PostMask; /* * Determine porch data. This groks the mode on entry to extract * the width and position of its sync and blanking pulses, and * considers any overscan as part of the displayed area, given that * the overscan is also stretched. * * This also attempts to determine panel dimensions but cannot do * so for one that is "auto-stretched". */ if (pATI->Chip == ATI_CHIP_264LT) { pATIHW->lcd_gen_ctrl = inr(LCD_GEN_CTRL); /* Set up to read non-shadow registers */ if (pATIHW->lcd_gen_ctrl & SHADOW_RW_EN) outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN); } else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || (pATI->Chip == ATI_CHIP_264XL) || (pATI->Chip == ATI_CHIP_MOBILITY)) */ { pATIHW->lcd_index = inr(LCD_INDEX); pATIHW->config_panel = ATIMach64GetLCDReg(LCD_CONFIG_PANEL); pATIHW->lcd_gen_ctrl = ATIMach64GetLCDReg(LCD_GEN_CNTL); /* Set up to read non-shadow registers */ if (pATIHW->lcd_gen_ctrl & SHADOW_RW_EN) ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl & ~SHADOW_RW_EN); } #ifndef AVOID_CPIO if (!(pATIHW->crtc_gen_cntl & CRTC_EXT_DISP_EN)) { unsigned HBlankStart, HSyncStart, HSyncEnd, HBlankEnd, HTotal; unsigned VBlankStart, VSyncStart, VSyncEnd, VBlankEnd, VTotal; pATIHW->clock = (inb(R_GENMO) & 0x0CU) >> 2; pATIHW->crt[2] = GetReg(CRTX(pATI->CPIO_VGABase), 0x02U); pATIHW->crt[3] = GetReg(CRTX(pATI->CPIO_VGABase), 0x03U); pATIHW->crt[5] = GetReg(CRTX(pATI->CPIO_VGABase), 0x05U); pATIHW->crt[7] = GetReg(CRTX(pATI->CPIO_VGABase), 0x07U); pATIHW->crt[9] = GetReg(CRTX(pATI->CPIO_VGABase), 0x09U); pATIHW->crt[21] = GetReg(CRTX(pATI->CPIO_VGABase), 0x15U); pATIHW->crt[22] = GetReg(CRTX(pATI->CPIO_VGABase), 0x16U); pATIHW->crtc_h_total_disp = inr(CRTC_H_TOTAL_DISP); pATIHW->crtc_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); pATIHW->crtc_v_total_disp = inr(CRTC_V_TOTAL_DISP); pATIHW->crtc_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); /* Switch to shadow registers */ if (pATI->Chip == ATI_CHIP_264LT) outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || (pATI->Chip == ATI_CHIP_264XL) || (pATI->Chip == ATI_CHIP_MOBILITY)) */ ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); pATIHW->shadow_vga[2] = GetReg(CRTX(pATI->CPIO_VGABase), 0x02U); pATIHW->shadow_vga[3] = GetReg(CRTX(pATI->CPIO_VGABase), 0x03U); pATIHW->shadow_vga[5] = GetReg(CRTX(pATI->CPIO_VGABase), 0x05U); pATIHW->shadow_vga[7] = GetReg(CRTX(pATI->CPIO_VGABase), 0x07U); pATIHW->shadow_vga[9] = GetReg(CRTX(pATI->CPIO_VGABase), 0x09U); pATIHW->shadow_vga[21] = GetReg(CRTX(pATI->CPIO_VGABase), 0x15U); pATIHW->shadow_vga[22] = GetReg(CRTX(pATI->CPIO_VGABase), 0x16U); pATIHW->shadow_h_total_disp = inr(CRTC_H_TOTAL_DISP); pATIHW->shadow_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); pATIHW->shadow_v_total_disp = inr(CRTC_V_TOTAL_DISP); pATIHW->shadow_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); /* * HSyncStart and HSyncEnd should equal their shadow * counterparts. Otherwise, due to a chip bug, the panel might * not sync, regardless of which register set is used to drive * the panel. There are certain combinations of register * values where the panel does in fact sync, but it remains * impossible to accurately determine the horizontal sync pulse * timing actually seen by the panel. * * Note that this hardware bug does not affect the CRT output. */ if (((pATIHW->crtc_h_sync_strt_wid ^ pATIHW->shadow_h_sync_strt_wid) & (CRTC_H_SYNC_STRT | CRTC_H_SYNC_STRT_HI | CRTC_H_SYNC_WID))) { xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_NOTICE, 0, "Invalid horizontal sync pulse timing detected in mode" " on server entry.\n"); /* Don't trust input timing */ pATI->OptionLCDSync = TRUE; ModeType = 0; } /* Merge in shadow registers as appropriate */ if (pATIHW->lcd_gen_ctrl & SHADOW_EN) { pATIHW->crt[2] = pATIHW->shadow_vga[2]; pATIHW->crt[3] = pATIHW->shadow_vga[3]; pATIHW->crt[5] = pATIHW->shadow_vga[5]; /* XXX Does this apply to VGA? If so, what about the LT? */ if ((pATI->Chip < ATI_CHIP_264LTPRO) || !(pATIHW->config_panel & DONT_SHADOW_HEND)) { pATIHW->crtc_h_total_disp &= ~CRTC_H_DISP; pATIHW->crtc_h_total_disp |= pATIHW->shadow_h_total_disp & CRTC_H_DISP; } pATIHW->crtc_h_total_disp &= ~CRTC_H_TOTAL; pATIHW->crtc_h_total_disp |= pATIHW->shadow_h_total_disp & CRTC_H_TOTAL; pATIHW->crtc_h_sync_strt_wid = pATIHW->shadow_h_sync_strt_wid; /* XXX Does this apply to VGA? */ if (pATIHW->lcd_gen_ctrl & USE_SHADOWED_VEND) { pATIHW->crtc_v_total_disp &= ~CRTC_V_DISP; pATIHW->crtc_v_total_disp |= pATIHW->shadow_v_total_disp & CRTC_V_DISP; } if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR)) { pATIHW->crt[7] = pATIHW->shadow_vga[7]; pATIHW->crt[9] = pATIHW->shadow_vga[9]; pATIHW->crt[21] = pATIHW->shadow_vga[21]; pATIHW->crt[22] = pATIHW->shadow_vga[22]; pATIHW->crtc_v_total_disp &= ~CRTC_V_TOTAL; pATIHW->crtc_v_total_disp |= pATIHW->shadow_v_total_disp & CRTC_V_TOTAL; } } if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR)) pATIHW->crtc_v_sync_strt_wid = pATIHW->shadow_v_sync_strt_wid; /* * Decipher input timing. This is complicated by the fact that * the full width of all timing parameters, except for the * blanking pulses, is only available through the accelerator * registers, not the VGA ones. Blanking pulse boundaries must * then be interpolated. * * Note that, in VGA mode, the accelerator's sync width fields * are actually end positions, not widths. */ HDisplay = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_DISP); HSyncStart = (GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_STRT_HI) * (MaxBits(CRTC_H_SYNC_STRT) + 1)) | GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_STRT); HSyncEnd = (HSyncStart & ~MaxBits(CRTC_H_SYNC_WID)) | GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_WID); if (HSyncStart >= HSyncEnd) HSyncEnd += MaxBits(CRTC_H_SYNC_WID) + 1; HTotal = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_TOTAL); HBlankStart = (HDisplay & ~0xFFU) | pATIHW->crt[2]; if (HDisplay > HBlankStart) HBlankStart += 0x0100U; HBlankEnd = (HSyncEnd & ~0x3FU) | ((pATIHW->crt[5] >> 2) & 0x20U) | (pATIHW->crt[3] & 0x1FU); if (HSyncEnd > (HBlankEnd + 1)) HBlankEnd += 0x40U; VDisplay = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_DISP); VSyncStart = GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_STRT); VSyncEnd = (VSyncStart & ~MaxBits(CRTC_V_SYNC_END_VGA)) | GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_END_VGA); if (VSyncStart > VSyncEnd) VSyncEnd += MaxBits(CRTC_V_SYNC_END_VGA) + 1; VTotal = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_TOTAL); VBlankStart = (VDisplay & ~0x03FFU) | ((pATIHW->crt[9] << 4) & 0x0200U) | ((pATIHW->crt[7] << 5) & 0x0100U) | pATIHW->crt[21]; if (VDisplay > VBlankStart) VBlankStart += 0x0400U; VBlankEnd = (VSyncEnd & ~0x00FFU) | pATIHW->crt[22]; if (VSyncEnd > (VBlankEnd + 1)) VBlankEnd += 0x0100U; pATI->LCDHBlankWidth = HBlankEnd - HBlankStart; pATI->LCDHSyncStart = HSyncStart - HBlankStart; pATI->LCDHSyncWidth = HSyncEnd - HSyncStart; pATI->LCDVBlankWidth = VBlankEnd - VBlankStart; pATI->LCDVSyncStart = VSyncStart - VBlankStart; pATI->LCDVSyncWidth = VSyncEnd - VSyncStart; HDisplay = HTotal + 5 - pATI->LCDHBlankWidth; VDisplay = VTotal + 2 - pATI->LCDVBlankWidth; } else #endif /* AVOID_CPIO */ { pATIHW->clock = inr(CLOCK_CNTL) & 0x03U; pATIHW->crtc_h_total_disp = inr(CRTC_H_TOTAL_DISP); pATIHW->crtc_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); pATIHW->crtc_v_total_disp = inr(CRTC_V_TOTAL_DISP); pATIHW->crtc_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); pATIHW->ovr_wid_left_right = inr(OVR_WID_LEFT_RIGHT); pATIHW->ovr_wid_top_bottom = inr(OVR_WID_TOP_BOTTOM); /* Switch to shadow registers */ if (pATI->Chip == ATI_CHIP_264LT) outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || (pATI->Chip == ATI_CHIP_264XL) || (pATI->Chip == ATI_CHIP_MOBILITY)) */ ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl | SHADOW_RW_EN); /* Oddly enough, there are no shadow overscan registers */ pATIHW->shadow_h_total_disp = inr(CRTC_H_TOTAL_DISP); pATIHW->shadow_h_sync_strt_wid = inr(CRTC_H_SYNC_STRT_WID); pATIHW->shadow_v_total_disp = inr(CRTC_V_TOTAL_DISP); pATIHW->shadow_v_sync_strt_wid = inr(CRTC_V_SYNC_STRT_WID); /* * HSyncStart and HSyncEnd should equal their shadow * counterparts. Otherwise, due to a chip bug, the panel might * not sync, regardless of which register set is used to drive * the panel. There are certain combinations of register * values where the panel does in fact sync, but it remains * impossible to accurately determine the horizontal sync pulse * timing actually seen by the panel. * * Note that this hardware bug does not affect the CRT output. */ if (((pATIHW->crtc_h_sync_strt_wid ^ pATIHW->shadow_h_sync_strt_wid) & (CRTC_H_SYNC_STRT | CRTC_H_SYNC_STRT_HI | CRTC_H_SYNC_WID))) { xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_NOTICE, 0, "Invalid horizontal sync pulse timing detected in mode" " on server entry.\n"); /* Don't trust input timing */ pATI->OptionLCDSync = TRUE; ModeType = 0; } /* Merge in shadow registers as appropriate */ if (pATIHW->lcd_gen_ctrl & SHADOW_EN) { /* XXX What about the LT? */ if ((pATI->Chip < ATI_CHIP_264LTPRO) || !(pATIHW->config_panel & DONT_SHADOW_HEND)) { pATIHW->crtc_h_total_disp &= ~CRTC_H_DISP; pATIHW->crtc_h_total_disp |= pATIHW->shadow_h_total_disp & CRTC_H_DISP; } pATIHW->crtc_h_total_disp &= ~CRTC_H_TOTAL; pATIHW->crtc_h_total_disp |= pATIHW->shadow_h_total_disp & CRTC_H_TOTAL; pATIHW->crtc_h_sync_strt_wid = pATIHW->shadow_h_sync_strt_wid; if (pATIHW->lcd_gen_ctrl & USE_SHADOWED_VEND) { pATIHW->crtc_v_total_disp &= ~CRTC_V_DISP; pATIHW->crtc_v_total_disp |= pATIHW->shadow_v_total_disp & CRTC_V_DISP; } if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR)) { pATIHW->crtc_v_total_disp &= ~CRTC_V_TOTAL; pATIHW->crtc_v_total_disp |= pATIHW->shadow_v_total_disp & CRTC_V_TOTAL; } } if (!(pATIHW->lcd_gen_ctrl & DONT_SHADOW_VPAR)) pATIHW->crtc_v_sync_strt_wid = pATIHW->shadow_v_sync_strt_wid; /* Decipher input timing */ HDisplay = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_DISP) + GetBits(pATIHW->ovr_wid_left_right, OVR_WID_LEFT) + GetBits(pATIHW->ovr_wid_left_right, OVR_WID_RIGHT); VDisplay = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_DISP) + GetBits(pATIHW->ovr_wid_top_bottom, OVR_WID_TOP) + GetBits(pATIHW->ovr_wid_top_bottom, OVR_WID_BOTTOM); pATI->LCDHSyncStart = (GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_STRT_HI) * (MaxBits(CRTC_H_SYNC_STRT) + 1)) + GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_STRT) - HDisplay; pATI->LCDHSyncWidth = GetBits(pATIHW->crtc_h_sync_strt_wid, CRTC_H_SYNC_WID); pATI->LCDHBlankWidth = GetBits(pATIHW->crtc_h_total_disp, CRTC_H_TOTAL) - HDisplay; pATI->LCDVSyncStart = GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_STRT) - VDisplay; pATI->LCDVSyncWidth = GetBits(pATIHW->crtc_v_sync_strt_wid, CRTC_V_SYNC_WID); pATI->LCDVBlankWidth = GetBits(pATIHW->crtc_v_total_disp, CRTC_V_TOTAL) - VDisplay; HDisplay++; VDisplay++; } /* Restore LCD registers */ if (pATI->Chip == ATI_CHIP_264LT) { outr(LCD_GEN_CTRL, pATIHW->lcd_gen_ctrl); } else /* if ((pATI->Chip == ATI_CHIP_264LTPRO) || (pATI->Chip == ATI_CHIP_264XL) || (pATI->Chip == ATI_CHIP_MOBILITY)) */ { ATIMach64PutLCDReg(LCD_GEN_CNTL, pATIHW->lcd_gen_ctrl); outr(LCD_INDEX, pATIHW->lcd_index); } HDisplay <<= 3; pATI->LCDHSyncStart <<= 3; pATI->LCDHSyncWidth <<= 3; pATI->LCDHBlankWidth <<= 3; /* Calculate panel dimensions implied by the input timing */ if ((pATIHW->horz_stretching & (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) == HORZ_STRETCH_EN) { if (pATIHW->horz_stretching & HORZ_STRETCH_MODE) { if (pATIHW->horz_stretching & HORZ_STRETCH_BLEND) { HDisplay = (HDisplay * (MaxBits(HORZ_STRETCH_BLEND) + 1)) / GetBits(pATIHW->horz_stretching, HORZ_STRETCH_BLEND); } } else if (((pATIHW->horz_stretching & HORZ_STRETCH_LOOP) > HORZ_STRETCH_LOOP15) || (pATIHW->horz_stretching & SetBits(1, HORZ_STRETCH_RATIO))) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Ignoring invalid horizontal stretch ratio in mode on" " server entry.\n"); } else { IOValue = GetBits(pATIHW->horz_stretching, HORZ_STRETCH_RATIO); switch (GetBits(pATIHW->horz_stretching, HORZ_STRETCH_LOOP)) { case GetBits(HORZ_STRETCH_LOOP09, HORZ_STRETCH_LOOP): i = 9; IOValue &= (1 << 9) - 1; break; case GetBits(HORZ_STRETCH_LOOP11, HORZ_STRETCH_LOOP): i = 11; IOValue &= (1 << 11) - 1; break; case GetBits(HORZ_STRETCH_LOOP12, HORZ_STRETCH_LOOP): i = 12; IOValue &= (1 << 12) - 1; break; case GetBits(HORZ_STRETCH_LOOP14, HORZ_STRETCH_LOOP): i = 14; IOValue &= (1 << 14) - 1; break; case GetBits(HORZ_STRETCH_LOOP15, HORZ_STRETCH_LOOP): default: /* Muffle compiler */ i = 15; IOValue &= (1 << 15) - 1; break; } if (IOValue) { /* Count the number of bits in IOValue */ j = (IOValue >> 1) & 0x36DBU; j = IOValue - j - ((j >> 1) & 0x36DBU); j = ((j + (j >> 3)) & 0x71C7U) % 0x3FU; HDisplay = (HDisplay * i) / j; } } } if ((pATIHW->vert_stretching & VERT_STRETCH_EN) && !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO)) { if ((pATIHW->vert_stretching & VERT_STRETCH_USE0) || (VDisplay <= 350)) IOValue = GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO0); else if (VDisplay <= 400) IOValue = GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO1); else if ((VDisplay <= 480) || !(pATIHW->ext_vert_stretch & VERT_STRETCH_RATIO3)) IOValue = GetBits(pATIHW->vert_stretching, VERT_STRETCH_RATIO2); else IOValue = GetBits(pATIHW->ext_vert_stretch, VERT_STRETCH_RATIO3); if (IOValue) VDisplay = (VDisplay * (MaxBits(VERT_STRETCH_RATIO0) + 1)) / IOValue; } /* Match calculated dimensions to probed dimensions */ if (!pATI->LCDHorizontal) { if ((pATIHW->horz_stretching & (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) != (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) pATI->LCDHorizontal = HDisplay; } else if (pATI->LCDHorizontal != (int)HDisplay) { if ((pATIHW->horz_stretching & (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) != (HORZ_STRETCH_EN | AUTO_HORZ_RATIO)) xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 4, "Inconsistent panel horizontal dimension:" " %d and %d.\n", pATI->LCDHorizontal, HDisplay); HDisplay = pATI->LCDHorizontal; } if (!pATI->LCDVertical) { if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) || !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO)) pATI->LCDVertical = VDisplay; } else if (pATI->LCDVertical != (int)VDisplay) { if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) || !(pATIHW->ext_vert_stretch & AUTO_VERT_RATIO)) xf86DrvMsgVerb(pScreenInfo->scrnIndex, X_WARNING, 4, "Inconsistent panel vertical dimension: %d and %d.\n", pATI->LCDVertical, VDisplay); VDisplay = pATI->LCDVertical; } if (!pATI->LCDHorizontal || !pATI->LCDVertical) { if (pATI->LCDPanelID || (pATI->Chip <= ATI_CHIP_264LTPRO)) xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Unable to determine dimensions of panel (ID %d).\n", pATI->LCDPanelID); else xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Unable to determine dimensions of panel.\n"); ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } /* If the mode on entry wasn't stretched, adjust timings */ if (!(pATIHW->horz_stretching & HORZ_STRETCH_EN) && (pATI->LCDHorizontal > (int)HDisplay)) { HDisplay = pATI->LCDHorizontal - HDisplay; if (pATI->LCDHSyncStart >= HDisplay) pATI->LCDHSyncStart -= HDisplay; else pATI->LCDHSyncStart = 0; pATI->LCDHBlankWidth -= HDisplay; HDisplay = pATI->LCDHSyncStart + pATI->LCDHSyncWidth; if (pATI->LCDHBlankWidth < HDisplay) pATI->LCDHBlankWidth = HDisplay; } if (!(pATIHW->vert_stretching & VERT_STRETCH_EN) && (pATI->LCDVertical > (int)VDisplay)) { VDisplay = pATI->LCDVertical - VDisplay; if (pATI->LCDVSyncStart >= VDisplay) pATI->LCDVSyncStart -= VDisplay; else pATI->LCDVSyncStart = 0; pATI->LCDVBlankWidth -= VDisplay; VDisplay = pATI->LCDVSyncStart + pATI->LCDVSyncWidth; if (pATI->LCDVBlankWidth < VDisplay) pATI->LCDVBlankWidth = VDisplay; } if (pATI->LCDPanelID || (pATI->Chip <= ATI_CHIP_264LTPRO)) xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%dx%d panel (ID %d) detected.\n", pATI->LCDHorizontal, pATI->LCDVertical, pATI->LCDPanelID); else xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "%dx%d panel detected.\n", pATI->LCDHorizontal, pATI->LCDVertical); if (LCDPanelInfo) { for (i = 0; i < 24; i++) Buffer[i] = BIOSByte(LCDPanelInfo + 1 + i); for (; --i >= 0; ) if (Buffer[i] && Buffer[i] != ' ') { Buffer[i + 1] = '\0'; xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "Panel model %s.\n", Buffer); break; } } /* * Determine panel clock. This must be done after option * processing so that the adapter's reference frequency is always * available. * * Get post divider. A GCC bug has caused the following expression * to be broken down into its individual components. */ ClockMask = PLL_VCLK0_XDIV << pATIHW->clock; PostMask = PLL_VCLK0_POST_DIV << (pATIHW->clock * 2); i = GetBits(ATIMach64GetPLLReg(PLL_XCLK_CNTL), ClockMask); i *= MaxBits(PLL_VCLK0_POST_DIV) + 1; i |= GetBits(ATIMach64GetPLLReg(PLL_VCLK_POST_DIV), PostMask); /* Calculate clock of mode on entry */ Numerator = ATIMach64GetPLLReg(PLL_VCLK0_FB_DIV + pATIHW->clock) * pATI->ReferenceNumerator; Denominator = pATI->ClockDescriptor.MinM * pATI->ReferenceDenominator * pATI->ClockDescriptor.PostDividers[i]; pATI->LCDClock = ATIDivide(Numerator, Denominator, 1, 0); xf86DrvMsg(pScreenInfo->scrnIndex, X_PROBED, "Panel clock is %.3f MHz.\n", (double)(pATI->LCDClock) / 1000.0); xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Using digital flat panel interface%s.\n", pATI->OptionCRTDisplay ? " to display on both CRT and panel" : ""); } } /* * Finish detecting video RAM size. */ pScreenInfo->videoRam = pATI->VideoRAM; #ifndef AVOID_CPIO AcceleratorVideoRAM = pScreenInfo->videoRam; if (pATI->Chip == ATI_CHIP_VGA) { if (pATI->depth <= 4) VGAVideoRAM = 256; else VGAVideoRAM = 64; /* For VGA, allow a lower override */ if ((pGDev->videoRam > 0) && (pGDev->videoRam < VGAVideoRAM)) VGAVideoRAM = pGDev->videoRam; } else if (pATI->CPIO_VGAWonder) { /* * XXX There's an assumption here that the values retrieved are those * set by BIOS initialisation. */ if (pATI->Chip <= ATI_CHIP_18800_1) { VGAVideoRAM = videoRamSizes[GetBits(ATIGetExtReg(0xBBU), 0x20U) + 1]; if (AcceleratorVideoRAM > 512) AcceleratorVideoRAM = 512; } else { IOValue = ATIGetExtReg(0xB0U); if (IOValue & 0x08U) VGAVideoRAM = 1024; else if (IOValue & 0x10U) VGAVideoRAM = 512; else VGAVideoRAM = 256; if (AcceleratorVideoRAM > 1024) AcceleratorVideoRAM = 1024; } } /* Check for hardware limitations */ if (!AcceleratorVideoRAM) { pScreenInfo->videoRam = pATI->VideoRAM = VGAVideoRAM; /* * VGA Wonder V3's, V4's and V5's don't appear to support banking in * planar modes. */ if ((pATI->depth <= 4) && (pATI->Chip <= ATI_CHIP_18800_1) && (VGAVideoRAM > 256)) { if (pATI->OptionDevel) { xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, "Virtual resolutions requiring more than %s kB\n of video" " memory might not function properly.\n", (pATI->depth == 1) ? "64" : "256"); } else { xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, "VideoRAM reduced to 256 kB due to hardware" " limitations.\n"); pScreenInfo->videoRam = 256; } } } else if ((pATI->NewHW.crtc == ATI_CRTC_MACH64) || (pATI->Chip >= ATI_CHIP_264CT)) #endif /* AVOID_CPIO */ { #ifndef AVOID_CPIO if (pATI->depth >= 8) #endif /* AVOID_CPIO */ { /* Get adapter's linear aperture configuration */ pATIHW->config_cntl = inr(CONFIG_CNTL); pATI->LinearBase = GetBits(pATIHW->config_cntl, CFG_MEM_AP_LOC) << 22; if ((pATIHW->config_cntl & CFG_MEM_AP_SIZE) != CFG_MEM_AP_SIZE) { pATI->LinearSize = GetBits(pATIHW->config_cntl, CFG_MEM_AP_SIZE) << 22; /* * Linear aperture could have been disabled (but still * assigned) by BIOS initialisation. */ if (pATI->LinearBase && !pATI->LinearSize) { if ((pATI->Chip <= ATI_CHIP_88800GXD) && (pATI->VideoRAM < 4096)) pATI->LinearSize = 4 * 1024 * 1024; else pATI->LinearSize = 8 * 1024 * 1024; } } #ifndef AVOID_CPIO /* Except for PCI & AGP, allow for user override */ if (!pVideo) { if (pATI->Chip == ATI_CHIP_88800CX) IOValue = ~((CARD32)((1 << 23) - 1)); else if (pATI->Chip >= ATI_CHIP_88800GXE) IOValue = ~((CARD32)((1 << 24) - 1)); else if (pATI->VideoRAM >= 4096) IOValue = ~((CARD32)((1 << 23) - 1)); else IOValue = ~((CARD32)((1 << 22) - 1)); IOValue &= pGDev->MemBase; if (IOValue && (IOValue <= (CARD32)(MaxBits(CFG_MEM_AP_LOC) << 22))) pATI->LinearBase = IOValue; if (!pATI->LinearBase) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Linear aperture not configured. Specify \"MemBase\"" " override in XF86Config \"Device\" section.\n"); } else { if (!pATI->LinearSize) { if ((pATI->Chip <= ATI_CHIP_88800GXD) && (pATI->VideoRAM < 4096)) pATI->LinearSize = 4 * 1024 * 1024; else pATI->LinearSize = 8 * 1024 * 1024; } Resources[0].type = ResExcMemBlock | ResBus; Resources[0].rBegin = pATI->LinearBase; Resources[0].rEnd = pATI->LinearBase + pATI->LinearSize - 1; if (xf86RegisterResources(pATI->iEntity, Resources, ResNone)) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Unable to register %d MB linear aperture at" " 0x%08lX.\n", pATI->LinearSize >> 10, pATI->LinearBase); pATI->LinearSize = 0; } } } #endif /* AVOID_CPIO */ if (pATI->LinearBase && pATI->LinearSize) { /* * Unless specified in PCI configuration space, set MMIO * address to tail end of linear aperture. */ if (!pATI->Block0Base) { pATI->Block0Base = pATI->LinearBase + pATI->LinearSize - 0x00000400U; pATI->MMIOInLinear = TRUE; } AcceleratorVideoRAM = pATI->LinearSize >> 10; /* * Account for MMIO area at the tail end of the linear * aperture, if it is needed or if it cannot be disabled. */ if (pATI->MMIOInLinear || (pATI->Chip < ATI_CHIP_264VTB)) AcceleratorVideoRAM -= 2; ServerVideoRAM = pATI->VideoRAM; if (pATI->Cursor > ATI_CURSOR_SOFTWARE) { /* * Allocate a 1 kB cursor image area at the top of the * little-endian aperture, just before any MMIO area that * might also be there. */ if (ServerVideoRAM > AcceleratorVideoRAM) ServerVideoRAM = AcceleratorVideoRAM; ServerVideoRAM--; pATI->CursorOffset = ServerVideoRAM << 10; pATI->CursorBase = pATI->LinearBase + pATI->CursorOffset; xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Storing hardware cursor image at 0x%08lX.\n", pATI->CursorBase); } #ifndef AVOID_CPIO if (pATI->OptionLinear) #endif /* AVOID_CPIO */ { CARD32 PageSize = getpagesize() >> 10; #if X_BYTE_ORDER == X_LITTLE_ENDIAN /* * MMIO areas must be mmap()'ed separately to avoid write * combining them. Thus, they might not end up still * adjacent with the little-endian linear aperture after * mmap()'ing. So, round down the linear aperture size to * avoid an overlap. Any hardware cursor image area might * not end up being write combined, but this seems * preferable to further reducing the video memory size * advertised to the server. * * XXX Ideally this should be dealt with in the os-support * layer, i.e., it should be possible to reset a * subarea's write combining after it has been * mmap()'ed, but doing so currently causes the removal * of write combining for the entire aperture. */ if (pATI->MMIOInLinear) AcceleratorVideoRAM -= AcceleratorVideoRAM % PageSize; #else /* if X_BYTE_ORDER != X_LITTLE_ENDIAN */ /* * Big-endian apertures are 8 MB higher and don't contain * an MMIO area. */ pATI->LinearBase += 0x00800000U; AcceleratorVideoRAM = pATI->LinearSize >> 10; #endif /* X_BYTE_ORDER */ if (ServerVideoRAM > AcceleratorVideoRAM) ServerVideoRAM = AcceleratorVideoRAM; else if (AcceleratorVideoRAM > pATI->VideoRAM) AcceleratorVideoRAM = pATI->VideoRAM; PageSize--; AcceleratorVideoRAM = (AcceleratorVideoRAM + PageSize) & ~PageSize; xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Using %d MB linear aperture at 0x%08lX.\n", pATI->LinearSize >> 20, pATI->LinearBase); /* Only mmap what is needed */ ApertureSize = pATI->LinearSize = AcceleratorVideoRAM << 10; } if (ServerVideoRAM < pATI->VideoRAM) { pScreenInfo->videoRam = ServerVideoRAM; xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, "Virtual resolutions will be limited to %d kB\n due to" " linear aperture size and/or placement of hardware" " cursor image area.\n", ServerVideoRAM); } } } #ifndef AVOID_CPIO /* Set up for a banked aperture */ if (pATI->VGAAdapter != ATI_ADAPTER_NONE) { pATI->UseSmallApertures = TRUE; /* Set banking functions */ if (pATI->depth <= 4) { pATI->NewHW.SetBank = ATIMach64SetBankPlanar; pATI->BankInfo.SetSourceBank = ATIMach64SetReadPlanar; pATI->BankInfo.SetDestinationBank = ATIMach64SetWritePlanar; pATI->BankInfo.SetSourceAndDestinationBanks = ATIMach64SetReadWritePlanar; } else { pATI->NewHW.SetBank = ATIMach64SetBankPacked; pATI->BankInfo.SetSourceBank = ATIMach64SetReadPacked; pATI->BankInfo.SetDestinationBank = ATIMach64SetWritePacked; pATI->BankInfo.SetSourceAndDestinationBanks = ATIMach64SetReadWritePacked; } /* * Unless specified in PCI configuration space, or at the top of * of a little-endian linear aperture, set MMIO address to the one * just above the VGA aperture. This does not work on the CT * (maybe others). */ if (!pATI->Block0Base && ((pATI->Chip < ATI_CHIP_264CT) || (pATI->Chip >= ATI_CHIP_264VT) || pATI->OptionDevel)) pATI->Block0Base = 0x000BFC00U; } if (!pATI->OptionLinear) pATI->LinearBase = 0; /* Not needed */ #endif /* AVOID_CPIO */ if (!pATI->LinearBase || !pATI->LinearSize) { #ifndef AVOID_CPIO if (pATI->VGAAdapter == ATI_ADAPTER_NONE) #endif /* AVOID_CPIO */ { xf86DrvMsg(pScreenInfo->scrnIndex, X_ERROR, "Linear aperture not available.\n"); ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } #ifndef AVOID_CPIO /* Insurance */ pATI->LinearBase = pATI->LinearSize = 0; #endif /* AVOID_CPIO */ } if (pATI->Block0Base) { xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Using Block 0 MMIO aperture at 0x%08lX.\n", pATI->Block0Base); /* Set Block1 MMIO address if supported */ if (pATI->Chip >= ATI_CHIP_264VT) { pATI->Block1Base = pATI->Block0Base - 0x00000400U; xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Using Block 1 MMIO aperture at 0x%08lX.\n", pATI->Block1Base); } } } #ifndef AVOID_CPIO else /* * After BIOS initialisation, the accelerator (if any) and the VGA won't * necessarily agree on the amount of video memory, depending on whether or * where the memory boundary is configured. Any discrepancy will be * resolved by ATIModePreInit(). * * However, it's possible that there is more video memory than VGA Wonder * can architecturally handle. */ if (((pATI->Chip < ATI_CHIP_68800) || (pATI->Chip > ATI_CHIP_68800AX)) && (AcceleratorVideoRAM < pScreenInfo->videoRam)) { if (pATI->OptionDevel) { if (pATI->depth == 1) AcceleratorVideoRAM /= 4; xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, "Virtual resolutions requiring more than %d kB\n of video" " memory might not function correctly.\n", AcceleratorVideoRAM); } else { xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, "VideoRAM reduced to %d kB due to hardware limitations.\n", AcceleratorVideoRAM); pScreenInfo->videoRam = AcceleratorVideoRAM; } } if (pATI->OptionLinear) { if (!pATI->LinearBase) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Linear aperture not supported in this configuration.\n"); pATI->OptionLinear = FALSE; } else if (pATI->VGAAdapter != ATI_ADAPTER_NONE) { /* * Free VGA memory aperture during operating state (but it is still * decoded). */ pResources = xf86SetOperatingState(resVgaMem, pATI->iEntity, ResUnusedOpr); if (pResources) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Logic error setting operating state for VGA memory" " aperture.\n"); xf86FreeResList(pResources); } } } #endif /* AVOID_CPIO */ if ((pATI->Cursor > ATI_CURSOR_SOFTWARE) && !pATI->CursorBase) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Unable to store hardware cursor image. Reverting to software" " cursor.\n"); pATI->Cursor = ATI_CURSOR_SOFTWARE; } /* * Remap apertures. Must lock and re-unlock around this in case the * remapping fails. */ ATILock(pATI); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); if (!ATIMapApertures(pScreenInfo->scrnIndex, pATI)) return FALSE; ATIUnlock(pATI); if (pATI->OptionAccel) { #ifndef AVOID_CPIO if (!pATI->Block0Base || (pATI->NewHW.crtc == ATI_CRTC_VGA)) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Acceleration not supported in this configuration.\n"); pATI->OptionAccel = FALSE; } else #endif /* AVOID_CPIO */ { xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "MMIO write caching %sabled.\n", pATI->OptionMMIOCache ? "en" : "dis"); } } #ifndef AVOID_CPIO if (pATI->Adapter >= ATI_ADAPTER_MACH32) #endif /* AVOID_CPIO */ { if (pATI->Chip >= ATI_CHIP_264CT) ATIReportMemory(pScreenInfo, pATI, ATIMemoryTypeNames_264xT[pATI->MemoryType]); else if (pATI->Chip == ATI_CHIP_88800CX) ATIReportMemory(pScreenInfo, pATI, ATIMemoryTypeNames_88800CX[pATI->MemoryType]); else ATIReportMemory(pScreenInfo, pATI, ATIMemoryTypeNames_Mach[pATI->MemoryType]); } #ifndef AVOID_CPIO else if (pATI->Adapter >= ATI_ADAPTER_V3) { ATIReportMemory(pScreenInfo, pATI, (ATIGetExtReg(0xB7U) & 0x04U) ? "DRAM" : "VRAM"); } else { ATIReportMemory(pScreenInfo, pATI, "video memory"); } #endif /* AVOID_CPIO */ /* * Finish banking setup. This needs to be fixed to not assume the mode on * entry is a VGA mode. XXX */ #ifndef AVOID_CPIO if (pATI->VGAAdapter == ATI_ADAPTER_NONE) #endif /* AVOID_CPIO */ { pATIHW->crtc = pATI->NewHW.crtc; #ifndef AVOID_CPIO pATIHW->SetBank = (ATIBankProcPtr)NoopDDA; pATI->BankInfo.BankSize = 0; /* No banking */ #endif /* AVOID_CPIO */ } #ifndef AVOID_CPIO else { pATIHW->crtc = ATI_CRTC_VGA; #if 0 /* ___NOT_YET___ */ if (pATI->ChipHasSUBSYS_CNTL) { } else #endif if ((pATI->Chip >= ATI_CHIP_88800GXC) && (pATI->LockData.crtc_gen_cntl & CRTC_EXT_DISP_EN)) { pATIHW->crtc = ATI_CRTC_MACH64; } if (pATI->depth <= 4) { pATI->BankInfo.nBankDepth = 1; pATI->NewHW.nPlane = 4; } else { pATI->BankInfo.nBankDepth = pATI->depth; pATI->NewHW.nPlane = 1; } if ((pATIHW->crtc != ATI_CRTC_VGA) || (GetReg(SEQX, 0x04U) & 0x08U)) pATIHW->nPlane = 1; else pATIHW->nPlane = 4; pATIHW->nBank = ATIDivide(pATI->VideoRAM, pATIHW->nPlane * pATI->BankInfo.BankSize, 10, 1); pATI->NewHW.nBank = ATIDivide(pATI->VideoRAM, pATI->NewHW.nPlane * pATI->BankInfo.BankSize, 10, 1); if (pATI->VGAAdapter == ATI_ADAPTER_VGA) { pATIHW->SetBank = pATI->NewHW.SetBank = (ATIBankProcPtr)NoopDDA; pATIHW->nBank = pATI->NewHW.nBank = 1; } else if (!pATI->UseSmallApertures) { pATIHW->SetBank = pATI->NewHW.SetBank; } else if ((pATIHW->crtc == ATI_CRTC_VGA) && !(pATI->LockData.config_cntl & CFG_MEM_VGA_AP_EN)) { pATIHW->SetBank = (ATIBankProcPtr)NoopDDA; pATIHW->nBank = 1; } else if (pATIHW->nPlane == 1) { pATIHW->SetBank = ATIMach64SetBankPacked; } else { pATIHW->SetBank = ATIMach64SetBankPlanar; } if (((ApertureSize * pATI->depth) / pATI->BankInfo.nBankDepth) >= (unsigned)(pScreenInfo->videoRam * 1024)) pATI->BankInfo.BankSize = 0; /* No banking */ } #endif /* AVOID_CPIO */ if (pATI->OptionShadowFB) { /* Until ShadowFB becomes a true screen wrapper, if it ever does... */ #ifndef AVOID_CPIO if (pATI->BankInfo.BankSize) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Cannot shadow a banked frame buffer.\n"); pATI->OptionShadowFB = FALSE; } else if (pATI->depth < 8) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Cannot shadow a planar frame buffer.\n"); pATI->OptionShadowFB = FALSE; } else #endif /* AVOID_CPIO */ if (pATI->OptionAccel) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Cannot shadow an accelerated frame buffer.\n"); pATI->OptionShadowFB = FALSE; } else { xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Using shadow frame buffer.\n"); } } /* 264VT-B's and later have DSP registers */ if ((pATI->Chip >= ATI_CHIP_264VTB) && !ATIDSPPreInit(pScreenInfo->scrnIndex, pATI)) { ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } /* * Determine minClock and maxClock. For adapters with supported * programmable clock generators, start with an absolute maximum. */ if (pATI->ClockDescriptor.MaxN > 0) { Numerator = pATI->ClockDescriptor.MaxN * pATI->ReferenceNumerator; Denominator = pATI->ClockDescriptor.MinM * pATI->ReferenceDenominator * pATI->ClockDescriptor.PostDividers[0]; /* * An integrated PLL behaves as though the reference frequency were * doubled. It also does not appear to care about the colour depth. */ if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL) Numerator <<= 1; else if (pATI->depth > 8) Denominator *= (pATI->bitsPerPixel / 8); ATIClockRange.maxClock = (Numerator / (Denominator * 1000)) * 1000; Numerator = pATI->ClockDescriptor.MinN * pATI->ReferenceNumerator; Denominator = pATI->ClockDescriptor.MaxM * pATI->ReferenceDenominator * pATI->ClockDescriptor.PostDividers[pATI->ClockDescriptor.NumD - 1]; if (pATI->ProgrammableClock == ATI_CLOCK_INTERNAL) Numerator <<= 1; ATIClockRange.minClock = (Numerator / (Denominator * 1000)) * 1000; if (pATI->XCLKFeedbackDivider) { /* Possibly reduce maxClock due to memory bandwidth */ Numerator = pATI->XCLKFeedbackDivider * 2 * pATI->ReferenceNumerator; Denominator = pATI->ClockDescriptor.MinM * pATI->XCLKReferenceDivider * pATI->ReferenceDenominator; #ifndef AVOID_CPIO if (pATI->depth >= 8) #endif /* AVOID_CPIO */ { Denominator *= pATI->bitsPerPixel / 4; } i = (6 - 2) - pATI->XCLKPostDivider; #ifndef AVOID_CPIO if (pATI->NewHW.crtc == ATI_CRTC_VGA) i--; #endif /* AVOID_CPIO */ i = (ATIDivide(Numerator, Denominator, i, -1) / 1000) * 1000; if (i < ATIClockRange.maxClock) ATIClockRange.maxClock = i; } } /* * Assume an internal DAC can handle whatever frequency the internal PLL * can produce (with the reference divider set by BIOS initialisation), but * default maxClock to a lower chip-specific default. */ if ((pATI->DAC & ~0x0FU) == ATI_DAC_INTERNAL) { int DacSpeed; switch (pATI->bitsPerPixel) { case 15: case 16: DacSpeed = pGDev->dacSpeeds[DAC_BPP16]; break; case 24: DacSpeed = pGDev->dacSpeeds[DAC_BPP24]; break; case 32: DacSpeed = pGDev->dacSpeeds[DAC_BPP32]; break; default: DacSpeed = 0; break; } if (!DacSpeed) DacSpeed = pGDev->dacSpeeds[DAC_BPP8]; if (DacSpeed < ATIClockRange.maxClock) { DefaultmaxClock = 135000; if (pATI->depth > 8) DefaultmaxClock = 80000; if ((pATI->Chip >= ATI_CHIP_264VTB) && (pATI->Chip != ATI_CHIP_Mach64)) { if ((pATI->Chip >= ATI_CHIP_264VT4) && (pATI->Chip != ATI_CHIP_264LTPRO)) DefaultmaxClock = 230000; else if (pATI->Chip >= ATI_CHIP_264VT3) DefaultmaxClock = 200000; else DefaultmaxClock = 170000; } if (DacSpeed > DefaultmaxClock) ATIClockRange.maxClock = DacSpeed; else if (DefaultmaxClock < ATIClockRange.maxClock) ATIClockRange.maxClock = DefaultmaxClock; } } else { switch(pATI->DAC) { case ATI_DAC_STG1700: case ATI_DAC_STG1702: case ATI_DAC_STG1703: DefaultmaxClock = 110000; break; case ATI_DAC_IBMRGB514: pATI->maxClock = 220000; #ifndef AVOID_CPIO if (pATI->NewHW.crtc == ATI_CRTC_VGA) { DefaultmaxClock = 100000; } else #endif /* AVOID_CPIO */ { DefaultmaxClock = 220000; } break; default: #ifndef AVOID_CPIO /* * 80 MHz is too high in some cases. Limit 18800-x's to 40 * MHz. Don't exceed the memory clock on VGA Wonder capables * with less than 1 MB, if using a packed mode. */ if ((pATI->Chip == ATI_CHIP_18800) || (pATI->Chip == ATI_CHIP_18800_1)) { DefaultmaxClock = 40000; } else if (pATI->CPIO_VGAWonder && (pATI->VideoRAM < 1024) && (pATI->depth >= 8)) { DefaultmaxClock = (GetBits(BIOSByte(0x44U), 0x04U) * 5000) + 40000; } else #endif /* AVOID_CPIO */ { DefaultmaxClock = 80000; } break; } if (DefaultmaxClock < ATIClockRange.maxClock) ATIClockRange.maxClock = DefaultmaxClock; } if (pATI->ClockDescriptor.MaxN <= 0) { ATIClockRange.maxClock = DefaultmaxClock; xf86DrvMsg(pScreenInfo->scrnIndex, X_INFO, "Maximum pixel clock: %.3f MHz.\n", (double)ATIClockRange.maxClock / 1000.0); } /* * Determine available pixel clock frequencies. */ ATIClockPreInit(pScreenInfo, pATI, pGDev, &ATIClockRange); if (pATI->ProgrammableClock > ATI_CLOCK_FIXED) Strategy = LOOKUP_BEST_REFRESH; /* * Mode validation. */ #ifdef AVOID_CPIO if (pATI->Chip >= ATI_CHIP_264CT) { minPitch = 8; } #else /* AVOID_CPIO */ if ((pATI->depth >= 8) && (pATI->Chip >= ATI_CHIP_264CT)) { minPitch = 8; } else if (pATI->CPIO_VGAWonder && (pATI->Chip <= ATI_CHIP_18800_1) && (pATI->VideoRAM == 256) && (pATI->depth >= 8)) { minPitch = 32; /* Very strange, but true */ maxPitch = 0x3FU; } #endif /* AVOID_CPIO */ else { minPitch = 16; } pATI->pitchInc = minPitch; #ifndef AVOID_CPIO if (pATI->depth >= 8) #endif /* AVOID_CPIO */ { pATI->pitchInc *= pATI->bitsPerPixel; } switch (pATI->NewHW.crtc) { #ifndef AVOID_CPIO case ATI_CRTC_VGA: /* * IBM's VGA doesn't allow for interlaced modes. */ if (pATI->Adapter <= ATI_ADAPTER_VGA) ATIClockRange.interlaceAllowed = FALSE; pScreenInfo->maxHValue = (0xFFU + 1) << 3; /* max HTotal */ /* * The maximum VTotal value set here applies to all modes, * including interlaced, doublescanned or multiscanned modes. * Finer-grained checks are done in ATIValidateMode(). */ pScreenInfo->maxVValue = 0x03FFU + 1; if (pATI->Adapter > ATI_ADAPTER_VGA) { pScreenInfo->maxVValue <<= 1; if (ATIClockRange.interlaceAllowed && (pATI->Chip < ATI_CHIP_264CT)) pScreenInfo->maxVValue <<= 1; } /* * 18800-x and 28800-x do not support interlaced modes when the * scanline pitch is 2048 pixels or more. For 18800-x's with 256 * kB of video memory, the limit for 8bpp is 1024. */ if (ATIClockRange.interlaceAllowed && (pATI->Chip <= ATI_CHIP_28800_6)) { if (minPitch == 32) pATI->MaximumInterlacedPitch = 0x1FU * 32; else pATI->MaximumInterlacedPitch = 0x7FU * minPitch; } Strategy |= LOOKUP_CLKDIV2; break; #endif /* AVOID_CPIO */ case ATI_CRTC_MACH64: pScreenInfo->maxHValue = (MaxBits(CRTC_H_TOTAL) + 1) << 3; if (pATI->Chip < ATI_CHIP_264VT) { /* * ATI finally fixed accelerated doublescanning in the 264VT * and later. On 88800's, the bit is documented to exist, but * only doubles the vertical timings. On the 264CT and 264ET, * the bit is ignored. */ ATIClockRange.doubleScanAllowed = FALSE; /* CRTC_H_TOTAL is one bit narrower */ pScreenInfo->maxHValue >>= 1; } pScreenInfo->maxVValue = MaxBits(CRTC_V_TOTAL) + 1; maxPitch = MaxBits(CRTC_PITCH); break; default: break; } maxPitch *= minPitch; if (pATI->OptionAccel) { /* * Set engine restrictions on coordinate space. Use maxPitch for the * horizontal and maxHeight for the vertical. */ if (maxPitch > (ATIMach64MaxX / pATI->XModifier)) maxPitch = ATIMach64MaxX / pATI->XModifier; maxHeight = ATIMach64MaxY; /* * For SGRAM & WRAM adapters, the display engine limits the pitch to * multiples of 64 bytes. */ if ((pATI->Chip >= ATI_CHIP_264CT) && ((pATI->Chip >= ATI_CHIP_264VTB) || (pATI->MemoryType >= MEM_264_SGRAM))) pATI->pitchInc = pATI->XModifier * (64 * 8); } if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) { /* * Given LCD modes are more tightly controlled than CRT modes, allow * the user the option of not specifying a panel's horizontal sync * and/or vertical refresh tolerances. */ Strategy |= LOOKUP_OPTIONAL_TOLERANCES; if (ModeType == M_T_BUILTIN) { /* * Add a mode to the end of the monitor's list for the panel's * native resolution. */ pMode = (DisplayModePtr)xnfcalloc(1, SizeOf(DisplayModeRec)); pMode->name = "Native panel mode"; pMode->type = M_T_BUILTIN; pMode->Clock = pATI->LCDClock; pMode->HDisplay = pATI->LCDHorizontal; pMode->VDisplay = pATI->LCDVertical; /* * These timings are bogus, but enough to survive sync tolerance * checks. */ pMode->HSyncStart = pMode->HDisplay; pMode->HSyncEnd = pMode->HSyncStart + minPitch; pMode->HTotal = pMode->HSyncEnd + minPitch; pMode->VSyncStart = pMode->VDisplay; pMode->VSyncEnd = pMode->VSyncStart + 1; pMode->VTotal = pMode->VSyncEnd + 1; pMode->CrtcHDisplay = pMode->HDisplay; pMode->CrtcHBlankStart = pMode->HDisplay; pMode->CrtcHSyncStart = pMode->HSyncStart; pMode->CrtcHSyncEnd = pMode->HSyncEnd; pMode->CrtcHBlankEnd = pMode->HTotal; pMode->CrtcHTotal = pMode->HTotal; pMode->CrtcVDisplay = pMode->VDisplay; pMode->CrtcVBlankStart = pMode->VDisplay; pMode->CrtcVSyncStart = pMode->VSyncStart; pMode->CrtcVSyncEnd = pMode->VSyncEnd; pMode->CrtcVBlankEnd = pMode->VTotal; pMode->CrtcVTotal = pMode->VTotal; if (!pScreenInfo->monitor->Modes) { pScreenInfo->monitor->Modes = pMode; } else { pScreenInfo->monitor->Last->next = pMode; pMode->prev = pScreenInfo->monitor->Last; } pScreenInfo->monitor->Last = pMode; } /* * Defeat Xconfigurator brain damage. Ignore all HorizSync and * VertRefresh specifications. For now, this does not take * SYNC_TOLERANCE into account. */ if (pScreenInfo->monitor->nHsync > 0) { double hsync = (double)pATI->LCDClock / (pATI->LCDHorizontal + pATI->LCDHBlankWidth); for (i = 0; ; i++) { if (i >= pScreenInfo->monitor->nHsync) { xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, "Conflicting XF86Config HorizSync specification(s)" " ignored.\n"); break; } if ((hsync >= pScreenInfo->monitor->hsync[i].lo) && (hsync <= pScreenInfo->monitor->hsync[i].hi)) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Extraneous XF86Config HorizSync specification(s)" " ignored.\n"); break; } } pScreenInfo->monitor->nHsync = 0; } if (pScreenInfo->monitor->nVrefresh > 0) { double vrefresh = ((double)pATI->LCDClock * 1000.0) / ((pATI->LCDHorizontal + pATI->LCDHBlankWidth) * (pATI->LCDVertical + pATI->LCDVBlankWidth)); for (i = 0; ; i++) { if (i >= pScreenInfo->monitor->nVrefresh) { xf86DrvMsg(pScreenInfo->scrnIndex, X_NOTICE, "Conflicting XF86Config VertRefresh specification(s)" " ignored.\n"); break; } if ((vrefresh >= pScreenInfo->monitor->vrefresh[i].lo) && (vrefresh <= pScreenInfo->monitor->vrefresh[i].hi)) { xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Extraneous XF86Config VertRefresh specification(s)" " ignored.\n"); break; } } pScreenInfo->monitor->nVrefresh = 0; } } i = xf86ValidateModes(pScreenInfo, pScreenInfo->monitor->Modes, pScreenInfo->display->modes, &ATIClockRange, NULL, minPitch, maxPitch, pATI->pitchInc, 0, maxHeight, pScreenInfo->display->virtualX, pScreenInfo->display->virtualY, ApertureSize, Strategy); if (i <= 0) { ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } /* Remove invalid modes */ xf86PruneDriverModes(pScreenInfo); /* Set current mode to the first in the list */ pScreenInfo->currentMode = pScreenInfo->modes; /* Print mode list */ xf86PrintModes(pScreenInfo); /* Set display resolution */ xf86SetDpi(pScreenInfo, 0, 0); /* Load required modules */ if (!ATILoadModules(pScreenInfo, pATI)) { ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return FALSE; } pATI->displayWidth = pScreenInfo->displayWidth; /* Initialise for panning */ ATIAdjustPreInit(pATI); /* * Warn about modes that are too small, or not aligned, to scroll to the * bottom right corner of the virtual screen. */ MinX = pScreenInfo->virtualX - pATI->AdjustMaxX; MinY = pScreenInfo->virtualY - pATI->AdjustMaxY; pMode = pScreenInfo->modes; do { if ((pMode->VDisplay <= MinY) && ((pMode->VDisplay < MinY) || (pMode->HDisplay < MinX))) xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Mode \"%s\" too small to scroll to bottom right corner of" " virtual resolution.\n", pMode->name); else if ((pMode->HDisplay & ~pATI->AdjustMask) / pScreenInfo->xInc) xf86DrvMsg(pScreenInfo->scrnIndex, X_WARNING, "Mode \"%s\" cannot scroll to bottom right corner of virtual" " resolution.\n Horizontal dimension not a multiple of %ld.\n", pMode->name, ~pATI->AdjustMask + 1); } while ((pMode = pMode->next) != pScreenInfo->modes); /* Initialise XVideo extension support */ ATIXVPreInit(pATI); /* Initialise CRTC code */ ATIModePreInit(pScreenInfo, pATI, &pATI->NewHW); /* Set up for I2C */ ATII2CPreInit(pScreenInfo, pATI); if (!pScreenInfo->chipset || !*pScreenInfo->chipset) pScreenInfo->chipset = (char *)ATIChipsetNames[0]; ATILock(pATI); ATIPrintNoiseIfRequested(pATI, BIOS, BIOSSize); ATIUnmapApertures(pScreenInfo->scrnIndex, pATI); return TRUE; }