/* * Copyright 1997 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 "atibus.h" #include "atichip.h" #include "atimach64io.h" #include "atiprobe.h" #include "ativersion.h" #include "atividmem.h" #include "atiwonderio.h" #ifndef AVOID_CPIO /* * 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 ) { CARD8 IOValue1, IOValue2, IOValue3, IOValue4, IOValue5, IOValue6; if (!pATI->OptionProbeSparse) { xf86Msg(X_WARNING, ATI_NAME ": Expected VGA Wonder capability at I/O port" " 0x%04lX will not be probed\n" "set option \"probe_sparse\" to force probing.\n", pATI->CPIO_VGAWonder); pATI->CPIO_VGAWonder = 0; return; } 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) | 0x80U); } /* * 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); 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%04lX detected.\n", pATI->CPIO_VGAWonder); } else { xf86Msg(X_WARNING, ATI_NAME ": Expected VGA Wonder capability at I/O port" " 0x%04lX was not detected.\n", pATI->CPIO_VGAWonder); pATI->CPIO_VGAWonder = 0; } } #endif /* AVOID_CPIO */ /* * ATIMach64Detect -- * * This function determines if a Mach64 is detectable at a particular base * address. */ static Bool ATIMach64Detect ( ATIPtr pATI, const CARD16 ChipType, const ATIChipType Chip ) { CARD32 IOValue, bus_cntl, gen_test_cntl; Bool DetectSuccess = FALSE; (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)) DetectSuccess = TRUE; } } /* Restore clobbered register value */ outr(SCRATCH_REG0, IOValue); /* If no Mach64 was detected, return now */ if (!DetectSuccess) { 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); 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 ( ATIPtr pATI, pciVideoPtr pVideo, const ATIChipType Chip ) { CARD16 ChipType = PCI_DEV_DEVICE_ID(pVideo); pATI->MMIOInLinear = FALSE; /* * Probe through auxiliary MMIO aperture if one exists. Because such * apertures can be enabled/disabled only through PCI, this probes no * further. */ if ((PCI_REGION_SIZE(pVideo, 2) >= (1 << 12)) && (pATI->Block0Base = PCI_REGION_BASE(pVideo, 2, REGION_MEM))) { pATI->Block0Base += 0x00000400U; if (ATIMach64Detect(pATI, ChipType, Chip)) return pATI; return NULL; } /* * 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 ((PCI_REGION_SIZE(pVideo, 0) >= (1 << 22)) && (pATI->Block0Base = PCI_REGION_BASE(pVideo, 0, REGION_MEM))) { pATI->MMIOInLinear = TRUE; pATI->Block0Base += 0x007FFC00U; if ((PCI_REGION_SIZE(pVideo, 0) >= (1 << 23)) && ATIMach64Detect(pATI, ChipType, Chip)) return pATI; pATI->Block0Base -= 0x00400000U; if (ATIMach64Detect(pATI, ChipType, Chip)) return 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 ( ATIPtr pATI, pciVideoPtr pVideo, const ATIChipType Chip ) { CARD32 IOValue; CARD16 ChipType = PCI_DEV_DEVICE_ID(pVideo); if ((pATI->CPIODecoding == BLOCK_IO) && (PCI_REGION_SIZE(pVideo, 1) < (1 << 8))) return NULL; if (!ATIMach64Detect(pATI, ChipType, Chip)) { 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 = TRUE; } 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 = TRUE; pATI->CPIO_VGAWonder = 0x01CEU; } } return pATI; } static void ATIAssignVGA ( pciVideoPtr pVideo, ATIPtr pATI ) { if (pATI->CPIO_VGAWonder) { ATIVGAWonderProbe(pVideo, pATI); 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); } } } /* * ATIFindVGA -- * * This function determines if a VGA associated with an ATI PCI adapter is * shareable. */ static void ATIFindVGA ( pciVideoPtr pVideo, ATIPtr pATI ) { /* * 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); ATIAssignVGA(pVideo, pATI); } #endif /* AVOID_CPIO */ /* * ATIMach64ProbeIO -- * * This function determines the IO method and IO base of the ATI PCI adapter. */ Bool ATIMach64ProbeIO ( pciVideoPtr pVideo, ATIPtr pATI ) { Bool ProbeSuccess = FALSE; #ifndef AVOID_CPIO /* Next, look for sparse I/O Mach64's */ if (!PCI_REGION_SIZE(pVideo, 1)) { static const IOADDRESS Mach64SparseIOBases[] = { 0x02ECU, 0x01CCU, 0x01C8U }; uint32_t PciReg; uint32_t j; pciConfigPtr pPCI = pVideo->thisCard; if (pPCI == NULL) goto SkipSparse; PCI_READ_LONG(pVideo, &PciReg, 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", PCI_DEV_BUS(pVideo), PCI_DEV_DEV(pVideo), PCI_DEV_FUNC(pVideo)); goto SkipSparse; } /* FIXME: * Should not probe at sparse I/O bases which have been registered to * other PCI devices. The old ATIProbe() would scan the PCI space and * build a list of registered I/O ports. If there was a conflict * between a mach64 sparse I/O base and a registered I/0 port, probing * that port was not allowed... * * We just add an option and let the user decide, this will not work * with "X -configure" though... */ if (!pATI->OptionProbeSparse) { xf86Msg(X_WARNING, ATI_NAME ": " "PCI Mach64 in slot %d:%d:%d will not be probed\n" "set option \"probe_sparse\" to force sparse I/O probing.\n", PCI_DEV_BUS(pVideo), PCI_DEV_DEV(pVideo), PCI_DEV_FUNC(pVideo)); goto SkipSparse; } /* Possibly fix block I/O indicator */ if (PciReg & 0x00000004U) { PciReg &= ~0x00000004U; PCI_WRITE_LONG(pVideo, PciReg, PCI_REG_USERCONFIG); } pATI->CPIOBase = Mach64SparseIOBases[j]; pATI->CPIODecoding = SPARSE_IO; pATI->PCIInfo = pVideo; if (!ATIMach64Probe(pATI, pVideo, pATI->Chip)) { xf86Msg(X_WARNING, ATI_NAME ": " "PCI Mach64 in slot %d:%d:%d could not be detected!\n", PCI_DEV_BUS(pVideo), PCI_DEV_DEV(pVideo), PCI_DEV_FUNC(pVideo)); } else { ProbeSuccess = TRUE; xf86Msg(X_INFO, ATI_NAME ": " "Shared PCI Mach64 in slot %d:%d:%d with sparse PIO base" " 0x%04lX detected.\n", PCI_DEV_BUS(pVideo), PCI_DEV_DEV(pVideo), PCI_DEV_FUNC(pVideo), Mach64SparseIOBases[j]); if (pATI->VGAAdapter) ATIFindVGA(pVideo, pATI); } } SkipSparse: #else /* AVOID_CPIO */ if (!PCI_REGION_SIZE(pVideo, 1)) { /* The adapter's CPIO base is of little concern here */ pATI->CPIOBase = 0; pATI->CPIODecoding = SPARSE_IO; pATI->PCIInfo = pVideo; if (ATIMach64Probe(pATI, pVideo, pATI->Chip)) { ProbeSuccess = TRUE; xf86Msg(X_INFO, ATI_NAME ": " "Shared PCI Mach64 in slot %d:%d:%d with Block 0 base" " 0x%08lX detected.\n", PCI_DEV_BUS(pVideo), PCI_DEV_DEV(pVideo), PCI_DEV_FUNC(pVideo), pATI->Block0Base); } else { xf86Msg(X_WARNING, ATI_NAME ": " "PCI Mach64 in slot %d:%d:%d could not be detected!\n", PCI_DEV_BUS(pVideo), PCI_DEV_DEV(pVideo), PCI_DEV_FUNC(pVideo)); } } #endif /* AVOID_CPIO */ /* Lastly, look for block I/O devices */ if (PCI_REGION_SIZE(pVideo, 1)) { pATI->CPIOBase = PCI_REGION_BASE(pVideo, 1, REGION_IO); pATI->CPIODecoding = BLOCK_IO; pATI->PCIInfo = pVideo; if (ATIMach64Probe(pATI, pVideo, pATI->Chip)) { ProbeSuccess = TRUE; xf86Msg(X_INFO, ATI_NAME ": " "Shared PCI/AGP Mach64 in slot %d:%d:%d detected.\n", PCI_DEV_BUS(pVideo), PCI_DEV_DEV(pVideo), PCI_DEV_FUNC(pVideo)); #ifndef AVOID_CPIO if (pATI->VGAAdapter) ATIFindVGA(pVideo, pATI); #endif /* AVOID_CPIO */ } else { xf86Msg(X_WARNING, ATI_NAME ": " "PCI/AGP Mach64 in slot %d:%d:%d could not be detected!\n", PCI_DEV_BUS(pVideo), PCI_DEV_DEV(pVideo), PCI_DEV_FUNC(pVideo)); } } return ProbeSuccess; }