NT4/private/ntos/video/ati/setup_cx.c
2020-09-30 17:12:29 +02:00

1295 lines
48 KiB
C

/************************************************************************/
/* */
/* SETUP_CX.C */
/* */
/* Aug 27 1993 (c) 1993, ATI Technologies Incorporated. */
/************************************************************************/
/********************** PolyTron RCS Utilities
$Revision: 1.21 $
$Date: 15 May 1996 16:36:04 $
$Author: RWolff $
$Log: S:/source/wnt/ms11/miniport/archive/setup_cx.c_v $
*
* Rev 1.21 15 May 1996 16:36:04 RWolff
* Now records in registry if we have to cut back on BIOS claim
* size (conflict with SCSI card having BIOS segment below 0xD000:0000)
* so we only get event log messages on the first boot, rather
* than on every boot.
*
* Rev 1.20 03 May 1996 15:16:42 RWolff
* Made new temporary variable conditional on platform type to avoid
* warning when compiling for non-Alpha platforms.
*
* Rev 1.19 03 May 1996 14:07:26 RWolff
* Fixed drawing problem with GX-F ASIC on DEC Alpha.
*
* Rev 1.18 15 Apr 1996 13:51:30 RWolff
* Fallback to claiming 32k of BIOS if we can't get the full 64k, to avoid
* conflict with Adaptec 154x adapters with their BIOS segment set to
* 0xC800:0000 or 0xCC00:0000
*
* Rev 1.17 29 Jan 1996 17:01:56 RWolff
* Now uses VideoPortInt10() rather than no-BIOS code on PPC, now
* rejects exhaustive list of non-Mach 64 cards and accepts all
* others when looking for block I/O cards, rather than accepting
* exhaustive list of Mach 64 cards and rejecting all others.
*
* Rev 1.16 23 Jan 1996 17:52:16 RWolff
* Added GT to list of Mach 64 cards capable of supporting block I/O.
*
* Rev 1.15 23 Jan 1996 11:49:38 RWolff
* Eliminated level 3 warnings, added debug print statements, removed
* conditionally-compilec code to use VideoPortGetAccessRanges() to
* find block I/O cards, since this function remaps the I/O base address
* and this is incompatible with the use of INT 10.
*
* Rev 1.14 12 Jan 1996 11:18:50 RWolff
* Reduced size of buffer requested through VideoPortGetBusData()
*
* Rev 1.13 23 Nov 1995 11:31:42 RWolff
* Now searches each PCI slot for our cards, rather than using
* VideoPortGetAccessRanges(), since that routine won't detect
* block-relocatable GX-F2s properly. This change is not sanctioned
* by Microsoft, and must be backed out if they fix their routine.
*
* Rev 1.12 24 Aug 1995 15:39:06 RWolff
* Changed detection of block I/O cards to match Microsoft's
* standard for plug-and-play.
*
* Rev 1.11 13 Jun 1995 15:11:18 RWOLFF
* On Alpha systems, now only uses dense space for the memory mapped
* registers on PCI cards. This is to allow support for ISA cards on
* the Jensen (EISA machine, no PCI support), which doesn't support
* dense space.
*
* Rev 1.10 30 Mar 1995 12:02:14 RWOLFF
* WaitForIdle_cx() and CheckFIFOSpace_cx() now time out and reset
* the engine after 3 seconds (no operation should take this long)
* to clear a hung engine, changed permanent debug print statements
* to use new debug level thresholds.
*
* Rev 1.9 08 Mar 1995 11:35:44 ASHANMUG
* Modified return values to be correct
*
* Rev 1.7 27 Feb 1995 17:53:26 RWOLFF
* Added routine that reports whether the I/O registers are packed
* (relocatable) or not.
*
* Rev 1.6 24 Feb 1995 12:30:44 RWOLFF
* Added code to support relocatable I/O. This is not yet fully
* operational, so it is disabled for this release.
*
* Rev 1.5 23 Dec 1994 10:47:12 ASHANMUG
* ALPHA/Chrontel-DAC
*
* Rev 1.4 18 Nov 1994 11:48:18 RWOLFF
* Added support for Mach 64 with no BIOS, routine to get the I/O base
* address for the card being used.
*
* Rev 1.3 20 Jul 1994 12:59:12 RWOLFF
* Added support for multiple I/O base addresses for accelerator registers.
*
* Rev 1.2 30 Jun 1994 18:16:50 RWOLFF
* Added IsApertureConflict_cx() (moved from QUERY_CX.C). Instead of checking
* to see if we can read back what we have written to the aperture, then
* looking for the proper text attribute, we now make a call to
* VideoPortVerifyAccessRanges() which includes the aperture in the list of
* ranges we are trying to claim. If this call fails, we make another call
* which does not include the LFB. We always claim the VGA aperture (shareable),
* since we need to use it when querying the card.
*
* Rev 1.1 07 Feb 1994 14:14:12 RWOLFF
* Added alloc_text() pragmas to allow miniport to be swapped out when
* not needed.
*
* Rev 1.0 31 Jan 1994 11:20:42 RWOLFF
* Initial revision.
*
* Rev 1.1 30 Nov 1993 18:30:06 RWOLFF
* Fixed calculation of offset for memory mapped address ranges.
*
* Rev 1.0 05 Nov 1993 13:36:14 RWOLFF
* Initial revision.
End of PolyTron RCS section *****************/
#ifdef DOC
SETUP_CX.C - Setup routines for 68800CX accelerators.
DESCRIPTION
This file contains routines which provide services specific to
the 68800CX-compatible family of ATI accelerators.
OTHER FILES
#endif
#include "dderror.h"
#include "miniport.h"
#include "video.h"
#include "ntddvdeo.h"
#include "stdtyp.h"
#include "amachcx.h"
#include "amach1.h"
#include "atimp.h"
#include "query_cx.h"
#include "services.h"
#define INCLUDE_SETUP_CX
#include "setup_cx.h"
static ULONG FindNextBlockATICard(void);
/*
* Allow miniport to be swapped out when not needed.
*/
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(PAGE_CX, CompatIORangesUsable_cx)
#pragma alloc_text(PAGE_CX, CompatMMRangesUsable_cx)
#pragma alloc_text(PAGE_CX, WaitForIdle_cx)
#pragma alloc_text(PAGE_CX, CheckFIFOSpace_cx)
#pragma alloc_text(PAGE_CX, IsApertureConflict_cx)
#pragma alloc_text(PAGE_CX, GetIOBase_cx)
#pragma alloc_text(PAGE_CX, IsPackedIO_cx)
#pragma alloc_text(PAGE_CX, FindNextBlockATICard)
#endif
UCHAR LookForAnotherCard = 1;
/***************************************************************************
*
* VP_STATUS CompatIORangesUsable_cx(void);
*
* DESCRIPTION:
* Ask Windows NT for permission to use the I/O space address ranges
* needed by the 68800CX accelerator.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if unable to gain access to the ranges we need.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* ATIMPFindAdapter()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS CompatIORangesUsable_cx(INTERFACE_TYPE SystemBus)
{
VP_STATUS Status; /* Value returned by operating system calls */
short Count; /* Loop counter */
VIDEO_ACCESS_RANGE SaveFirstMM; /* Place to save the first memory mapped registers */
USHORT BaseIndex; /* Index into register base array */
USHORT VariableIndex; /* Index into array of variable part of register array */
ULONG BaseAddress; /* I/O base address for relocatable I/O */
ULONG ClaimSize; /* Size of VGA aperture/BIOS block to claim */
ULONG InitialClaimSize; /* Initial size of the BIOS block to claim */
BOOL FoundSafeClaim = FALSE; /* Have we found a BIOS block we can claim safely? */
/*
* Check to see if someone has added or deleted I/O ranges without
* changing the defined value. I/O registers start at index 0.
*
* All the I/O mapped registers are before the first register which
* exists only in memory-mapped form.
*/
if ((DriverIORange_cx[NUM_IO_REGISTERS-1].RangeStart.HighPart == DONT_USE) ||
(DriverIORange_cx[NUM_IO_REGISTERS].RangeStart.HighPart != DONT_USE))
{
VideoDebugPrint((DEBUG_ERROR, "Wrong defined value for number of I/O ranges\n"));
return ERROR_INSUFFICIENT_BUFFER;
}
/*
* Clear the list of mapped I/O addresses so we can identify
* which ones have been mapped in order to unmap them if
* there is a failure partway through the mapping.
*/
for (Count = 0; Count < NUM_IO_REGISTERS; Count++)
{
phwDeviceExtension->aVideoAddressIO[Count] = 0;
}
/*
* Run through the list of base addresses, trying each
* until we find the one that the Mach 64 is using.
*/
for (BaseIndex = 0; BaseIndex < NUM_BASE_ADDRESSES; BaseIndex++)
{
/*
* Possible problem area: if this is the first bus to be
* tested which contains a fixed-base Mach 64, but a previous
* bus had at least one block-relocatable card without
* having the maximum number we support (which would have
* been caught in ATIMPFindAdapter()), we don't want to
* look for fixed-base cards. This is because we don't
* support a mixture of fixed-base and block-relocatable
* cards.
*/
if (NumBlockCardsFound != 0)
{
VideoDebugPrint((DEBUG_NORMAL, "Skipping fixed base because block cards found\n"));
break;
}
/*
* Build up the accelerator registers using the current
* base address.
*/
for (VariableIndex = 0; VariableIndex < NUM_REGS_TO_BUILD; VariableIndex++)
{
DriverIORange_cx[VariableIndex+FIRST_REG_TO_BUILD].RangeStart.LowPart =
VariableRegisterBases[BaseIndex] + VariableRegisterOffsets[VariableIndex];
}
/*
* If we encounter a conflict claiming the full 64k of the BIOS
* area, it will generate two messages in the event log even
* though this is not a fatal error. To avoid this, we must
* store claim restrictions in the registry, and on subsequent
* boots start claiming where we were successful last time.
*
* If we can't read the registry entry, assume that we can
* claim the full 64k area starting at 0xC000:0000.
*
* Don't worry about a user upgrading to a Mach 64 with a 64k
* video BIOS and moving the SCSI card above 0xD000:0000, since
* our install script will clear this registry entry to its
* "claim 64k" value.
*/
if (VideoPortGetRegistryParameters(phwDeviceExtension,
L"BiosClaimSize",
FALSE,
RegistryParameterCallback,
NULL) == NO_ERROR)
{
InitialClaimSize = *RegistryBuffer;
VideoDebugPrint((DEBUG_DETAIL, "Read initial claim size 0x%X\n", VgaResourceSize[InitialClaimSize]));
}
else
{
InitialClaimSize = CLAIM_32k_BIOS;
VideoDebugPrint((DEBUG_DETAIL, "Using default initial claim size 0x%X\n", VgaResourceSize[InitialClaimSize]));
}
if ((InitialClaimSize < CLAIM_32k_BIOS) || (InitialClaimSize > CLAIM_APERTURE_ONLY) )
InitialClaimSize = CLAIM_32k_BIOS;
/*
* Claim as much as possible of our BIOS area. If we fail to
* claim the full 64k, try restricting ourselves to 32k and
* finally no BIOS area, only giving up on the current I/O
* base address if we can't claim our access ranges even with
* no BIOS area.
*/
for (ClaimSize = InitialClaimSize; ClaimSize <= CLAIM_APERTURE_ONLY; ClaimSize++)
{
/*
* Set up our VGA resource claim size.
*/
DriverApertureRange_cx[0].RangeLength = VgaResourceSize[ClaimSize];
/*
* Check to see if there is a hardware resource conflict. We must save
* the information for the first memory mapped register, copy in
* the information for the VGA aperture (which we always need),
* and restore the memory mapped register information after
* we have verified that we can use the required address ranges.
*/
VideoPortMoveMemory(&SaveFirstMM, DriverIORange_cx+VGA_APERTURE_ENTRY, sizeof(VIDEO_ACCESS_RANGE));
VideoPortMoveMemory(DriverIORange_cx+VGA_APERTURE_ENTRY, DriverApertureRange_cx, sizeof(VIDEO_ACCESS_RANGE));
Status = VideoPortVerifyAccessRanges(phwDeviceExtension,
NUM_IO_REGISTERS + 1,
DriverIORange_cx);
VideoPortMoveMemory(DriverIORange_cx+VGA_APERTURE_ENTRY, &SaveFirstMM, sizeof(VIDEO_ACCESS_RANGE));
/*
* If there is a hardware resource conflict, we can't use this
* base address and BIOS region size, so try the next. If there
* is no conflict, use the current size.
*
* If the size of the BIOS block we were able to claim
* differs from our initial attempt, record the "maximum
* possible BIOS block size" in the registry so that on
* subsequent boots we won't generate event log entries
* by claiming a BIOS region that conflicts with another
* card.
*/
if (Status != NO_ERROR)
{
VideoDebugPrint((DEBUG_DETAIL, "Rejecting VGA aperture/BIOS block size of 0x%X bytes\n", VgaResourceSize[ClaimSize]));
continue;
}
else
{
VideoDebugPrint((DEBUG_DETAIL, "VGA aperture/BIOS block size = 0x%X bytes\n", VgaResourceSize[ClaimSize]));
if (FoundSafeClaim == FALSE)
{
FoundSafeClaim = TRUE;
if (ClaimSize != InitialClaimSize)
{
//ClaimSize = 1;
VideoDebugPrint((DEBUG_DETAIL, "Writing claim size 0x%X\n", VgaResourceSize[ClaimSize]));
VideoPortSetRegistryParameters(phwDeviceExtension,
L"BiosClaimSize",
&ClaimSize,
sizeof(ULONG));
}
}
break;
}
} /* end for (decreasing claim size) */
/*
* If we fell out of the above loop, rather than breaking out,
* go on to the next I/O base address, since we have run into
* a hardware resource conflict.
*/
if ((Status != NO_ERROR) && (ClaimSize > CLAIM_APERTURE_ONLY))
continue;
/*
* Map the video controller address ranges we need to identify
* our cards into the system virtual address space. If a register
* only exists in memory-mapped form, set its I/O mapped address
* to zero (won't be used because memory-mapped takes precedence
* over I/O mapped).
*
* Initialize the mapped addresses for memory mapped registers
* to 0 (flag to show the registers are not memory mapped) in
* case they were initialized to a nonzero value.
*/
for (Count=0; Count < NUM_DRIVER_ACCESS_RANGES; Count++)
{
if (Count < NUM_IO_REGISTERS)
{
if ((phwDeviceExtension->aVideoAddressIO[Count] =
VideoPortGetDeviceBase(phwDeviceExtension,
DriverIORange_cx[Count].RangeStart,
DriverIORange_cx[Count].RangeLength,
DriverIORange_cx[Count].RangeInIoSpace)) == NULL)
{
/*
* There was an error in mapping. Remember this
* so we don't try to find a Mach 64 without all
* the registers being mapped properly, then
* break out of the mapping loop. We will have
* another shot at mapping all the addresses
* when we try the next base address for the
* accelerator registers.
*/
Status = ERROR_INVALID_PARAMETER;
VideoDebugPrint((DEBUG_ERROR, "Mapping error 1\n"));
break;
}
}
else
{
phwDeviceExtension->aVideoAddressIO[Count] = 0;
}
phwDeviceExtension->aVideoAddressMM[Count] = 0;
} /* End for */
/*
* If all I/O registers were successfully mapped, check to see
* if a Mach 64 is present at the current base address. If it
* is, report that we have successfully mapped our registers
* and found a Mach 64. Since this means we have found a
* card which is not block relocatable, we do not want to
* look for further cards. Also, since this is the only
* Mach 64 in the system, assume that its VGA is enabled.
*/
if (Status == NO_ERROR)
{
if (DetectMach64() == MACH64_ULTRA)
{
FoundNonBlockCard = TRUE;
LookForAnotherCard = 0;
phwDeviceExtension->BiosPrefix = BIOS_PREFIX_VGA_ENAB;
return NO_ERROR;
}
}
/*
* We did not find a Mach 64 at this base address, so unmap
* the I/O mapped registers in preparation for trying the
* next base address. Only unmap those registers which were
* mapped, in case the mapping loop aborted due to a failure
* to map one register.
*/
for (Count = 1; Count < NUM_IO_REGISTERS; Count++)
{
if (phwDeviceExtension->aVideoAddressIO[Count] != 0)
{
VideoPortFreeDeviceBase(phwDeviceExtension,
phwDeviceExtension->aVideoAddressIO[Count]);
phwDeviceExtension->aVideoAddressIO[Count] = 0;
}
}
} /* End for (loop of base addresses) */
/*
* The video card in the machine isn't a Mach 64 that uses one of
* the standard I/O base addresses. Check if it's a Mach 64 with
* relocatable I/O.
*
* All our relocatable cards are PCI implementations. The code we
* use to detect them is PCI-specific, so if the bus we are currently
* dealing with is not PCI, don't look for relocatable cards.
*/
if (SystemBus != PCIBus)
{
VideoDebugPrint((DEBUG_DETAIL, "Not PCI bus - can't check for relocatable card\n"));
return ERROR_DEV_NOT_EXIST;
}
BaseAddress = FindNextBlockATICard();
/*
* BaseAddress will be zero if FindNextBlockATICard()
* couldn't find a block-relocatable ATI card.
*/
if (BaseAddress == 0)
{
LookForAnotherCard = 0;
VideoDebugPrint((DEBUG_NORMAL, "Finished checking for relocatable cards\n"));
return ERROR_DEV_NOT_EXIST;
}
/*
* We have found a block relocatable ATI card. Save its I/O base
* address so we can (during ATIMPInitialize()) match it up to
* the accelerator prefix for the card, and set the initial prefix
* to show that this card needs its I/O base and accelerator prefix
* matched.
*/
phwDeviceExtension->BaseIOAddress = BaseAddress;
phwDeviceExtension->BiosPrefix = BIOS_PREFIX_UNASSIGNED;
NumBlockCardsFound++;
VideoDebugPrint((DEBUG_NORMAL, "Block relocatable card found, I/O base 0x%X\n", BaseAddress));
/*
* We now have the I/O base address. Map in the I/O addresses,
* then check to see if we have a Mach 64 card. Depending on
* the results, either report success or unmap the addresses
* and report failure.
*/
VideoDebugPrint((DEBUG_DETAIL, "About to map I/O addresses\n"));
for (VariableIndex = 0; VariableIndex < NUM_REGS_TO_BUILD; VariableIndex++)
{
DriverIORange_cx[VariableIndex+FIRST_REG_TO_BUILD].RangeStart.LowPart =
BaseAddress + (RelocatableRegisterOffsets[VariableIndex] * 4);
}
/*
* Claim as much as possible of our BIOS area. If we fail to
* claim the full 64k, try restricting ourselves to 32k and
* finally no BIOS area, only giving up on the current I/O
* base address if we can't claim our access ranges even with
* no BIOS area.
*/
for (ClaimSize = InitialClaimSize; ClaimSize <= CLAIM_APERTURE_ONLY; ClaimSize++)
{
/*
* Set up our VGA resource claim size.
*/
DriverApertureRange_cx[0].RangeLength = VgaResourceSize[ClaimSize];
/*
* Check to see if there is a hardware resource conflict. We must save
* the information for the first memory mapped register, copy in
* the information for the VGA aperture (which we always need),
* and restore the memory mapped register information after
* we have verified that we can use the required address ranges.
*/
VideoPortMoveMemory(&SaveFirstMM, DriverIORange_cx+VGA_APERTURE_ENTRY, sizeof(VIDEO_ACCESS_RANGE));
VideoPortMoveMemory(DriverIORange_cx+VGA_APERTURE_ENTRY, DriverApertureRange_cx, sizeof(VIDEO_ACCESS_RANGE));
Status = VideoPortVerifyAccessRanges(phwDeviceExtension,
NUM_IO_REGISTERS + 1,
DriverIORange_cx);
VideoPortMoveMemory(DriverIORange_cx+VGA_APERTURE_ENTRY, &SaveFirstMM, sizeof(VIDEO_ACCESS_RANGE));
/*
* If there is a hardware resource conflict, we are either trying
* to claim a bigger BIOS block than we need, and someone else is
* sitting in (and claiming as nonshareable) the "slack", or we have
* a conflict over the I/O base address. Try the next smallest BIOS
* block.
*
* If the size of the BIOS block we were able to claim
* differs from our initial attempt, record the "maximum
* possible BIOS block size" in the registry so that on
* subsequent boots we won't generate event log entries
* by claiming a BIOS region that conflicts with another
* card.
*/
if (Status != NO_ERROR)
{
VideoDebugPrint((DEBUG_DETAIL, "Rejecting VGA aperture/BIOS block size of 0x%X bytes\n", VgaResourceSize[ClaimSize]));
continue;
}
else
{
VideoDebugPrint((DEBUG_DETAIL, "VGA aperture/BIOS block size = 0x%X bytes\n", VgaResourceSize[ClaimSize]));
if (FoundSafeClaim == FALSE)
{
FoundSafeClaim = TRUE;
if (ClaimSize != InitialClaimSize)
{
//ClaimSize = 1;
VideoDebugPrint((DEBUG_DETAIL, "Writing claim size 0x%X\n", VgaResourceSize[ClaimSize]));
VideoPortSetRegistryParameters(phwDeviceExtension,
L"BiosClaimSize",
&ClaimSize,
sizeof(ULONG));
}
}
break;
}
} /* end for (decreasing claim size) */
/*
* If there is a conflict over the I/O base address, we can't use
* it. Since this is our last chance to find a Mach 64, report failure.
*/
if (Status != NO_ERROR)
{
VideoDebugPrint((DEBUG_ERROR, "VideoPortVerifyAccessRanges() failed in check for relocatable Mach 64\n"));
return ERROR_DEV_NOT_EXIST;
}
/*
* Map the video controller address ranges we need to identify
* our cards into the system virtual address space. If a register
* only exists in memory-mapped form, set its I/O mapped address
* to zero (won't be used because memory-mapped takes precedence
* over I/O mapped).
*
* Initialize the mapped addresses for memory mapped registers
* to 0 (flag to show the registers are not memory mapped) in
* case they were initialized to a nonzero value.
*/
for (Count=0; Count < NUM_DRIVER_ACCESS_RANGES; Count++)
{
if (Count < NUM_IO_REGISTERS)
{
if ((phwDeviceExtension->aVideoAddressIO[Count] =
VideoPortGetDeviceBase(phwDeviceExtension,
DriverIORange_cx[Count].RangeStart,
DriverIORange_cx[Count].RangeLength,
DriverIORange_cx[Count].RangeInIoSpace)) == NULL)
{
/*
* There was an error in mapping. Remember this
* so we don't try to find a Mach 64 without all
* the registers being mapped properly, then
* break out of the mapping loop.
*/
Status = ERROR_INVALID_PARAMETER;
VideoDebugPrint((DEBUG_ERROR, "Mapping error 2\n"));
break;
}
}
else
{
phwDeviceExtension->aVideoAddressIO[Count] = 0;
}
phwDeviceExtension->aVideoAddressMM[Count] = 0;
} /* End for */
/*
* If all I/O registers were successfully mapped, check to see
* if a Mach 64 is present at the current base address. If it
* is, report that we have successfully mapped our registers
* and found a Mach 64.
*/
if (Status == NO_ERROR)
{
if (DetectMach64() == MACH64_ULTRA)
{
return NO_ERROR;
}
}
/*
* We did not find a Mach 64 at this base address, so clean
* up after ourselves by unmapping the I/O mapped registers
* before reporting failure. Only unmap those registers which
* were mapped, in case the mapping loop aborted due to a
* failure to map one register.
*/
for (Count = 1; Count < NUM_IO_REGISTERS; Count++)
{
if (phwDeviceExtension->aVideoAddressIO[Count] != 0)
{
VideoPortFreeDeviceBase(phwDeviceExtension,
phwDeviceExtension->aVideoAddressIO[Count]);
phwDeviceExtension->aVideoAddressIO[Count] = 0;
}
}
/*
* We haven't found a Mach 64 at any of the allowable base addresses,
* so report that there is no Mach 64 in the machine.
*/
VideoDebugPrint((DEBUG_NORMAL, "No Mach 64 found at this address\n"));
return ERROR_DEV_NOT_EXIST;
} /* CompatIORangesUsable_cx() */
/***************************************************************************
*
* VP_STATUS CompatMMRangesUsable_cx(void);
*
* DESCRIPTION:
* Ask Windows NT for permission to use the memory mapped registers
* needed by the 68800CX accelerator.
*
* RETURN VALUE:
* NO_ERROR if successful
* error code if unable to gain access to the ranges we need.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* ATIMPFindAdapter()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
VP_STATUS CompatMMRangesUsable_cx(void)
{
PHYSICAL_ADDRESS MMrange; /* Used in translating offset to memory address */
ULONG RegisterOffset; /* Offset of memory mapped registers start of address space */
int Count; /* Loop counter */
struct query_structure *QueryPtr; /* Query information for the card */
UCHAR InIOSpace;
#if defined (ALPHA)
ULONG Scratch;
#endif
/*
* Get a formatted pointer into the query section of HwDeviceExtension.
* The CardInfo[] field is an unformatted buffer.
*/
QueryPtr = (struct query_structure *) (phwDeviceExtension->CardInfo);
/*
* Set the offset of the memory mapped registers from the start of
* the aperture to the appropriate value for the aperture size
* being used.
*/
if ((QueryPtr->q_aperture_cfg & BIOS_AP_SIZEMASK) == BIOS_AP_8M)
RegisterOffset = phwDeviceExtension->PhysicalFrameAddress.LowPart + OFFSET_8M;
else if ((QueryPtr->q_aperture_cfg & BIOS_AP_SIZEMASK) == BIOS_AP_4M)
RegisterOffset = phwDeviceExtension->PhysicalFrameAddress.LowPart + OFFSET_4M;
else
RegisterOffset = OFFSET_VGA;
/*
* We are working in a 32 bit address space, so the upper DWORD
* of the quad word address is always zero.
*/
MMrange.HighPart = 0;
#if defined (ALPHA)
/*
* All Alpha systems are capable of supporting sparse space
* (normal memory mapped space for the Alpha). Newer systems
* (those that have PCI buses) are also able to support dense
* space, but older systems can't. In almost all cases, non-PCI
* cards are a sign that we are using an older system, but
* assuming this is an older system when it is actually an ISA
* card in a newer system is mostly harmless (slight performance
* penalty). Assuming that dense space is available on all Alpha
* systems will crash a Jensen (older system).
*/
if (QueryPtr->q_bus_type == BUS_PCI)
InIOSpace = 4; // DENSE Space
else
InIOSpace = 0;
/*
* The GX-F ASIC has a bug where burst reads of a quadword of
* memory will result in the high doubleword being corrupted.
* The memory-mapped form of CONFIG_CHIP_ID is the high doubleword,
* and on the Alpha in dense space (on PCI cards we always use
* dense space for our memory-mapped registers) all read access
* to memory is by quadwords, so we will run into the burst mode
* problem. The I/O mapped form of this register is safe to use.
*/
Scratch = INPD(CONFIG_CHIP_ID);
if (((Scratch & CONFIG_CHIP_ID_TypeMask) == CONFIG_CHIP_ID_TypeGX) &&
((Scratch & CONFIG_CHIP_ID_RevMask) == CONFIG_CHIP_ID_RevF))
{
VideoDebugPrint((DEBUG_DETAIL, "GX-F detected, must use I/O mapped form of CRTC_OFF_PITCH\n"));
DriverMMRange_cx[CRTC_OFF_PITCH].RangeStart.HighPart = DONT_USE;
}
#else
InIOSpace = 0; // memory mapped I/O Space
#endif
for (Count=1; Count < NUM_DRIVER_ACCESS_RANGES; Count++)
{
/*
* In a 32-bit address space, the high doubleword of all
* physical addresses is zero. Setting this value to DONT_USE
* indicates that this accelerator register isn't memory mapped.
*/
if (DriverMMRange_cx[Count].RangeStart.HighPart != DONT_USE)
{
/*
* DriverMMRange_cx[Count].RangeStart.LowPart is the offset
* (in doublewords) of the memory mapped register from the
* beginning of the block of memory mapped registers. We must
* convert this to bytes, add the offset of the start of the
* memory mapped register area from the start of the aperture
* and the physical address of the start of the linear
* framebuffer to get the physical address of this
* memory mapped register.
*/
MMrange.LowPart = (DriverMMRange_cx[Count].RangeStart.LowPart * 4) + RegisterOffset;
phwDeviceExtension->aVideoAddressMM[Count] =
VideoPortGetDeviceBase(phwDeviceExtension,
MMrange,
DriverMMRange_cx[Count].RangeLength,
InIOSpace); // not in IO space
/*
* If we were unable to claim the memory-mapped version of
* this register, and it exists only in memory-mapped form,
* then we have a register which we can't access. Report
* this as an error condition.
*/
if ((phwDeviceExtension->aVideoAddressMM[Count] == 0) &&
(DriverIORange_cx[Count].RangeStart.HighPart == DONT_USE))
{
VideoDebugPrint((DEBUG_ERROR, "Mapping error 3\n"));
return ERROR_INVALID_PARAMETER;
}
}
}
VideoDebugPrint((DEBUG_DETAIL, "CompatMMRangesUsable_cx() succeeded\n"));
return NO_ERROR;
} /* CompatMMRangesUsable_cx() */
/***************************************************************************
*
* int WaitForIdle_cx(void);
*
* DESCRIPTION:
* Poll GUI_STAT waiting for GuiActive field to go low. If it does not go
* low within 3 seconds (arbitrary value, but no operation should take
* that long), time out.
*
* RETURN VALUE:
* FALSE if timeout
* TRUE if engine is idle
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* Any 68800CX-specific routine may call this routine.
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
int WaitForIdle_cx(void)
{
int i;
ULONG Scratch;
for (i=0; i<300; i++)
{
if ((INPD(GUI_STAT) & GUI_STAT_GuiActive) == 0)
return TRUE;
/*
* Wait 1/100th of a second
*/
delay(10);
}
/*
* Something has happened, so reset the engine and return FALSE.
*/
VideoDebugPrint((DEBUG_ERROR, "ATI: Timeout on WaitForIdle_cx()\n"));
Scratch = INPD(GEN_TEST_CNTL) & ~GEN_TEST_CNTL_GuiEna;
OUTPD(GEN_TEST_CNTL, Scratch);
Scratch |= GEN_TEST_CNTL_GuiEna;
OUTPD(GEN_TEST_CNTL, Scratch);
return FALSE;
} /* WaitForIdle_cx() */
/***************************************************************************
*
* void CheckFIFOSpace_cx(SpaceNeeded);
*
* WORD SpaceNeeded; Number of free FIFO entries needed
*
* DESCRIPTION:
* Wait until the specified number of FIFO entries are free
* on a 68800CX-compatible ATI accelerator.
*
* If the specified number of entries does not become free in
* 3 seconds (arbitrary value greater than any operation should
* take), assume the engine has locked and reset it.
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* Any 68800CX-specific routine may call this routine.
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
void CheckFIFOSpace_cx(WORD SpaceNeeded)
{
ULONG LoopCount;
ULONG Scratch;
for (LoopCount = 0; LoopCount < 300; LoopCount++)
{
/*
* Return from test if enough entries are free
*/
if (!(INPD(FIFO_STAT)&SpaceNeeded))
return;
/*
* Wait 1/100th of a second
*/
delay(10);
}
/*
* Something has happened, so reset the engine and return FALSE.
*/
VideoDebugPrint((DEBUG_ERROR, "ATI: Timeout on CheckFIFOSpace_cx()\n"));
Scratch = INPD(GEN_TEST_CNTL) & ~GEN_TEST_CNTL_GuiEna;
OUTPD(GEN_TEST_CNTL, Scratch);
Scratch |= GEN_TEST_CNTL_GuiEna;
OUTPD(GEN_TEST_CNTL, Scratch);
return;
} /* CheckFIFOSpace_cx() */
/*
* BOOL IsApertureConflict_cx(QueryPtr);
*
* struct query_structure *QueryPtr; Pointer to query structure
*
* Check to see if the linear aperture conflicts with other memory.
* If a conflict exists, disable the linear aperture.
*
* Returns:
* TRUE if a conflict exists (aperture unusable)
* FALSE if the aperture is usable.
*/
BOOL IsApertureConflict_cx(struct query_structure *QueryPtr)
{
DWORD Scratch; /* Used in manipulating registers */
VP_STATUS Status; /* Return value from VideoPortVerifyAccessRanges() */
VIDEO_X86_BIOS_ARGUMENTS Registers; /* Used in VideoPortInt10() calls */
VIDEO_ACCESS_RANGE SaveFirstMM[2]; /* Place to save the first two memory mapped registers */
USHORT VariableIndex; /* Index into array of variable part of register array */
/*
* Set up by disabling the memory boundary (must be disabled in order
* to access accelerator memory through the VGA aperture).
*/
Scratch = INPD(MEM_CNTL);
Scratch &= ~MEM_CNTL_MemBndryEn;
OUTPD(MEM_CNTL, Scratch);
/*
* If there is an aperture conflict, a call to
* VideoPortVerifyAccessRanges() including our linear framebuffer in
* the range list will return an error. If there is no conflict, it
* will return success.
*
* We must save the contents of the first 2 memory mapped register
* entries, copy in the aperture ranges (VGA and linear) we need
* to claim, then restore the memory mapped entries after we
* have verified that we can use the aperture(s).
*
* DriverIORange_cx[] contains the physical addresses of the registers
* for the last card we have dealt with. In a single-card setup, this
* is no problem, but in a multi-card setup we must re-load this
* array with the physical addresses of the card we want to claim
* the aperture for.
*/
if (NumBlockCardsFound > 1)
{
for (VariableIndex = 0; VariableIndex < NUM_REGS_TO_BUILD; VariableIndex++)
{
DriverIORange_cx[VariableIndex+FIRST_REG_TO_BUILD].RangeStart.LowPart =
phwDeviceExtension->BaseIOAddress + (RelocatableRegisterOffsets[VariableIndex] * 4);
}
}
DriverApertureRange_cx[LFB_ENTRY].RangeStart.LowPart = QueryPtr->q_aperture_addr*ONE_MEG;
if ((QueryPtr->q_aperture_cfg & BIOS_AP_SIZEMASK) == BIOS_AP_8M)
DriverApertureRange_cx[LFB_ENTRY].RangeLength = 8*ONE_MEG;
else
DriverApertureRange_cx[LFB_ENTRY].RangeLength = 4*ONE_MEG;
VideoPortMoveMemory(SaveFirstMM, DriverIORange_cx+VGA_APERTURE_ENTRY, 2*sizeof(VIDEO_ACCESS_RANGE));
VideoPortMoveMemory(DriverIORange_cx+VGA_APERTURE_ENTRY, DriverApertureRange_cx, 2*sizeof(VIDEO_ACCESS_RANGE));
Status = VideoPortVerifyAccessRanges(phwDeviceExtension,
NUM_IO_REGISTERS+2,
DriverIORange_cx);
if (Status != NO_ERROR)
{
/*
* If there is an aperture conflict, reclaim our I/O ranges without
* asking for the LFB. This call should not fail, since we would not
* have reached this point if there were a conflict.
*/
Status = VideoPortVerifyAccessRanges(phwDeviceExtension,
NUM_IO_REGISTERS+1,
DriverIORange_cx);
if (Status != NO_ERROR)
VideoDebugPrint((DEBUG_ERROR, "ERROR: Can't reclaim I/O ranges\n"));
VideoPortMoveMemory(DriverIORange_cx+VGA_APERTURE_ENTRY, SaveFirstMM, 2*sizeof(VIDEO_ACCESS_RANGE));
ISAPitchAdjust(QueryPtr);
return TRUE;
}
else
{
VideoPortMoveMemory(DriverIORange_cx+VGA_APERTURE_ENTRY, SaveFirstMM, 2*sizeof(VIDEO_ACCESS_RANGE));
/*
* There is no aperture conflict, so enable the linear aperture.
*/
VideoPortZeroMemory(&Registers, sizeof(VIDEO_X86_BIOS_ARGUMENTS));
Registers.Eax = BIOS_APERTURE;
Registers.Ecx = BIOS_LINEAR_APERTURE;
VideoPortInt10(phwDeviceExtension, &Registers);
return FALSE;
}
} /* IsApertureConflict_cx() */
/***************************************************************************
*
* USHORT GetIOBase_cx(void);
*
* DESCRIPTION:
* Get the I/O base address being used by this card.
*
* RETURN VALUE:
* I/O base register
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* Any 68800CX-specific routine may call this routine after
* CompatIORangesUsable_cx() has returned success. Results
* are undefined if this routine is called either before
* CompatIORangesUsable_cx() is called, or after it retunrs
* failure.
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
USHORT GetIOBase_cx(void)
{
/*
* CRTC_H_TOTAL_DISP is at offset 0 from the base address.
* In a single-card setup, after CompatIORangesUsable_cx()
* returns, the value in
* DriverIORange_cx[CRTC_H_TOTAL_DISP].RangeStart.LowPart
* will be either the I/O base address in use (returned
* success) or the last I/O base address tried (returned
* failure).
*
* In a multi-card setup, this value will hold the I/O base
* for the last card which was set up, but the I/O base for
* each card is stored in its hardware device extension
* structure. This second storage location is not guaranteed
* for single-card setups, so use the DriverIORange location
* for them.
*/
if (NumBlockCardsFound > 1)
return (USHORT)(phwDeviceExtension->BaseIOAddress);
else
return (USHORT)(DriverIORange_cx[CRTC_H_TOTAL_DISP].RangeStart.LowPart);
} /* GetIOBase_cx() */
/***************************************************************************
*
* BOOL IsPackedIO_cx(void);
*
* DESCRIPTION:
* Report whether or not we are using packed (relocatable) I/O.
*
* RETURN VALUE:
* TRUE if using packed I/O
* FALSE if using sparse I/O
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* Any 68800CX-specific routine may call this routine after
* CompatIORangesUsable_cx() has returned success. Results
* are undefined if this routine is called either before
* CompatIORangesUsable_cx() is called, or after it retunrs
* failure.
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
BOOL IsPackedIO_cx(void)
{
/*
* CRTC_H_TOTAL_DISP and CRTC_H_SYNC_STRT_WID are the registers
* with the lowest I/O addresses (CRTC_H_TOTAL_DISP is at
* offset 0 from the base address). If we are using packed I/O,
* the DriverIORange_cx[].RangeStart.LowPart entries for these
* two registers will differ by 4 bytes, while if we are using
* normal (sparse) I/O, they will differ by 0x400 bytes.
*/
if (DriverIORange_cx[CRTC_H_SYNC_STRT_WID].RangeStart.LowPart -
DriverIORange_cx[CRTC_H_TOTAL_DISP].RangeStart.LowPart == 4)
{
VideoDebugPrint((DEBUG_DETAIL, "Reporting dense I/O\n"));
return TRUE;
}
else
{
VideoDebugPrint((DEBUG_DETAIL, "Reporting sparse I/O\n"));
return FALSE;
}
} /* IsPackedIO_cx() */
/***************************************************************************
*
* ULONG FindNextBlockATICard(void);
*
* DESCRIPTION:
* Find the next Mach 64 which uses block relocatable I/O.
*
* RETURN VALUE:
* I/O base address if card is found
* 0 if no card is found
*
* GLOBALS CHANGED:
* none
*
* CALLED BY:
* CompatIORangesUsable_cx()
*
* AUTHOR:
* Robert Wolff
*
* CHANGE HISTORY:
*
* TEST HISTORY:
*
***************************************************************************/
static ULONG FindNextBlockATICard(void)
{
PCI_COMMON_CONFIG ConfigData; /* Configuration information about PCI device */
PCI_SLOT_NUMBER SlotNumber; /* PCI slot under test */
static ULONG DeviceNumber=0; /* PCI device number */
static ULONG FunctionNumber=0; /* PCI function number */
ULONG BaseAddress=0; /* I/O base address */
ULONG RetVal; /* Value returned by function calls */
/*
* The PCI_SLOT_NUMBER union allows 32 slot numbers with 8
* function numbers each. The upper 24 bits are reserved.
*/
while (DeviceNumber < 32)
{
while (FunctionNumber < 8)
{
VideoDebugPrint((DEBUG_DETAIL, "Checking device 0x%X function 0x%X\n", DeviceNumber, FunctionNumber));
SlotNumber.u.bits.DeviceNumber = DeviceNumber;
SlotNumber.u.bits.FunctionNumber = FunctionNumber;
SlotNumber.u.bits.Reserved = 0;
ConfigData.VendorID = PCI_INVALID_VENDORID;
RetVal = VideoPortGetBusData(phwDeviceExtension,
PCIConfiguration,
SlotNumber.u.AsULONG,
&ConfigData,
0,
PCI_COMMON_HDR_LENGTH);
FunctionNumber++;
/*
* If we received an error return, skip to the
* next possible slot.
*/
if (RetVal != PCI_COMMON_HDR_LENGTH)
{
VideoDebugPrint((DEBUG_DETAIL, "Error return 0x%X, skipping to next slot\n", RetVal));
continue;
}
/*
* If this is not an ATI card, we are not interested.
* Instead, go on to the next candidate.
*/
VideoDebugPrint((DEBUG_DETAIL, "Vendor ID = 0x%X\n", ConfigData.VendorID));
if (ConfigData.VendorID != 0x1002)
continue;
/*
* We have found an ATI card. On all our block-relocatable
* cards, we must mask off the lowest order bit of the
* reported address, since this is always reported as 1
* (I/O space), but its actual value is always 0.
*
* Not all ATI PCI cards are block-relocatable Mach 64
* cards. Since we only look for block-relocatable cards
* if we have failed to find a fixed-base Mach 64, we can
* safely assume that any Mach 64 we find is block-relocatable.
*
* Despite this assumption, we must still distinguish Mach 64
* cards from non-Mach 64 cards, either by recognizing and
* accepting all Mach 64 device IDs and rejecting other
* device IDs, or by recognizing and rejecting all non-Mach 64
* device IDs and accepting other device IDs. The latter
* route is safer, since new device IDs are more likely
* to be Mach 64 than non-Mach 64, and this route will
* not falsely reject new Mach 64 cards. Currently, our
* only non-Mach 64 PCI card is the Mach 32 AX.
*
* Resetting BaseAddress to zero for non-Mach 64 cards
* will result in the same treatment as for non-ATI
* cards, i.e. we will treat the current slot as not
* containing a block-relocatable Mach 64, and search
* the next slot.
*/
BaseAddress = (ConfigData.u.type0.BaseAddresses[PCI_ADDRESS_IO_SPACE]) & 0xFFFFFFFE;
switch (ConfigData.DeviceID)
{
case ATI_DEVID_M32AX:
VideoDebugPrint((DEBUG_NORMAL, "Mach 32 AX card found, skipping it\n"));
BaseAddress = 0;
break;
default:
VideoDebugPrint((DEBUG_NORMAL, "Found ATI card with device ID 0x%X, treating as Mach 64\n", ConfigData.DeviceID));
break;
}
/*
* We will only reach this point if we find an ATI card.
* If it is a block-relocatable card, BaseAddress will
* be set to the I/O base address, and we must get out
* of the loop. If it is not a block-relocatable card,
* BaseAddress will be zero, and we must continue looking.
*/
if (BaseAddress != 0)
break;
} /* end while (FunctionNumber < 8) */
/*
* If we have found a Mach 64 relocatable card, we will have
* broken out of the inner loop, but we will still be in the
* outer loop. Since BaseAddress is zero if we have not found
* a card, and nonzero if we have found one, check this value
* to determine whether we should break out of the outer loop.
*/
if (BaseAddress != 0)
break;
VideoDebugPrint((DEBUG_DETAIL, "Finished inner loop, zeroing function number and incrementing device number\n"));
FunctionNumber = 0;
DeviceNumber++;
} /* end while (DeviceNumber < 32) */
return BaseAddress;
} /* FindNextBlockATICard() */