/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/atiprobe.c,v 1.54 2003/01/01 19:16:33 tsi Exp $ */ /* * Copyright 1997 through 2003 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. */ #include "ati.h" #include "atiadapter.h" #include "atiadjust.h" #include "atibus.h" #include "atichip.h" #include "aticonsole.h" #include "atiident.h" #include "atimach64io.h" #include "atimodule.h" #include "atipreinit.h" #include "atiprobe.h" #include "atiscreen.h" #include "ativalid.h" #include "ativersion.h" #include "atividmem.h" #include "atiwonderio.h" #include "radeon_probe.h" #include "radeon_version.h" #include "r128_probe.h" #include "r128_version.h" /* * NOTES: * * - The driver private structures (ATIRec's) are allocated here, rather than * in ATIPreInit(). This allows ATIProbe() to pass information to later * stages. * - A minor point, perhaps, is that XF86Config Chipset names denote functional * levels, rather than specific graphics controller chips. * - ATIProbe() does not call xf86MatchPciInstances(), because ATIProbe() * should be able to match a mix of PCI and non-PCI devices to XF86Config * Device sections. Also, PCI configuration space for Mach32's is to be * largely ignored. */ #ifdef XFree86LOADER /* * The following exists to prevent the compiler from considering entry points * defined in a separate module from being constants. */ static xf86PreInitProc * const volatile PreInitProc = ATIPreInit; static xf86ScreenInitProc * const volatile ScreenInitProc = ATIScreenInit; static xf86SwitchModeProc * const volatile SwitchModeProc = ATISwitchMode; static xf86AdjustFrameProc * const volatile AdjustFrameProc = ATIAdjustFrame; static xf86EnterVTProc * const volatile EnterVTProc = ATIEnterVT; static xf86LeaveVTProc * const volatile LeaveVTProc = ATILeaveVT; static xf86FreeScreenProc * const volatile FreeScreenProc = ATIFreeScreen; static xf86ValidModeProc * const volatile ValidModeProc = ATIValidMode; #define ATIPreInit PreInitProc #define ATIScreenInit ScreenInitProc #define ATISwitchMode SwitchModeProc #define ATIAdjustFrame AdjustFrameProc #define ATIEnterVT EnterVTProc #define ATILeaveVT LeaveVTProc #define ATIFreeScreen FreeScreenProc #define ATIValidMode ValidModeProc #endif /* Used as a temporary buffer */ #define Identifier ((char *)(pATI->MMIOCache)) /* * An internal structure definition to facilitate the matching of detected * adapters to XF86Config Device sections. */ typedef struct _ATIGDev { GDevPtr pGDev; int iATIPtr; CARD8 Chipset; } ATIGDev, *ATIGDevPtr; #ifndef AVOID_CPIO /* * Definitions for I/O conflict avoidance. */ #define LongPort(_Port) GetBits(_Port, PCIGETIO(SPARSE_IO_BASE)) #define DetectedVGA (1 << 0) #define Detected8514A (1 << 1) #define DetectedMach64 (1 << 2) #define Allowed (1 << 3) #define DoProbe (1 << 4) typedef struct { IOADDRESS Base; CARD8 Size; CARD8 Flag; } PortRec, *PortPtr; /* * ATIScanPCIBases -- * * This function loops though a device's PCI registered bases and accumulates * a list of block I/O bases in use in the system. */ static void ATIScanPCIBases ( PortPtr *PCIPorts, int *nPCIPort, const CARD32 *pBase, const int *pSize, const CARD8 ProbeFlag ) { IOADDRESS Base; int i, j; for (i = 6; --i >= 0; pBase++, pSize++) { if (*pBase & PCI_MAP_IO) { Base = *pBase & ~IO_BYTE_SELECT; for (j = 0; ; j++) { if (j >= *nPCIPort) { (*nPCIPort)++; *PCIPorts = (PortPtr)xnfrealloc(*PCIPorts, *nPCIPort * SizeOf(PortRec)); (*PCIPorts)[j].Base = Base; (*PCIPorts)[j].Size = (CARD8)*pSize; (*PCIPorts)[j].Flag = ProbeFlag; break; } if (Base == (*PCIPorts)[j].Base) break; } continue; } /* Allow for 64-bit addresses */ if (!PCI_MAP_IS64BITMEM(*pBase)) continue; i--; pBase++; pSize++; } } /* * ATICheckSparseIOBases -- * * This function checks whether a sparse I/O base can safely be probed. */ static CARD8 ATICheckSparseIOBases ( pciVideoPtr pVideo, CARD8 *ProbeFlags, const IOADDRESS IOBase, const int Count, const Bool Override ) { CARD32 FirstPort, LastPort; if (!pVideo || !xf86IsPrimaryPci(pVideo)) { FirstPort = LongPort(IOBase); LastPort = LongPort(IOBase + Count - 1); for (; FirstPort <= LastPort; FirstPort++) { CARD8 ProbeFlag = ProbeFlags[FirstPort]; if (ProbeFlag & DoProbe) continue; if (!(ProbeFlag & Allowed)) return ProbeFlag; if (Override) continue; /* User might wish to override this decision */ xf86Msg(X_WARNING, ATI_NAME ": Sparse I/O base 0x%04X not probed.\n", IOBase); return Allowed; } } return DoProbe; } /* * ATIClaimSparseIOBases -- * * This function updates the sparse I/O base table with information from the * hardware probes. */ static void ATIClaimSparseIOBases ( CARD8 *ProbeFlags, const IOADDRESS IOBase, const int Count, const CARD8 ProbeFlag ) { CARD32 FirstPort = LongPort(IOBase), LastPort = LongPort(IOBase + Count - 1); for (; FirstPort <= LastPort; FirstPort++) ProbeFlags[FirstPort] = ProbeFlag; } /* * ATIVGAProbe -- * * This function looks for an IBM standard VGA, or clone, and sets * pATI->VGAAdapter if one is found. */ static ATIPtr ATIVGAProbe ( ATIPtr pVGA ) { CARD8 IOValue1, IOValue2, IOValue3; if (!pVGA) pVGA = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec)); /* * VGA has one more attribute register than EGA. See if it can be read and * written. Note that the CRTC registers are not used here, so there's no * need to unlock them. */ ATISetVGAIOBase(pVGA, inb(R_GENMO)); (void)inb(GENS1(pVGA->CPIO_VGABase)); IOValue1 = inb(ATTRX); (void)inb(GENS1(pVGA->CPIO_VGABase)); IOValue2 = GetReg(ATTRX, 0x14U | 0x20U); outb(ATTRX, IOValue2 ^ 0x0FU); IOValue3 = GetReg(ATTRX, 0x14U | 0x20U); outb(ATTRX, IOValue2); outb(ATTRX, IOValue1); (void)inb(GENS1(pVGA->CPIO_VGABase)); if (IOValue3 == (IOValue2 ^ 0x0FU)) { /* VGA device detected */ if (pVGA->Chip == ATI_CHIP_NONE) pVGA->Chip = ATI_CHIP_VGA; if (pVGA->VGAAdapter == ATI_ADAPTER_NONE) pVGA->VGAAdapter = ATI_ADAPTER_VGA; if (pVGA->Adapter == ATI_ADAPTER_NONE) pVGA->Adapter = ATI_ADAPTER_VGA; } else pVGA->VGAAdapter = ATI_ADAPTER_NONE; return pVGA; } /* * ATIVGAWonderProbe -- * * This function determines if ATI extended VGA registers can be accessed * through the I/O port specified by pATI->CPIO_VGAWonder. If not, the * function resets pATI->CPIO_VGAWonder to zero. */ static void ATIVGAWonderProbe ( pciVideoPtr pVideo, ATIPtr pATI, ATIPtr p8514, CARD8 *ProbeFlags ) { CARD8 IOValue1, IOValue2, IOValue3, IOValue4, IOValue5, IOValue6; switch (ATICheckSparseIOBases(pVideo, ProbeFlags, pATI->CPIO_VGAWonder, 2, TRUE)) { case 0: xf86Msg(X_WARNING, ATI_NAME ": Expected VGA Wonder capability could not be" " detected at I/O port 0x%04X because it would conflict with" " a non-video PCI/AGP device.\n", pATI->CPIO_VGAWonder); pATI->CPIO_VGAWonder = 0; break; case Detected8514A: xf86Msg(X_WARNING, ATI_NAME ": Expected VGA Wonder capability could not be" " detected at I/O port 0x%04X because it would conflict with" " a %s %s.\n", pATI->CPIO_VGAWonder, ATIBusNames[p8514->BusType], ATIAdapterNames[p8514->Adapter]); pATI->CPIO_VGAWonder = 0; break; case DetectedMach64: xf86Msg(X_WARNING, ATI_NAME ": Expected VGA Wonder capability could not be" " detected at I/O port 0x%04X because it would conflict with" " a Mach64.\n", pATI->CPIO_VGAWonder); pATI->CPIO_VGAWonder = 0; break; case DetectedVGA: default: /* Must be DoProbe */ if (pVideo && !xf86IsPrimaryPci(pVideo) && (pATI->Chip <= ATI_CHIP_88800GXD)) { /* Set up extended VGA register addressing */ PutReg(GRAX, 0x50U, GetByte(pATI->CPIO_VGAWonder, 0)); PutReg(GRAX, 0x51U, GetByte(pATI->CPIO_VGAWonder, 1) | pATI->VGAOffset); } /* * Register 0xBB is used by the BIOS to keep track of various * things (monitor type, etc.). Except for 18800-x's, register * 0xBC must be zero and causes the adapter to enter a test mode * when written to with a non-zero value. */ IOValue1 = inb(pATI->CPIO_VGAWonder); IOValue2 = ATIGetExtReg(IOValue1); IOValue3 = ATIGetExtReg(0xBBU); ATIPutExtReg(0xBBU, IOValue3 ^ 0xAAU); IOValue4 = ATIGetExtReg(0xBBU); ATIPutExtReg(0xBBU, IOValue3 ^ 0x55U); IOValue5 = ATIGetExtReg(0xBBU); ATIPutExtReg(0xBBU, IOValue3); if (pATI->Chip <= ATI_CHIP_18800_1) IOValue6 = 0; else IOValue6 = ATIGetExtReg(0xBCU); ATIPutExtReg(IOValue1, IOValue2); if ((IOValue4 == (IOValue3 ^ 0xAAU)) && (IOValue5 == (IOValue3 ^ 0x55U)) && (IOValue6 == 0)) { xf86MsgVerb(X_INFO, 3, ATI_NAME ": VGA Wonder at I/O port 0x%04X detected.\n", pATI->CPIO_VGAWonder); } else { xf86Msg(X_WARNING, ATI_NAME ": Expected VGA Wonder capability at I/O port" " 0x%04X was not detected.\n", pATI->CPIO_VGAWonder); pATI->CPIO_VGAWonder = 0; } break; } } /* * ATI8514Probe -- * * This function looks for an 8514/A compatible and returns an ATIRec if one is * found. The function also determines whether or not the detected 8514/A * compatible device is actually a Mach8 or Mach32, and sets pATI->Adapter * accordingly. */ static ATIPtr ATI8514Probe ( pciVideoPtr pVideo ) { ATIPtr pATI = NULL; CARD16 IOValue1, IOValue2; /* * Save register value to be modified, just in case there is no 8514/A * compatible accelerator. Note that, in more ways than one, * SUBSYS_STAT == SUBSYS_CNTL. */ IOValue1 = inw(SUBSYS_STAT); IOValue2 = IOValue1 & _8PLANE; /* Reset any 8514/A compatible adapter that might be present */ outw(SUBSYS_CNTL, IOValue2 | (GPCTRL_RESET | CHPTEST_NORMAL)); outw(SUBSYS_CNTL, IOValue2 | (GPCTRL_ENAB | CHPTEST_NORMAL | RVBLNKFLG | RPICKFLAG | RINVALIDIO | RGPIDLE)); /* Probe for an 8514/A compatible */ IOValue2 = inw(ERR_TERM); outw(ERR_TERM, 0x5A5AU); ProbeWaitIdleEmpty(); if (inw(ERR_TERM) == 0x5A5AU) { outw(ERR_TERM, 0x2525U); if (inw(ERR_TERM) == 0x2525U) { pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec)); pATI->Adapter = ATI_ADAPTER_8514A; pATI->ChipHasSUBSYS_CNTL = TRUE; pATI->PCIInfo = pVideo; } } outw(ERR_TERM, IOValue2); /* Restore register value clobbered by 8514/A reset attempt */ if (!pATI) { outw(SUBSYS_CNTL, IOValue1); return NULL; } /* Ensure any Mach8 or Mach32 is not in 8514/A emulation mode */ IOValue1 = inw(CLOCK_SEL); outw(CLOCK_SEL, IOValue1); ProbeWaitIdleEmpty(); IOValue1 = IOValue2 = inw(ROM_ADDR_1); outw(ROM_ADDR_1, 0x5555U); ProbeWaitIdleEmpty(); if (inw(ROM_ADDR_1) == 0x5555U) { outw(ROM_ADDR_1, 0x2A2AU); ProbeWaitIdleEmpty(); if (inw(ROM_ADDR_1) == 0x2A2AU) pATI->Adapter = ATI_ADAPTER_MACH8; } outw(ROM_ADDR_1, IOValue1); if (pATI->Adapter == ATI_ADAPTER_MACH8) { /* A Mach8 or Mach32 has been detected */ IOValue1 = inw(READ_SRC_X); outw(DESTX_DIASTP, 0xAAAAU); ProbeWaitIdleEmpty(); if (inw(READ_SRC_X) == 0x02AAU) pATI->Adapter = ATI_ADAPTER_MACH32; outw(DESTX_DIASTP, 0x5555U); ProbeWaitIdleEmpty(); if (inw(READ_SRC_X) == 0x0555U) { if (pATI->Adapter != ATI_ADAPTER_MACH32) pATI->Adapter = ATI_ADAPTER_8514A; } else { if (pATI->Adapter != ATI_ADAPTER_MACH8) pATI->Adapter = ATI_ADAPTER_8514A; } outw(DESTX_DIASTP, IOValue1); } switch (pATI->Adapter) { case ATI_ADAPTER_8514A: pATI->Coprocessor = ATI_CHIP_8514A; IOValue1 = inb(EXT_CONFIG_3); outb(EXT_CONFIG_3, IOValue1 & 0x0FU); if (!(inb(EXT_CONFIG_3) & 0xF0U)) { outb(EXT_CONFIG_3, IOValue1 | 0xF0U); if ((inb(EXT_CONFIG_3) & 0xF0U) == 0xF0U) pATI->Coprocessor = ATI_CHIP_CT480; } outb(EXT_CONFIG_3, IOValue1); break; case ATI_ADAPTER_MACH8: pATI->Coprocessor = ATI_CHIP_38800_1; if (inw(CONFIG_STATUS_1) & MC_BUS) pATI->BusType = ATI_BUS_MCA16; break; case ATI_ADAPTER_MACH32: IOValue1 = inw(CONFIG_STATUS_1); pATI->BusType = GetBits(IOValue1, BUS_TYPE); pATI->BIOSBase = 0x000C0000U + (GetBits(IOValue2, BIOS_BASE_SEGMENT) << 11); if (!(IOValue1 & (_8514_ONLY | CHIP_DIS))) { pATI->VGAAdapter = ATI_ADAPTER_MACH32; if ((xf86ReadBIOS(pATI->BIOSBase, 0x10U, (pointer)(&pATI->CPIO_VGAWonder), SizeOf(pATI->CPIO_VGAWonder)) < SizeOf(pATI->CPIO_VGAWonder)) || !(pATI->CPIO_VGAWonder &= SPARSE_IO_PORT)) pATI->CPIO_VGAWonder = 0x01CEU; pATI->VGAOffset = 0x80U; } ATIMach32ChipID(pATI); break; default: break; } return pATI; } #endif /* AVOID_CPIO */ /* * ATIDetectMach64 -- * * This function determines if a Mach64 is detectable at a particular base * address. */ static Bool ATIDetectMach64 ( ATIPtr pATI, const CARD16 ChipType, const ATIChipType Chip ) { CARD32 IOValue, bus_cntl, gen_test_cntl; (void)ATIMapApertures(-1, pATI); /* Ignore errors */ #ifdef AVOID_CPIO if (!pATI->pBlock[0]) { ATIUnmapApertures(-1, pATI); return FALSE; } #endif /* AVOID_CPIO */ /* Make sure any Mach64 is not in some weird state */ bus_cntl = inr(BUS_CNTL); if (Chip < ATI_CHIP_264VTB) outr(BUS_CNTL, (bus_cntl & ~(BUS_HOST_ERR_INT_EN | BUS_FIFO_ERR_INT_EN)) | (BUS_HOST_ERR_INT | BUS_FIFO_ERR_INT)); else if (Chip < ATI_CHIP_264VT4) outr(BUS_CNTL, (bus_cntl & ~BUS_HOST_ERR_INT_EN) | BUS_HOST_ERR_INT); gen_test_cntl = inr(GEN_TEST_CNTL); IOValue = gen_test_cntl & (GEN_OVR_OUTPUT_EN | GEN_OVR_POLARITY | GEN_CUR_EN | GEN_BLOCK_WR_EN); outr(GEN_TEST_CNTL, IOValue | GEN_GUI_EN); outr(GEN_TEST_CNTL, IOValue); outr(GEN_TEST_CNTL, IOValue | GEN_GUI_EN); /* See if a Mach64 answers */ IOValue = inr(SCRATCH_REG0); /* Test odd bits */ outr(SCRATCH_REG0, 0x55555555U); if (inr(SCRATCH_REG0) == 0x55555555U) { /* Test even bits */ outr(SCRATCH_REG0, 0xAAAAAAAAU); if (inr(SCRATCH_REG0) == 0xAAAAAAAAU) { /* * *Something* has a R/W 32-bit register at this address. Try to * make sure it's a Mach64. The following assumes that ATI will * not be producing any more adapters that do not register * themselves in PCI configuration space. */ ATIMach64ChipID(pATI, ChipType); if ((pATI->Chip != ATI_CHIP_Mach64) || (pATI->CPIODecoding == BLOCK_IO)) pATI->Adapter = ATI_ADAPTER_MACH64; } } /* Restore clobbered register value */ outr(SCRATCH_REG0, IOValue); /* If no Mach64 was detected, return now */ if (pATI->Adapter != ATI_ADAPTER_MACH64) { outr(GEN_TEST_CNTL, gen_test_cntl); outr(BUS_CNTL, bus_cntl); ATIUnmapApertures(-1, pATI); return FALSE; } /* Determine legacy BIOS address */ pATI->BIOSBase = 0x000C0000U + (GetBits(inr(SCRATCH_REG1), BIOS_BASE_SEGMENT) << 11); ATIUnmapApertures(-1, pATI); pATI->PCIInfo = NULL; return TRUE; } #ifdef AVOID_CPIO /* * ATIMach64Probe -- * * This function looks for a Mach64 at a particular MMIO address and returns an * ATIRec if one is found. */ static ATIPtr ATIMach64Probe ( pciVideoPtr pVideo, const IOADDRESS IOBase, const CARD8 IODecoding, const ATIChipType Chip ) { ATIPtr pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec)); CARD16 ChipType = 0; pATI->CPIOBase = IOBase; pATI->CPIODecoding = IODecoding; if (pVideo) { pATI->PCIInfo = pVideo; ChipType = pVideo->chipType; /* * Probe through auxiliary MMIO aperture if one exists. Because such * apertures can be enabled/disabled only through PCI, this probes no * further. */ if ((pVideo->size[2] >= 12) && (pATI->Block0Base = pVideo->memBase[2]) && (pATI->Block0Base < (CARD32)(-1 << pVideo->size[2]))) { pATI->Block0Base += 0x00000400U; goto LastProbe; } /* * Probe through the primary MMIO aperture that exists at the tail end * of the linear aperture. Test for both 8MB and 4MB linear apertures. */ if ((pVideo->size[0] >= 22) && (pATI->Block0Base = pVideo->memBase[0])) { pATI->Block0Base += 0x007FFC00U; if ((pVideo->size[0] >= 23) && ATIDetectMach64(pATI, ChipType, Chip)) return pATI; pATI->Block0Base -= 0x00400000U; if (ATIDetectMach64(pATI, ChipType, Chip)) return pATI; } } /* * A last, perhaps desparate, probe attempt. Note that if this succeeds, * there's a VGA in the system and it's likely the PIO version of the * driver should be used instead (barring OS issues). */ pATI->Block0Base = 0x000BFC00U; LastProbe: if (ATIDetectMach64(pATI, ChipType, Chip)) return pATI; xfree(pATI); return NULL; } #else /* AVOID_CPIO */ /* * ATIMach64Probe -- * * This function looks for a Mach64 at a particular PIO address and returns an * ATIRec if one is found. */ static ATIPtr ATIMach64Probe ( pciVideoPtr pVideo, const IOADDRESS IOBase, const CARD8 IODecoding, const ATIChipType Chip ) { ATIPtr pATI; CARD32 IOValue; CARD16 ChipType = 0; if (!IOBase) return NULL; if (pVideo) { if ((IODecoding == BLOCK_IO) && ((pVideo->size[1] < 8) || (IOBase >= (CARD32)(-1 << pVideo->size[1])))) return NULL; ChipType = pVideo->chipType; } pATI = (ATIPtr)xnfcalloc(1, SizeOf(ATIRec)); pATI->CPIOBase = IOBase; pATI->CPIODecoding = IODecoding; pATI->PCIInfo = pVideo; if (!ATIDetectMach64(pATI, ChipType, Chip)) { xfree(pATI); return NULL; } /* * Determine VGA capability. VGA can always be enabled on integrated * controllers. For the GX/CX, it's a board strap. */ if (pATI->Chip >= ATI_CHIP_264CT) pATI->VGAAdapter = ATI_ADAPTER_MACH64; else { IOValue = inr(CONFIG_STATUS64_0); pATI->BusType = GetBits(IOValue, CFG_BUS_TYPE); IOValue &= (CFG_VGA_EN | CFG_CHIP_EN); if (pATI->Chip == ATI_CHIP_88800CX) IOValue |= CFG_VGA_EN; if (IOValue == (CFG_VGA_EN | CFG_CHIP_EN)) { pATI->VGAAdapter = ATI_ADAPTER_MACH64; pATI->CPIO_VGAWonder = 0x01CEU; pATI->VGAOffset = 0x80U; } } return pATI; } /* * ATIAssignVGA -- * * This function is called to associate a VGA interface with an accelerator. * This is done by temporarily configuring the accelerator to route VGA RAMDAC * I/O through the accelerator's RAMDAC. A value is then written through the * VGA DAC ports and a check is made to see if the same value shows up on the * accelerator side. */ static void ATIAssignVGA ( pciVideoPtr pVideo, ATIPtr *ppVGA, ATIPtr pATI, ATIPtr p8514, CARD8 *ProbeFlags ) { ATIPtr pVGA = *ppVGA; CARD8 OldDACMask; /* Assume unassignable VGA */ pATI->VGAAdapter = ATI_ADAPTER_NONE; /* If no assignable VGA, return now */ if ((pATI != pVGA) && (!pVGA || (pVGA->Adapter > ATI_ADAPTER_VGA))) return; switch (pATI->Adapter) { case ATI_ADAPTER_8514A: { /* * Assumption: Bit DISABPASSTHRU in ADVFUNC_CNTL is already * off. */ OldDACMask = inb(VGA_DAC_MASK); if (inb(IBM_DAC_MASK) == OldDACMask) { outb(VGA_DAC_MASK, 0xA5U); if (inb(IBM_DAC_MASK) == 0xA5U) pATI->VGAAdapter = ATI_ADAPTER_VGA; } outb(VGA_DAC_MASK, OldDACMask); } break; case ATI_ADAPTER_MACH8: { CARD16 ClockSel = inw(CLOCK_SEL); if (ClockSel & DISABPASSTHRU) outw(CLOCK_SEL, ClockSel & ~DISABPASSTHRU); ProbeWaitIdleEmpty(); OldDACMask = inb(VGA_DAC_MASK); if (inb(IBM_DAC_MASK) == OldDACMask) { outb(VGA_DAC_MASK, 0xA5U); if (inb(IBM_DAC_MASK) == 0xA5U) pATI->VGAAdapter = ATI_ADAPTER_VGA; } outb(VGA_DAC_MASK, OldDACMask); if (ClockSel & DISABPASSTHRU) outw(CLOCK_SEL, ClockSel); } break; case ATI_ADAPTER_MACH32: { CARD16 ClockSel = inw(CLOCK_SEL), MiscOptions = inw(MISC_OPTIONS); if (ClockSel & DISABPASSTHRU) outw(CLOCK_SEL, ClockSel & ~DISABPASSTHRU); if (MiscOptions & (DISABLE_VGA | DISABLE_DAC)) outw(MISC_OPTIONS, MiscOptions & ~(DISABLE_VGA | DISABLE_DAC)); ProbeWaitIdleEmpty(); OldDACMask = inb(VGA_DAC_MASK); if (inb(IBM_DAC_MASK) == OldDACMask) { outb(VGA_DAC_MASK, 0xA5U); if (inb(IBM_DAC_MASK) == 0xA5U) pATI->VGAAdapter = ATI_ADAPTER_MACH32; } outb(VGA_DAC_MASK, OldDACMask); if (ClockSel & DISABPASSTHRU) outw(CLOCK_SEL, ClockSel); if (MiscOptions & (DISABLE_VGA | DISABLE_DAC)) outw(MISC_OPTIONS, MiscOptions); } break; case ATI_ADAPTER_MACH64: { CARD32 DACCntl = inr(DAC_CNTL); if (!(DACCntl & DAC_VGA_ADR_EN)) outr(DAC_CNTL, DACCntl | DAC_VGA_ADR_EN); OldDACMask = inb(VGA_DAC_MASK); if (in8(M64_DAC_MASK) == OldDACMask) { outb(VGA_DAC_MASK, 0xA5U); if (in8(M64_DAC_MASK) == 0xA5U) pATI->VGAAdapter = ATI_ADAPTER_MACH64; } outb(VGA_DAC_MASK, OldDACMask); if (!(DACCntl & DAC_VGA_ADR_EN)) outr(DAC_CNTL, DACCntl); } break; default: break; } if (pATI->VGAAdapter == ATI_ADAPTER_NONE) { pATI->CPIO_VGAWonder = 0; return; } if (pATI->CPIO_VGAWonder) { ATIVGAWonderProbe(pVideo, pATI, p8514, ProbeFlags); if (!pATI->CPIO_VGAWonder) { /* * Some adapters are reputed to append ATI extended VGA registers * to the VGA Graphics controller registers. In particular, 0x01CE * cannot, in general, be used in a PCI environment due to routing * of I/O through the bus tree. */ pATI->CPIO_VGAWonder = GRAX; ATIVGAWonderProbe(pVideo, pATI, p8514, ProbeFlags); } } if (pATI == pVGA) { pATI->SharedVGA = TRUE; return; } /* Assign the VGA to this adapter */ xfree(pVGA); *ppVGA = pATI; xf86MsgVerb(X_INFO, 3, ATI_NAME ": VGA assigned to this adapter.\n"); } /* * ATIClaimVGA -- * * Attempt to assign a non-shareable VGA to an accelerator. If successful, * update ProbeFlags array. */ static void ATIClaimVGA ( pciVideoPtr pVideo, ATIPtr *ppVGA, ATIPtr pATI, ATIPtr p8514, CARD8 *ProbeFlags, int Detected ) { ATIAssignVGA(pVideo, ppVGA, pATI, p8514, ProbeFlags); if (pATI->VGAAdapter == ATI_ADAPTER_NONE) return; ATIClaimSparseIOBases(ProbeFlags, MonochromeIOBase, 48, Detected); if (!pATI->CPIO_VGAWonder) return; ATIClaimSparseIOBases(ProbeFlags, pATI->CPIO_VGAWonder, 2, Detected); } /* * ATIFindVGA -- * * This function determines if a VGA associated with an ATI PCI adapter is * shareable. */ static void ATIFindVGA ( pciVideoPtr pVideo, ATIPtr *ppVGA, ATIPtr *ppATI, ATIPtr p8514, CARD8 *ProbeFlags ) { ATIPtr pATI = *ppATI; if (!*ppVGA) { /* * An ATI PCI adapter has been detected at this point, and its VGA, if * any, is shareable. Ensure the VGA isn't in sleep mode. */ outb(GENENA, 0x16U); outb(GENVS, 0x01U); outb(GENENA, 0x0EU); pATI = ATIVGAProbe(pATI); if (pATI->VGAAdapter == ATI_ADAPTER_NONE) return; ppVGA = ppATI; } ATIAssignVGA(pVideo, ppVGA, pATI, p8514, ProbeFlags); } #endif /* AVOID_CPIO */ /* * ATIProbe -- * * This function is called once, at the start of the first server generation to * do a minimal probe for supported hardware. */ Bool ATIProbe ( DriverPtr pDriver, int flags ) { ATIPtr pATI, *ATIPtrs = NULL; GDevPtr *GDevs, pGDev; pciVideoPtr pVideo, *xf86PciVideoInfo = xf86GetPciVideoInfo(); pciConfigPtr pPCI; ATIGDev *ATIGDevs = NULL, *pATIGDev; ScrnInfoPtr pScreenInfo; CARD32 PciReg; Bool ProbeSuccess = FALSE; Bool DoRage128 = FALSE, DoRadeon = FALSE; int i, j, k; int nGDev, nATIGDev = -1, nATIPtr = 0; int Chipset; ATIChipType Chip; #ifndef AVOID_CPIO ATIPtr pVGA = NULL, p8514 = NULL; ATIPtr pMach64[3] = {NULL, NULL, NULL}; pciConfigPtr *xf86PciInfo = xf86GetPciConfigInfo(); PortPtr PCIPorts = NULL; int nPCIPort = 0; CARD8 fChipsets[ATI_CHIPSET_MAX]; static const IOADDRESS Mach64SparseIOBases[] = {0x02ECU, 0x01CCU, 0x01C8U}; CARD8 ProbeFlags[LongPort(SPARSE_IO_BASE) + 1]; unsigned long BIOSBase; static const CARD8 ATISignature[] = " 761295520"; # define SignatureSize 10 # define PrefixSize 0x50U # define BIOSSignature 0x30U CARD8 BIOS[PrefixSize]; # define BIOSWord(_n) (BIOS[_n] | (BIOS[(_n) + 1] << 8)) #endif /* AVOID_CPIO */ # define AddAdapter(_p) \ do \ { \ nATIPtr++; \ ATIPtrs = (ATIPtr *)xnfrealloc(ATIPtrs, SizeOf(ATIPtr) * nATIPtr); \ ATIPtrs[nATIPtr - 1] = (_p); \ (_p)->iEntity = -2; \ } while (0) #ifndef AVOID_CPIO (void)memset(fChipsets, FALSE, SizeOf(fChipsets)); #endif /* AVOID_CPIO */ if (!(flags & PROBE_DETECT)) { /* * Get a list of XF86Config device sections whose "Driver" is either * not specified, or specified as this driver. From this list, * eliminate those device sections that specify a "Chipset" or a * "ChipID" not recognised by the driver. Those device sections that * specify a "ChipRev" without a "ChipID" are also weeded out. */ nATIGDev = 0; if ((nGDev = xf86MatchDevice(ATI_NAME, &GDevs)) > 0) { ATIGDevs = (ATIGDevPtr)xnfcalloc(nGDev, SizeOf(ATIGDev)); for (i = 0, pATIGDev = ATIGDevs; i < nGDev; i++) { pGDev = GDevs[i]; Chipset = ATIIdentProbe(pGDev->chipset); if (Chipset == -1) continue; if ((pGDev->chipID > (int)((CARD16)(-1))) || (pGDev->chipRev > (int)((CARD8)(-1)))) continue; if (pGDev->chipID >= 0) { if (ATIChipID(pGDev->chipID, 0) == ATI_CHIP_Mach64) continue; } else { if (pGDev->chipRev >= 0) continue; } pATIGDev->pGDev = pGDev; pATIGDev->Chipset = Chipset; nATIGDev++; pATIGDev++; xf86MsgVerb(X_INFO, 3, ATI_NAME ": Candidate \"Device\" section \"%s\".\n", pGDev->identifier); #ifndef AVOID_CPIO fChipsets[Chipset] = TRUE; #endif /* AVOID_CPIO */ } xfree(GDevs); if (!nATIGDev) { xfree(ATIGDevs); ATIGDevs = NULL; } } if (xf86MatchDevice(R128_NAME, NULL) > 0) DoRage128 = TRUE; if (xf86MatchDevice(RADEON_NAME, NULL) > 0) DoRadeon = TRUE; } #ifndef AVOID_CPIO /* * Collect hardware information. This must be done with care to avoid * lockups due to overlapping I/O port assignments. * * First, scan PCI configuration space for registered I/O ports (which will * be block I/O bases). Each such port is used to generate a list of * sparse I/O bases it precludes. This list is then used to decide whether * or not certain sparse I/O probes are done. Unfortunately, this assumes * that any registered I/O base actually reserves upto the full 256 ports * allowed by the PCI specification. This assumption holds true for PCI * Mach64, but probably doesn't for other device types. For some things, * such as video devices, the number of ports a base represents is * determined by the server's PCI probe, but, for other devices, this * cannot be done by a user-level process without jeopardizing system * integrity. This information should ideally be retrieved from the OS's * own PCI probe (if any), but there's currently no portable way of doing * so. The following allows sparse I/O probes to be forced in certain * circumstances when an appropriate chipset specification is used in any * XF86Config Device section. * * Note that this is not bullet-proof. Lockups can still occur, but they * will usually be due to devices that are misconfigured to respond to the * same I/O ports as 8514/A's or ATI sparse I/O devices without registering * them in PCI configuration space. */ if (nATIGDev) { if (xf86PciVideoInfo) { for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) { if (pVideo->vendor == PCI_VENDOR_ATI) continue; pPCI = pVideo->thisCard; ATIScanPCIBases(&PCIPorts, &nPCIPort, &pPCI->pci_base0, pVideo->size, (pciReadLong(pPCI->tag, PCI_CMD_STAT_REG) & PCI_CMD_IO_ENABLE) ? 0 : Allowed); } } /* Check non-video PCI devices for I/O bases */ if (xf86PciInfo) { for (i = 0; (pPCI = xf86PciInfo[i++]); ) { if ((pPCI->pci_vendor == PCI_VENDOR_ATI) || (pPCI->pci_base_class == PCI_CLASS_BRIDGE) || (pPCI->pci_header_type & ~GetByte(PCI_HEADER_MULTIFUNCTION, 2))) continue; ATIScanPCIBases(&PCIPorts, &nPCIPort, &pPCI->pci_base0, pPCI->basesize, (pciReadLong(pPCI->tag, PCI_CMD_STAT_REG) & PCI_CMD_IO_ENABLE) ? 0 : Allowed); } } /* Generate ProbeFlags array from list of registered PCI I/O bases */ (void)memset(ProbeFlags, Allowed | DoProbe, SizeOf(ProbeFlags)); for (i = 0; i < nPCIPort; i++) { CARD32 Base = PCIPorts[i].Base; CARD16 Count = (1 << PCIPorts[i].Size) - 1; CARD8 ProbeFlag = PCIPorts[i].Flag; /* * The following reduction of Count is based on the assumption that * PCI-registered I/O port ranges do not overlap. */ for (j = 0; j < nPCIPort; j++) { CARD32 Base2 = PCIPorts[j].Base; if (Base < Base2) while ((Base + Count) >= Base2) Count >>= 1; } Base = LongPort(Base); Count = LongPort((Count | IO_BYTE_SELECT) + 1); while (Count--) ProbeFlags[Base++] &= ProbeFlag; } xfree(PCIPorts); /* * A note on probe strategy. I/O and memory response by certain PCI * devices has been disabled by the common layer at this point, * including any devices this driver might be interested in. The * following does sparse I/O probes, followed by block I/O probes. * Block I/O probes are dictated by what is found to be of interest in * PCI configuration space. All this will detect ATI adapters that do * not implement this disablement, pre-PCI or not. * * PCI configuration space is then scanned again for ATI devices that * failed to be detected the first time around. Each such device is * probed for again, this time with I/O temporarily enabled through * PCI. */ if (ATICheckSparseIOBases(NULL, ProbeFlags, ATTRX, 16, TRUE) == DoProbe) { pATI = ATIVGAProbe(NULL); if (pATI->Adapter == ATI_ADAPTER_NONE) { xfree(pATI); xf86MsgVerb(X_INFO, 4, ATI_NAME ": Unshared VGA not detected.\n"); } else { /* * Claim all MDA/HGA/CGA/EGA/VGA I/O ports. This might need to * be more selective. */ ATIClaimSparseIOBases(ProbeFlags, MonochromeIOBase, 48, DetectedVGA); pVGA = pATI; strcpy(Identifier, "Unshared VGA"); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier); } } else { xf86MsgVerb(X_INFO, 2, ATI_NAME ": Unshared VGA not probed.\n"); } if (ATICheckSparseIOBases(NULL, ProbeFlags, 0x02E8U, 8, fChipsets[ATI_CHIPSET_IBM8514] || fChipsets[ATI_CHIPSET_MACH8] || fChipsets[ATI_CHIPSET_MACH32]) == DoProbe) { if ((pATI = ATI8514Probe(NULL))) { strcpy(Identifier, "Unshared 8514/A"); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier); AddAdapter(p8514 = pATI); if ((pATI->VGAAdapter != ATI_ADAPTER_NONE) || (pATI->Coprocessor != ATI_CHIP_NONE)) ATIClaimVGA(NULL, &pVGA, pATI, p8514, ProbeFlags, Detected8514A); ATIClaimSparseIOBases(ProbeFlags, 0x02E8U, 8, Detected8514A); } else { xf86MsgVerb(X_INFO, 4, ATI_NAME ": Unshared 8514/A not detected.\n"); } } else { xf86MsgVerb(X_INFO, 2, ATI_NAME ": Unshared 8514/A not probed.\n"); } for (i = 0; i < NumberOf(Mach64SparseIOBases); i++) { if (ATICheckSparseIOBases(NULL, ProbeFlags, Mach64SparseIOBases[i], 4, fChipsets[ATI_CHIPSET_MACH64]) != DoProbe) { xf86MsgVerb(X_INFO, 2, ATI_NAME ": Unshared Mach64 at PIO base 0x%04X not" " probed.\n", Mach64SparseIOBases[i]); continue; } pATI = ATIMach64Probe(NULL, Mach64SparseIOBases[i], SPARSE_IO, 0); if (!pATI) { xf86MsgVerb(X_INFO, 4, ATI_NAME ": Unshared Mach64 at PIO base 0x%04X not" " detected.\n", Mach64SparseIOBases[i]); continue; } sprintf(Identifier, "Unshared Mach64 at sparse PIO base 0x%04lX", Mach64SparseIOBases[i]); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier); AddAdapter(pMach64[i] = pATI); if (pATI->VGAAdapter != ATI_ADAPTER_NONE) ATIClaimVGA(NULL, &pVGA, pATI, p8514, ProbeFlags, DetectedMach64); ATIClaimSparseIOBases(ProbeFlags, Mach64SparseIOBases[i], 4, DetectedMach64); } } #endif /* AVOID_CPIO */ if (xf86PciVideoInfo) { if (nATIGDev) { #ifndef AVOID_NON_PCI #ifdef AVOID_CPIO /* PCI sparse I/O adapters can still be used through MMIO */ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) { if ((pVideo->vendor != PCI_VENDOR_ATI) || (pVideo->chipType == PCI_CHIP_MACH32) || pVideo->size[1]) continue; pPCI = pVideo->thisCard; PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG); /* Possibly fix block I/O indicator */ if (PciReg & 0x00000004U) pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG, PciReg & ~0x00000004U); Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); /* * The CPIO base used by the adapter is of little concern here. */ pATI = ATIMach64Probe(pVideo, 0, SPARSE_IO, Chip); if (!pATI) continue; sprintf(Identifier, "Unshared PCI sparse I/O Mach64 in slot %d:%d:%d", pVideo->bus, pVideo->device, pVideo->func); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected through Block 0 at 0x%08X.\n", Identifier, pATI->Block0Base); AddAdapter(pATI); pATI->PCIInfo = pVideo; } #endif /* AVOID_CPIO */ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) { if ((pVideo->vendor != PCI_VENDOR_ATI) || (pVideo->chipType == PCI_CHIP_MACH32) || !pVideo->size[1]) continue; /* For now, ignore Rage128's and Radeon's */ Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); if (Chip > ATI_CHIP_Mach64) continue; pPCI = pVideo->thisCard; /* * Possibly fix block I/O indicator in PCI configuration space. */ PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG); if (!(PciReg & 0x00000004U)) pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG, PciReg | 0x00000004U); pATI = ATIMach64Probe(pVideo, pVideo->ioBase[1], BLOCK_IO, Chip); if (!pATI) continue; sprintf(Identifier, "Unshared PCI/AGP Mach64 in slot %d:%d:%d", pVideo->bus, pVideo->device, pVideo->func); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier); AddAdapter(pATI); #ifndef AVOID_CPIO /* This is probably not necessary */ if (pATI->VGAAdapter != ATI_ADAPTER_NONE) ATIClaimVGA(pVideo, &pVGA, pATI, p8514, ProbeFlags, DetectedMach64); #endif /* AVOID_CPIO */ } #endif /* AVOID_NON_PCI */ #ifndef AVOID_CPIO /* * This is the second pass through PCI configuration space. Much * of this is verbiage to deal with potential situations that are * very unlikely to occur in practice. * * First, look for non-ATI shareable VGA's. For now, these must * the primary device. */ if (ATICheckSparseIOBases(NULL, ProbeFlags, ATTRX, 16, TRUE) == DoProbe) { for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) { if ((pVideo->vendor == PCI_VENDOR_ATI) || !xf86IsPrimaryPci(pVideo)) continue; if (!xf86CheckPciSlot(pVideo->bus, pVideo->device, pVideo->func)) continue; xf86SetPciVideo(pVideo, MEM_IO); pATI = ATIVGAProbe(NULL); if (pATI->Adapter == ATI_ADAPTER_NONE) { xfree(pATI); xf86Msg(X_WARNING, ATI_NAME ": PCI/AGP VGA compatible in slot" " %d:%d:%d could not be detected!\n", pVideo->bus, pVideo->device, pVideo->func); } else { sprintf(Identifier, "Shared non-ATI VGA in PCI/AGP slot %d:%d:%d", pVideo->bus, pVideo->device, pVideo->func); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier); AddAdapter(pATI); pATI->SharedVGA = TRUE; pATI->BusType = ATI_BUS_PCI; pATI->PCIInfo = pVideo; } xf86SetPciVideo(NULL, NONE); } } /* Next, look for PCI Mach32's */ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) { if ((pVideo->vendor != PCI_VENDOR_ATI) || (pVideo->chipType != PCI_CHIP_MACH32)) continue; switch (ATICheckSparseIOBases(pVideo, ProbeFlags, 0x02E8U, 8, TRUE)) { case 0: xf86Msg(X_WARNING, ATI_NAME ": PCI Mach32 in slot %d:%d:%d will not" " be enabled\n because it conflicts with a" " non-video PCI/AGP device.\n", pVideo->bus, pVideo->device, pVideo->func); break; case Detected8514A: if ((p8514->BusType >= ATI_BUS_PCI) && !p8514->PCIInfo) p8514->PCIInfo = pVideo; else xf86Msg(X_WARNING, ATI_NAME ": PCI Mach32 in slot %d:%d:%d will" " not be enabled\n because it conflicts with" " another %s %s.\n", pVideo->bus, pVideo->device, pVideo->func, ATIBusNames[p8514->BusType], ATIAdapterNames[p8514->Adapter]); break; case DetectedMach64: xf86Msg(X_WARNING, ATI_NAME ": PCI Mach32 in slot %d:%d:%d will not" " be enabled\n because it conflicts with a Mach64" " at I/O base 0x02EC.\n", pVideo->bus, pVideo->device, pVideo->func); break; default: /* Must be DoProbe */ if (!xf86CheckPciSlot(pVideo->bus, pVideo->device, pVideo->func)) continue; xf86SetPciVideo(pVideo, MEM_IO); if (!(pATI = ATI8514Probe(pVideo))) xf86Msg(X_WARNING, ATI_NAME ": PCI Mach32 in slot %d:%d:%d could" " not be detected!\n", pVideo->bus, pVideo->device, pVideo->func); else { sprintf(Identifier, "Shared 8514/A in PCI slot %d:%d:%d", pVideo->bus, pVideo->device, pVideo->func); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier); if (pATI->Adapter != ATI_ADAPTER_MACH32) xf86Msg(X_WARNING, ATI_NAME ": PCI Mach32 in slot %d:%d:%d" " could only be detected as an %s!\n", pVideo->bus, pVideo->device, pVideo->func, ATIAdapterNames[pATI->Adapter]); AddAdapter(pATI); pATI->SharedAccelerator = TRUE; if ((pATI->VGAAdapter != ATI_ADAPTER_NONE) || (pATI->Coprocessor != ATI_CHIP_NONE)) ATIFindVGA(pVideo, &pVGA, &pATI, p8514, ProbeFlags); } xf86SetPciVideo(NULL, NONE); break; } } /* Next, look for sparse I/O Mach64's */ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) { if ((pVideo->vendor != PCI_VENDOR_ATI) || (pVideo->chipType == PCI_CHIP_MACH32) || pVideo->size[1]) continue; pPCI = pVideo->thisCard; PciReg = pciReadLong(pPCI->tag, PCI_REG_USERCONFIG); j = PciReg & 0x03U; if (j == 0x03U) xf86Msg(X_WARNING, ATI_NAME ": PCI Mach64 in slot %d:%d:%d cannot be" " enabled\n because it has neither a block, nor a" " sparse, I/O base.\n", pVideo->bus, pVideo->device, pVideo->func); else switch(ATICheckSparseIOBases(pVideo, ProbeFlags, Mach64SparseIOBases[j], 4, TRUE)) { case 0: xf86Msg(X_WARNING, ATI_NAME ": PCI Mach64 in slot %d:%d:%d will not" " be enabled\n because it conflicts with another" " non-video PCI device.\n", pVideo->bus, pVideo->device, pVideo->func); break; case Detected8514A: xf86Msg(X_WARNING, ATI_NAME ": PCI Mach64 in slot %d:%d:%d will not" " be enabled\n because it conflicts with an %s.\n", pVideo->bus, pVideo->device, pVideo->func, ATIAdapterNames[p8514->Adapter]); break; case DetectedMach64: pATI = pMach64[j]; if ((pATI->BusType >= ATI_BUS_PCI) && !pATI->PCIInfo) pATI->PCIInfo = pVideo; else xf86Msg(X_WARNING, ATI_NAME ": PCI Mach64 in slot %d:%d:%d will" " not be enabled\n because it conflicts with" " another %s Mach64 at sparse I/O base" " 0x%04X.\n", pVideo->bus, pVideo->device, pVideo->func, ATIBusNames[pATI->BusType], Mach64SparseIOBases[j]); break; default: /* Must be DoProbe */ if (!xf86CheckPciSlot(pVideo->bus, pVideo->device, pVideo->func)) continue; /* Possibly fix block I/O indicator */ if (PciReg & 0x00000004U) pciWriteLong(pPCI->tag, PCI_REG_USERCONFIG, PciReg & ~0x00000004U); xf86SetPciVideo(pVideo, MEM_IO); Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); pATI = ATIMach64Probe(pVideo, Mach64SparseIOBases[j], SPARSE_IO, Chip); if (!pATI) xf86Msg(X_WARNING, ATI_NAME ": PCI Mach64 in slot %d:%d:%d could" " not be detected!\n", pVideo->bus, pVideo->device, pVideo->func); else { sprintf(Identifier, "Shared PCI Mach64 in slot %d:%d:%d", pVideo->bus, pVideo->device, pVideo->func); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s with sparse PIO base 0x%04X" " detected.\n", Identifier, Mach64SparseIOBases[j]); AddAdapter(pATI); pATI->SharedAccelerator = TRUE; pATI->PCIInfo = pVideo; if (pATI->VGAAdapter != ATI_ADAPTER_NONE) ATIFindVGA(pVideo, &pVGA, &pATI, p8514, ProbeFlags); } xf86SetPciVideo(NULL, NONE); break; } } #else /* AVOID_CPIO */ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) { if ((pVideo->vendor != PCI_VENDOR_ATI) || (pVideo->chipType == PCI_CHIP_MACH32) || pVideo->size[1]) continue; /* Check if this one has already been detected */ for (j = 0; j < nATIPtr; j++) { pATI = ATIPtrs[j]; if (pATI->PCIInfo == pVideo) goto SkipThisSlot; } if (!xf86CheckPciSlot(pVideo->bus, pVideo->device, pVideo->func)) continue; xf86SetPciVideo(pVideo, MEM_IO); Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); /* The adapter's CPIO base is of little concern here */ pATI = ATIMach64Probe(pVideo, 0, SPARSE_IO, Chip); if (pATI) { sprintf(Identifier, "Shared PCI Mach64 in slot %d:%d:%d", pVideo->bus, pVideo->device, pVideo->func); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s with Block 0 base 0x%08X detected.\n", Identifier, pATI->Block0Base); AddAdapter(pATI); pATI->SharedAccelerator = TRUE; pATI->PCIInfo = pVideo; } else { xf86Msg(X_WARNING, ATI_NAME ": PCI Mach64 in slot %d:%d:%d could not be" " detected!\n", pVideo->bus, pVideo->device, pVideo->func); } xf86SetPciVideo(NULL, NONE); SkipThisSlot:; } #endif /* AVOID_CPIO */ } /* Lastly, look for block I/O devices */ for (i = 0; (pVideo = xf86PciVideoInfo[i++]); ) { if ((pVideo->vendor != PCI_VENDOR_ATI) || (pVideo->chipType == PCI_CHIP_MACH32) || !pVideo->size[1]) continue; /* Check for Rage128's, Radeon's and later adapters */ Chip = ATIChipID(pVideo->chipType, pVideo->chipRev); if (Chip > ATI_CHIP_Mach64) { switch (Chip) { case ATI_CHIP_RAGE128GL: case ATI_CHIP_RAGE128VR: case ATI_CHIP_RAGE128PROULTRA: case ATI_CHIP_RAGE128PROGL: case ATI_CHIP_RAGE128PROVR: case ATI_CHIP_RAGE128MOBILITY3: case ATI_CHIP_RAGE128MOBILITY4: DoRage128 = TRUE; continue; case ATI_CHIP_RADEON: case ATI_CHIP_RADEONVE: case ATI_CHIP_RADEONMOBILITY6: case ATI_CHIP_RADEONMOBILITY7: case ATI_CHIP_R200: case ATI_CHIP_RV200: case ATI_CHIP_RV250: case ATI_CHIP_RADEONMOBILITY9: case ATI_CHIP_R300: DoRadeon = TRUE; continue; case ATI_CHIP_HDTV: default: continue; } } if (!nATIGDev) continue; /* Check if this one has already been detected */ for (j = 0; j < nATIPtr; j++) { pATI = ATIPtrs[j]; if (pATI->CPIOBase == pVideo->ioBase[1]) goto SetPCIInfo; } if (!xf86CheckPciSlot(pVideo->bus, pVideo->device, pVideo->func)) continue; /* Probe for it */ xf86SetPciVideo(pVideo, MEM_IO); pATI = ATIMach64Probe(pVideo, pVideo->ioBase[1], BLOCK_IO, Chip); if (pATI) { sprintf(Identifier, "Shared PCI/AGP Mach64 in slot %d:%d:%d", pVideo->bus, pVideo->device, pVideo->func); xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s detected.\n", Identifier); AddAdapter(pATI); pATI->SharedAccelerator = TRUE; #ifndef AVOID_CPIO if (pATI->VGAAdapter != ATI_ADAPTER_NONE) ATIFindVGA(pVideo, &pVGA, &pATI, p8514, ProbeFlags); #endif /* AVOID_CPIO */ } xf86SetPciVideo(NULL, NONE); if (!pATI) { xf86Msg(X_WARNING, ATI_NAME ": PCI/AGP Mach64 in slot %d:%d:%d could not be" " detected!\n", pVideo->bus, pVideo->device, pVideo->func); continue; } SetPCIInfo: pATI->PCIInfo = pVideo; } } #ifndef AVOID_CPIO /* * At this point, if there's a non-shareable VGA with its own framebuffer, * find out if it's an ATI VGA Wonder. */ do { if (!nATIGDev || !pVGA || (pVGA->VGAAdapter > ATI_ADAPTER_VGA)) break; /* If it has not been assigned to a coprocessor, keep track of it */ if (pVGA->Coprocessor == ATI_CHIP_NONE) AddAdapter(pVGA); /* * A VGA should have installed its int 10 vector. Use that to find the * VGA BIOS. If this fails, scan all legacy BIOS segments, in 512-byte * increments. */ if (xf86ReadBIOS(0U, 0x42U, BIOS, 2) != 2) goto NoVGAWonder; pATI = NULL; BIOSBase = 0; if (!(BIOS[0] & 0x1FU)) /* Otherwise there's no 512-byte alignment */ BIOSBase = ((BIOS[1] << 8) | BIOS[0]) << 4; /* Look for its BIOS */ for(; ; BIOSBase += 0x00000200U) { if (!BIOSBase) goto SkipBiosSegment; if (BIOSBase >= 0x000F8000U) goto NoVGAWonder; /* Skip over those that are already known */ for (i = 0; i < nATIPtr; i++) if (ATIPtrs[i]->BIOSBase == BIOSBase) goto SkipBiosSegment; /* Get first 80 bytes of video BIOS */ if (xf86ReadBIOS(BIOSBase, 0, BIOS, SizeOf(BIOS)) != SizeOf(BIOS)) goto NoVGAWonder; if ((BIOS[0x00U] != 0x55U) || (BIOS[0x01U] != 0xAAU)) goto SkipBiosSegment; if ((BIOS[0x1EU] == 'I') && (BIOS[0x1FU] == 'B') && (BIOS[0x20U] == 'M')) break; /* XXX Should PCI BIOS signature be checked for here ? */ if ((BIOS[0x20U] == 'P') && (BIOS[0x21U] == 'C') && (BIOS[0x22U] == 'I')) break; SkipBiosSegment: if (pATI) continue; pATI = pVGA; BIOSBase = 0x000C0000U - 0x00000200U; } pVGA->BIOSBase = BIOSBase; /* Look for the ATI signature string */ if (memcmp(BIOS + BIOSSignature, ATISignature, SignatureSize)) break; if (BIOS[0x40U] != '3') break; switch (BIOS[0x41U]) { case '1': /* This is a Mach8 or VGA Wonder adapter of some kind */ if ((BIOS[0x43U] >= '1') && (BIOS[0x43U] <= '6')) pVGA->Chip = BIOS[0x43U] - ('1' - ATI_CHIP_18800); switch (BIOS[0x43U]) { case '1': /* ATI_CHIP_18800 */ pVGA->VGAOffset = 0xB0U; pVGA->VGAAdapter = ATI_ADAPTER_V3; break; case '2': /* ATI_CHIP_18800_1 */ pVGA->VGAOffset = 0xB0U; if (BIOS[0x42U] & 0x10U) pVGA->VGAAdapter = ATI_ADAPTER_V5; else pVGA->VGAAdapter = ATI_ADAPTER_V4; break; case '3': /* ATI_CHIP_28800_2 */ case '4': /* ATI_CHIP_28800_4 */ case '5': /* ATI_CHIP_28800_5 */ case '6': /* ATI_CHIP_28800_6 */ pVGA->VGAOffset = 0xA0U; if (BIOS[0x44U] & 0x80U) pVGA->VGAAdapter = ATI_ADAPTER_XL; else pVGA->VGAAdapter = ATI_ADAPTER_PLUS; break; case 'a': /* A crippled Mach32 */ case 'b': case 'c': pVGA->VGAOffset = 0x80U; pVGA->VGAAdapter = ATI_ADAPTER_NONISA; ATIMach32ChipID(pVGA); ProbeWaitIdleEmpty(); if (inw(SUBSYS_STAT) != (CARD16)(-1)) pVGA->ChipHasSUBSYS_CNTL = TRUE; break; #if 0 case ' ': /* A crippled Mach64 */ pVGA->VGAOffset = 0x80U; pVGA->VGAAdapter = ATI_ADAPTER_NONISA; ATIMach64ChipID(pVGA, 0); break; #endif default: break; } if (pVGA->VGAAdapter == ATI_ADAPTER_NONE) break; /* Set VGA Wonder I/O port */ pVGA->CPIO_VGAWonder = BIOSWord(0x10U) & SPARSE_IO_PORT; if (!pVGA->CPIO_VGAWonder) pVGA->CPIO_VGAWonder = 0x01CEU; ATIVGAWonderProbe(NULL, pVGA, p8514, ProbeFlags); break; #if 0 case '2': pVGA->VGAOffset = 0xB0U; /* Presumably */ pVGA->VGAAdapter = ATI_ADAPTER_EGA_PLUS; break; case '3': pVGA->VGAOffset = 0xB0U; /* Presumably */ pVGA->VGAAdapter = ATI_ADAPTER_BASIC; break; case '?': /* A crippled Mach64 */ pVGA->VGAAdapter = ATI_ADAPTER_NONISA; ATIMach64ChipID(pVGA, 0); break; #endif default: break; } if (pVGA->Adapter <= ATI_ADAPTER_VGA) pVGA->Adapter = pVGA->VGAAdapter; NoVGAWonder:; } while (0); #endif /* AVOID_CPIO */ /* * Re-order list of detected devices so that the primary device is before * any other PCI device. */ for (i = 0; i < nATIPtr; i++) { if (!ATIPtrs[i]->PCIInfo) continue; for (j = i; j < nATIPtr; j++) { pATI = ATIPtrs[j]; if (!xf86IsPrimaryPci(pATI->PCIInfo)) continue; for (; j > i; j--) ATIPtrs[j] = ATIPtrs[j - 1]; ATIPtrs[j] = pATI; break; } break; } if (flags & PROBE_DETECT) { /* * No XF86Config information available, so use the default Chipset of * "ati", and as many device sections as there are adapters. */ for (i = 0; i < nATIPtr; i++) { pATI = ATIPtrs[i]; #ifndef AVOID_CPIO if ((pATI->Adapter != ATI_ADAPTER_VGA) && ((pATI->Adapter != ATI_ADAPTER_8514A) || ((pATI->VGAAdapter != ATI_ADAPTER_VGA) && (pATI->VGAAdapter != ATI_ADAPTER_NONE)))) #endif /* AVOID_CPIO */ { ProbeSuccess = TRUE; pGDev = xf86AddDeviceToConfigure(ATI_DRIVER_NAME, pATI->PCIInfo, ATI_CHIPSET_ATI); if (pGDev) { /* Fill in additional information */ pGDev->vendor = ATI_NAME; pGDev->chipset = (char *)ATIChipsetNames[ATI_CHIPSET_ATI]; if (!pATI->PCIInfo) pGDev->busID = NULL; } } xfree(pATI); } } else { /* * Assign detected devices to XF86Config Device sections. This is done * by comparing certain Device section specifications against the * corresponding adapter information. Begin with those specifications * that are independent of the adapter's bus location. */ for (i = 0, pATIGDev = ATIGDevs; i < nATIGDev; i++, pATIGDev++) { pGDev = pATIGDev->pGDev; for (j = 0; j < nATIPtr; j++) { pATI = ATIPtrs[j]; /* * First check the Chipset specification. The placement of * "break" and "continue" statements here is carefully chosen * to produce the intended behaviour for each Chipset value. */ switch (pATIGDev->Chipset) { case ATI_CHIPSET_ATI: #ifndef AVOID_CPIO if (pATI->Adapter == ATI_ADAPTER_VGA) continue; if (pATI->Adapter != ATI_ADAPTER_8514A) break; /* Fall through */ case ATI_CHIPSET_ATIVGA: if (pATI->VGAAdapter == ATI_ADAPTER_VGA) continue; /* Fall through */ case ATI_CHIPSET_IBMVGA: if (pATI->VGAAdapter == ATI_ADAPTER_NONE) continue; break; case ATI_CHIPSET_VGAWONDER: if (!pATI->CPIO_VGAWonder) continue; break; case ATI_CHIPSET_IBM8514: if (pATI->Adapter == ATI_ADAPTER_8514A) break; /* Fall through */ case ATI_CHIPSET_MACH8: if (pATI->Adapter == ATI_ADAPTER_MACH8) break; /* Fall through */ case ATI_CHIPSET_MACH32: if (pATI->Adapter == ATI_ADAPTER_MACH32) break; continue; #endif /* AVOID_CPIO */ case ATI_CHIPSET_MACH64: if (pATI->Adapter == ATI_ADAPTER_MACH64) break; continue; default: continue; } /* * The ChipID and ChipRev specifications are compared next. * First, require these to be unspecified for anything other * than Mach32 or Mach64 adapters. ChipRev is also required to * be unspecified for Mach32's. ChipID is optional for * Mach32's, and both specifications are optional for Mach64's. * Lastly, allow both specifications to override their detected * value in the case of Mach64 adapters whose ChipID is * unrecognised. */ pVideo = pATI->PCIInfo; if (pGDev->chipID >= 0) { if ((pATI->ChipType != pGDev->chipID) && (!pVideo || (pGDev->chipID != pVideo->chipType))) { if ((pATI->Adapter != ATI_ADAPTER_MACH64) || (pATI->Chip != ATI_CHIP_Mach64)) continue; Chip = ATIChipID(pGDev->chipID, 0); if ((Chip <= ATI_CHIP_264GTB) || (Chip == ATI_CHIP_Mach64)) continue; } if ((pGDev->chipRev >= 0) && (pATI->ChipRev != pGDev->chipRev) && (!pVideo || (pGDev->chipRev != pVideo->chipRev) || (pGDev->chipID != pVideo->chipType))) { if (pATI->Chip < ATI_CHIP_264CT) continue; if (pATI->Chip != ATI_CHIP_Mach64) { /* * There are two foundry codes for UMC. Some * adapters will advertise one in CONFIG_CHIP_ID * and the other in PCI configuration space. For * matching purposes, make both codes compare * equal. */ # define UMC_IGNORE \ (ATI_FOUNDRY_UMC ^ ATI_FOUNDRY_UMCA) # define UMC_NOCARE \ GetBits(SetBits(UMC_IGNORE, CFG_CHIP_FOUNDRY), \ CFG_CHIP_REV) if ((pATI->ChipRev ^ pGDev->chipRev) & ~UMC_NOCARE) continue; if ((pATI->ChipFoundry != ATI_FOUNDRY_UMC) && (pATI->ChipFoundry != ATI_FOUNDRY_UMCA)) continue; k = GetBits(pGDev->chipRev, GetBits(CFG_CHIP_FOUNDRY, CFG_CHIP_REV)); if ((k != ATI_FOUNDRY_UMC) && (k != ATI_FOUNDRY_UMCA)) continue; } } } /* * IOBase is next. This is the first specification that is * potentially dependent on bus location. It is only allowed * for Mach64 adapters, and is optional. */ if (pGDev->IOBase && (pATI->CPIOBase != pGDev->IOBase)) continue; /* * Compare BusID's. This specification is only allowed for PCI * Mach32's or Mach64's and is optional. */ if (pGDev->busID && pGDev->busID[0]) { pVideo = pATI->PCIInfo; #ifndef AVOID_CPIO if (!pVideo) continue; #endif /* AVOID_CPIO */ if (!xf86ComparePciBusString(pGDev->busID, pVideo->bus, pVideo->device, pVideo->func)) continue; } /* * Ensure no two adapters are assigned to the same XF86Config * Device section. */ if (pATIGDev->iATIPtr) { if (pATIGDev->iATIPtr < 0) break; xf86Msg(X_ERROR, ATI_NAME ": XF86Config Device section \"%s\" may not" " be assigned to more than one adapter.\n", pGDev->identifier); pATIGDev->iATIPtr = -1; break; } /* Assign adapter */ pATIGDev->iATIPtr = j + 1; /* * For compatibility with previous releases, assign the first * applicable adapter if there is only one Device section. */ if (nATIGDev == 1) break; } } /* * Ensure no two XF86Config Device sections are assigned to the same * adapter. Then, generate screens for any that are left. */ for (i = 0, pATIGDev = ATIGDevs; i < nATIGDev; i++, pATIGDev++) { pGDev = pATIGDev->pGDev; j = pATIGDev->iATIPtr; if (j <= 0) continue; for (k = i; ++k < nATIGDev; ) { if (j == ATIGDevs[k].iATIPtr) { xf86Msg(X_ERROR, ATI_NAME ": XF86Config Device sections \"%s\" and" " \"%s\" may not be assigned to the same adapter.\n", pGDev->identifier, ATIGDevs[k].pGDev->identifier); pATIGDev->iATIPtr = ATIGDevs[k].iATIPtr = -1; } } j = ATIGDevs[i].iATIPtr; if (j <= 0) continue; pATI = ATIPtrs[j - 1]; xf86MsgVerb(X_INFO, 3, ATI_NAME ": %s assigned to %sactive \"Device\" section" " \"%s\".\n", Identifier, pGDev->active ? "" : "in", pGDev->identifier); /* * Attach adapter to XF86Config Device section and register its * resources. */ if (ATIClaimBusSlot(pDriver, pATIGDev->Chipset, pGDev, pGDev->active, pATI) < 0) { xf86Msg(X_ERROR, ATI_NAME ": Could not claim bus slot for %s.\n", Identifier); continue; } if (!pGDev->active) continue; /* Allocate screen */ pScreenInfo = xf86AllocateScreen(pDriver, 0); #ifdef XFree86LOADER if (!xf86LoadSubModule(pScreenInfo, "atimisc")) { xf86Msg(X_ERROR, ATI_NAME ": Failed to load \"atimisc\" module.\n"); xf86DeleteScreen(pScreenInfo->scrnIndex, 0); continue; } xf86LoaderReqSymLists(ATISymbols, NULL); #endif /* Attach device to screen */ xf86AddEntityToScreen(pScreenInfo, pATI->iEntity); ATIPtrs[j - 1] = NULL; /* Fill in probe data */ pScreenInfo->driverVersion = ATI_VERSION_CURRENT; pScreenInfo->driverName = ATI_DRIVER_NAME; pScreenInfo->name = ATI_NAME; pScreenInfo->Probe = ATIProbe; pScreenInfo->PreInit = ATIPreInit; pScreenInfo->ScreenInit = ATIScreenInit; pScreenInfo->SwitchMode = ATISwitchMode; pScreenInfo->AdjustFrame = ATIAdjustFrame; pScreenInfo->EnterVT = ATIEnterVT; pScreenInfo->LeaveVT = ATILeaveVT; pScreenInfo->FreeScreen = ATIFreeScreen; pScreenInfo->ValidMode = ATIValidMode; pScreenInfo->driverPrivate = pATI; pATI->Chipset = pATIGDev->Chipset; ProbeSuccess = TRUE; } /* Deal with unassigned adapters */ for (i = 0; i < nATIPtr; i++) { if (!(pATI = ATIPtrs[i])) continue; #ifndef AVOID_CPIO if (pATI->Adapter > ATI_ADAPTER_VGA) #endif /* AVOID_CPIO */ { if (pATI->iEntity < 0) (void)ATIClaimBusSlot(pDriver, 0, NULL, FALSE, pATI); } xfree(pATI); } xfree(ATIGDevs); } xfree(ATIPtrs); /* Call Rage 128 driver probe */ if (DoRage128 && R128Probe(pDriver, flags)) ProbeSuccess = TRUE; /* Call Radeon driver probe */ if (DoRadeon && RADEONProbe(pDriver, flags)) ProbeSuccess = TRUE; return ProbeSuccess; }